/* * @(#)hprof_check.c 1.8 10/03/23 * * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * -Redistribution of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * -Redistribution in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of Oracle or the names of contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed, licensed or intended * for use in the design, construction, operation or maintenance of any * nuclear facility. */ /* Functionality for checking hprof format=b output. */ /* ONLY used with logflags=4. */ /* Verifies and write a verbose textual version of a format=b file. * Textual output file is gdata->checkfilename, fd is gdata->check_fd. * Buffer is in gdata too, see gdata->check* variables. * Could probably be isolated to a separate library or utility. */ #include "hprof.h" typedef TableIndex HprofId; #include "hprof_b_spec.h" static int type_size[ /*HprofType*/ ] = HPROF_TYPE_SIZES; /* For map from HPROF_UTF8 to a string */ typedef struct UmapInfo { char *str; } UmapInfo; /* Field information */ typedef struct Finfo { HprofId id; HprofType ty; } Finfo; /* Class information map from class ID (ClassIndex) to class information */ typedef struct CmapInfo { int max_finfo; int n_finfo; Finfo *finfo; int inst_size; HprofId sup; } CmapInfo; /* Read raw bytes from the file image, update the pointer */ static void read_raw(unsigned char **pp, unsigned char *buf, int len) { while ( len > 0 ) { *buf = **pp; buf++; (*pp)++; len--; } } /* Read various sized elements, properly converted from big to right endian. * File will contain big endian format. */ static unsigned read_u1(unsigned char **pp) { unsigned char b; read_raw(pp, &b, 1); return b; } static unsigned read_u2(unsigned char **pp) { unsigned short s; read_raw(pp, (void*)&s, 2); return md_htons(s); } static unsigned read_u4(unsigned char **pp) { unsigned int u; read_raw(pp, (void*)&u, 4); return md_htonl(u); } static jlong read_u8(unsigned char **pp) { unsigned int high; unsigned int low; jlong x; high = read_u4(pp); low = read_u4(pp); x = high; x = (x << 32) | low; return x; } static HprofId read_id(unsigned char **pp) { return (HprofId)read_u4(pp); } /* System error routine */ static void system_error(const char *system_call, int rc, int errnum) { char buf[256]; char details[256]; details[0] = 0; if ( errnum != 0 ) { md_system_error(details, (int)sizeof(details)); } else if ( rc >= 0 ) { (void)strcpy(details,"Only part of buffer processed"); } if ( details[0] == 0 ) { (void)strcpy(details,"Unknown system error condition"); } (void)md_snprintf(buf, sizeof(buf), "System %s failed: %s\n", system_call, details); HPROF_ERROR(JNI_TRUE, buf); } /* Write to a fd */ static void system_write(int fd, void *buf, int len) { int res; HPROF_ASSERT(fd>=0); res = md_write(fd, buf, len); if (res < 0 || res!=len) { system_error("write", res, errno); } } /* Flush check buffer */ static void check_flush(void) { if ( gdata->check_fd < 0 ) { return; } if (gdata->check_buffer_index) { system_write(gdata->check_fd, gdata->check_buffer, gdata->check_buffer_index); gdata->check_buffer_index = 0; } } /* Read out a given typed element */ static jvalue read_val(unsigned char **pp, HprofType ty) { jvalue val; static jvalue empty_val; val = empty_val; switch ( ty ) { case 0: case HPROF_ARRAY_OBJECT: case HPROF_NORMAL_OBJECT: val.i = read_id(pp); break; case HPROF_BYTE: case HPROF_BOOLEAN: val.b = read_u1(pp); break; case HPROF_CHAR: case HPROF_SHORT: val.s = read_u2(pp); break; case HPROF_FLOAT: case HPROF_INT: val.i = read_u4(pp); break; case HPROF_DOUBLE: case HPROF_LONG: val.j = read_u8(pp); break; default: HPROF_ERROR(JNI_TRUE, "bad type number"); break; } return val; } /* Move arbitrary byte stream into gdata->check_fd */ static void check_raw(void *buf, int len) { if ( gdata->check_fd < 0 ) { return; } if ( len <= 0 ) { return; } if (gdata->check_buffer_index + len > gdata->check_buffer_size) { check_flush(); if (len > gdata->check_buffer_size) { system_write(gdata->check_fd, buf, len); return; } } (void)memcpy(gdata->check_buffer + gdata->check_buffer_index, buf, len); gdata->check_buffer_index += len; } /* Printf for gdata->check_fd */ static void check_printf(char *fmt, ...) { char buf[1024]; va_list args; if ( gdata->check_fd < 0 ) { return; } va_start(args, fmt); (void)md_vsnprintf(buf, sizeof(buf), fmt, args); buf[sizeof(buf)-1] = 0; check_raw(buf, (int)strlen(buf)); va_end(args); } /* Printf of an element for gdata->check_fd */ static void check_printf_val(HprofType ty, jvalue val, int long_form) { jint low; jint high; switch ( ty ) { case HPROF_ARRAY_OBJECT: check_printf("0x%08x", val.i); break; case HPROF_NORMAL_OBJECT: check_printf("0x%08x", val.i); break; case HPROF_BOOLEAN: check_printf("0x%02x", val.b); break; case HPROF_CHAR: if ( long_form ) { if ( val.s < 0 || val.s > 0x7f || !isprint(val.s) ) { check_printf("0x%04x", val.s); } else { check_printf("0x%04x(%c)", val.s, val.s); } } else { if ( val.s < 0 || val.s > 0x7f || !isprint(val.s) ) { check_printf("\\u%04x", val.s); } else { check_printf("%c", val.s); } } break; case HPROF_FLOAT: low = jlong_low(val.j); check_printf("0x%08x(%f)", low, (double)val.f); break; case HPROF_DOUBLE: high = jlong_high(val.j); low = jlong_low(val.j); check_printf("0x%08x%08x(%f)", high, low, val.d); break; case HPROF_BYTE: check_printf("0x%02x", val.b); break; case HPROF_SHORT: check_printf("0x%04x", val.s); break; case HPROF_INT: check_printf("0x%08x", val.i); break; case HPROF_LONG: high = jlong_high(val.j); low = jlong_low(val.j); check_printf("0x%08x%08x", high, low); break; } } /* Printf of a string for gdata->check_fd */ static void check_printf_str(char *str) { int len; int i; if ( str == NULL ) { check_printf(""); } check_printf("\""); len = (int)strlen(str); for (i = 0; i < len; i++) { unsigned char c; c = str[i]; if ( isprint(c) ) { check_printf("%c", c); } else { check_printf("\\x%02x", c); } } check_printf("\""); } /* Printf of a utf8 id for gdata->check_fd */ static void check_print_utf8(struct LookupTable *utab, char *prefix, HprofId id) { TableIndex uindex; if ( id == 0 ) { check_printf("%s0x%x", prefix, id); } else { uindex = table_find_entry(utab, &id, sizeof(id)); if ( uindex == 0 ) { check_printf("%s0x%x", prefix, id); } else { UmapInfo *umap; umap = (UmapInfo*)table_get_info(utab, uindex); HPROF_ASSERT(umap!=NULL); HPROF_ASSERT(umap->str!=NULL); check_printf("%s0x%x->", prefix, id); check_printf_str(umap->str); } } } /* Add a instance field information to this cmap. */ static void add_inst_field_to_cmap(CmapInfo *cmap, HprofId id, HprofType ty) { int i; HPROF_ASSERT(cmap!=NULL); i = cmap->n_finfo++; if ( i+1 >= cmap->max_finfo ) { int osize; Finfo *new_finfo; osize = cmap->max_finfo; cmap->max_finfo += 12; new_finfo = (Finfo*)HPROF_MALLOC(cmap->max_finfo*(int)sizeof(Finfo)); (void)memset(new_finfo,0,cmap->max_finfo*(int)sizeof(Finfo)); if ( i == 0 ) { cmap->finfo = new_finfo; } else { (void)memcpy(new_finfo,cmap->finfo,osize*(int)sizeof(Finfo)); HPROF_FREE(cmap->finfo); cmap->finfo = new_finfo; } } cmap->finfo[i].id = id; cmap->finfo[i].ty = ty; } /* LookupTable callback for cmap entry cleanup */ static void cmap_cleanup(TableIndex i, void *key_ptr, int key_len, void*info, void*data) { CmapInfo *cmap = info; if ( cmap == NULL ) { return; } if ( cmap->finfo != NULL ) { HPROF_FREE(cmap->finfo); cmap->finfo = NULL; } } /* Case label for a switch on hprof heap dump elements */ #define CASE_HEAP(name) case name: label = #name; /* Given the heap dump data and the utf8 map, check/write the heap dump. */ static int check_heap_tags(struct LookupTable *utab, unsigned char *pstart, int nbytes) { int nrecords; unsigned char *p; unsigned char *psave; struct LookupTable *ctab; CmapInfo cmap; char *label; unsigned tag; HprofType ty; HprofId id, id2, fr, sup; int num_elements; int num_bytes; SerialNumber trace_serial_num; SerialNumber thread_serial_num; int npos; int i; int inst_size; ctab = table_initialize("temp ctab", 64, 64, 512, sizeof(CmapInfo)); /* First pass over heap records just fills in the CmapInfo table */ nrecords = 0; p = pstart; while ( p < (pstart+nbytes) ) { nrecords++; /*LINTED*/ npos = (int)(p - pstart); tag = read_u1(&p); switch ( tag ) { CASE_HEAP(HPROF_GC_ROOT_UNKNOWN) id = read_id(&p); break; CASE_HEAP(HPROF_GC_ROOT_JNI_GLOBAL) id = read_id(&p); id2 = read_id(&p); break; CASE_HEAP(HPROF_GC_ROOT_JNI_LOCAL) id = read_id(&p); thread_serial_num = read_u4(&p); fr = read_u4(&p); break; CASE_HEAP(HPROF_GC_ROOT_JAVA_FRAME) id = read_id(&p); thread_serial_num = read_u4(&p); fr = read_u4(&p); break; CASE_HEAP(HPROF_GC_ROOT_NATIVE_STACK) id = read_id(&p); thread_serial_num = read_u4(&p); break; CASE_HEAP(HPROF_GC_ROOT_STICKY_CLASS) id = read_id(&p); break; CASE_HEAP(HPROF_GC_ROOT_THREAD_BLOCK) id = read_id(&p); thread_serial_num = read_u4(&p); break; CASE_HEAP(HPROF_GC_ROOT_MONITOR_USED) id = read_id(&p); break; CASE_HEAP(HPROF_GC_ROOT_THREAD_OBJ) id = read_id(&p); thread_serial_num = read_u4(&p); trace_serial_num = read_u4(&p); break; CASE_HEAP(HPROF_GC_CLASS_DUMP) (void)memset((void*)&cmap, 0, sizeof(cmap)); id = read_id(&p); trace_serial_num = read_u4(&p); { HprofId ld, si, pr, re1, re2; sup = read_id(&p); ld = read_id(&p); si = read_id(&p); pr = read_id(&p); re1 = read_id(&p); re2 = read_id(&p); cmap.sup = sup; } inst_size = read_u4(&p); cmap.inst_size = inst_size; num_elements = read_u2(&p); for(i=0; i 0 ) { TableIndex cindex; int ifield; CmapInfo *map; cindex = table_find_entry(ctab, &id2, sizeof(id2)); HPROF_ASSERT(cindex!=0); map = (CmapInfo*)table_get_info(ctab, cindex); HPROF_ASSERT(map!=NULL); HPROF_ASSERT(num_bytes==map->inst_size); psave = p; ifield = 0; do { for(i=0;in_finfo;i++) { HprofType ty; HprofId id; jvalue val; ty = map->finfo[i].ty; id = map->finfo[i].id; HPROF_ASSERT(ty!=0); HPROF_ASSERT(id!=0); val = read_val(&p, ty); check_printf(" field %d: ", ifield); check_print_utf8(utab, "id=", id); check_printf(", ty=%d, val=", ty); check_printf_val(ty, val, 1); check_printf("\n"); ifield++; } id2 = map->sup; map = NULL; cindex = 0; if ( id2 != 0 ) { cindex = table_find_entry(ctab, &id2, sizeof(id2)); HPROF_ASSERT(cindex!=0); map = (CmapInfo*)table_get_info(ctab, cindex); HPROF_ASSERT(map!=NULL); } } while ( map != NULL ); HPROF_ASSERT(num_bytes==(p-psave)); } break; CASE_HEAP(HPROF_GC_OBJ_ARRAY_DUMP) id = read_id(&p); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); num_elements = read_u4(&p); id2 = read_id(&p); check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u, nelems=%d, eid=0x%x\n", nrecords, npos, label, id, trace_serial_num, num_elements, id2); for(i=0; i 0 ) { int count; int long_form; int max_count; char *quote; quote = ""; long_form = 1; max_count = 8; count = 0; switch ( ty ) { case HPROF_CHAR: long_form = 0; max_count = 72; quote = "\""; /*FALLTHRU*/ case HPROF_INT: case HPROF_DOUBLE: case HPROF_LONG: case HPROF_BYTE: case HPROF_BOOLEAN: case HPROF_SHORT: case HPROF_FLOAT: check_printf(" val=%s", quote); for(i=0; i 0 && count == 0 ) { check_printf(" %s", quote); } val = read_val(&p, ty); check_printf_val(ty, val, long_form); count += 1; if ( count >= max_count ) { check_printf("\"\n"); count = 0; } } if ( count != 0 ) { check_printf("%s\n", quote); } break; } } HPROF_ASSERT(type_size[ty]*num_elements==(p-psave)); break; default: label = "UNKNOWN"; check_printf("H#%d@%d %s: ERROR!\n", nrecords, npos, label); HPROF_ERROR(JNI_TRUE, "unknown heap record type"); break; } } CHECK_FOR_ERROR(p==pstart+nbytes); table_cleanup(ctab, &cmap_cleanup, NULL); return nrecords; } /* LookupTable cleanup callback for utab */ static void utab_cleanup(TableIndex i, void *key_ptr, int key_len, void*info, void*data) { UmapInfo *umap = info; if ( umap == NULL ) { return; } if ( umap->str != NULL ) { HPROF_FREE(umap->str); umap->str = NULL; } } /* Check all the heap tags in a heap dump */ static int check_tags(unsigned char *pstart, int nbytes) { unsigned char *p; int nrecord; struct LookupTable *utab; UmapInfo umap; check_printf("\nCHECK TAGS: starting\n"); utab = table_initialize("temp utf8 map", 64, 64, 512, sizeof(UmapInfo)); /* Walk the tags, assumes UTF8 tags are defined before used */ p = pstart; nrecord = 0; while ( p < (pstart+nbytes) ) { unsigned tag; unsigned size; int nheap_records; int npos; char *label; HprofId id, nm, sg, so, gr, gn; int i, li, num_elements; HprofType ty; SerialNumber trace_serial_num; SerialNumber thread_serial_num; SerialNumber class_serial_num; unsigned flags; unsigned depth; float cutoff; unsigned temp; jint nblive; jint nilive; jlong tbytes; jlong tinsts; jint total_samples; jint trace_count; nrecord++; /*LINTED*/ npos = (int)(p - pstart); tag = read_u1(&p); (void)read_u4(&p); /* microsecs */ size = read_u4(&p); #define CASE_TAG(name) case name: label = #name; switch ( tag ) { CASE_TAG(HPROF_UTF8) CHECK_FOR_ERROR(size>=(int)sizeof(HprofId)); id = read_id(&p); check_printf("#%d@%d: %s, sz=%d, name_id=0x%x, \"", nrecord, npos, label, size, id); num_elements = size-(int)sizeof(HprofId); check_raw(p, num_elements); check_printf("\"\n"); /* Create entry in umap */ umap.str = HPROF_MALLOC(num_elements+1); (void)strncpy(umap.str, (char*)p, (size_t)num_elements); umap.str[num_elements] = 0; (void)table_create_entry(utab, &id, sizeof(id), &umap); p += num_elements; break; CASE_TAG(HPROF_LOAD_CLASS) CHECK_FOR_ERROR(size==2*4+2*(int)sizeof(HprofId)); class_serial_num = read_u4(&p); CHECK_CLASS_SERIAL_NO(class_serial_num); id = read_id(&p); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); nm = read_id(&p); check_printf("#%d@%d: %s, sz=%d, class_serial_num=%u," " id=0x%x, trace_serial_num=%u, name_id=0x%x\n", nrecord, npos, label, size, class_serial_num, id, trace_serial_num, nm); break; CASE_TAG(HPROF_UNLOAD_CLASS) CHECK_FOR_ERROR(size==4); class_serial_num = read_u4(&p); CHECK_CLASS_SERIAL_NO(class_serial_num); check_printf("#%d@%d: %s, sz=%d, class_serial_num=%u\n", nrecord, npos, label, size, class_serial_num); break; CASE_TAG(HPROF_FRAME) CHECK_FOR_ERROR(size==2*4+4*(int)sizeof(HprofId)); id = read_id(&p); nm = read_id(&p); sg = read_id(&p); so = read_id(&p); class_serial_num = read_u4(&p); CHECK_CLASS_SERIAL_NO(class_serial_num); li = read_u4(&p); check_printf("#%d@%d: %s, sz=%d, ", nrecord, npos, label, size); check_print_utf8(utab, "id=", id); check_printf(" name_id=0x%x, sig_id=0x%x, source_id=0x%x," " class_serial_num=%u, lineno=%d\n", nm, sg, so, class_serial_num, li); break; CASE_TAG(HPROF_TRACE) CHECK_FOR_ERROR(size>=3*4); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); thread_serial_num = read_u4(&p); /* Can be 0 */ num_elements = read_u4(&p); check_printf("#%d@%d: %s, sz=%d, trace_serial_num=%u," " thread_serial_num=%u, nelems=%d [", nrecord, npos, label, size, trace_serial_num, thread_serial_num, num_elements); for(i=0; i< num_elements; i++) { check_printf("0x%x,", read_id(&p)); } check_printf("]\n"); break; CASE_TAG(HPROF_ALLOC_SITES) CHECK_FOR_ERROR(size>=2+4*4+2*8); flags = read_u2(&p); temp = read_u4(&p); cutoff = *((float*)&temp); nblive = read_u4(&p); nilive = read_u4(&p); tbytes = read_u8(&p); tinsts = read_u8(&p); num_elements = read_u4(&p); check_printf("#%d@%d: %s, sz=%d, flags=0x%x, cutoff=%g," " nblive=%d, nilive=%d, tbytes=(%d,%d)," " tinsts=(%d,%d), num_elements=%d\n", nrecord, npos, label, size, flags, cutoff, nblive, nilive, jlong_high(tbytes), jlong_low(tbytes), jlong_high(tinsts), jlong_low(tinsts), num_elements); for(i=0; i< num_elements; i++) { ty = read_u1(&p); class_serial_num = read_u4(&p); CHECK_CLASS_SERIAL_NO(class_serial_num); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); nblive = read_u4(&p); nilive = read_u4(&p); tbytes = read_u4(&p); tinsts = read_u4(&p); check_printf("\t %d: ty=%d, class_serial_num=%u," " trace_serial_num=%u, nblive=%d, nilive=%d," " tbytes=%d, tinsts=%d\n", i, ty, class_serial_num, trace_serial_num, nblive, nilive, (jint)tbytes, (jint)tinsts); } break; CASE_TAG(HPROF_HEAP_SUMMARY) CHECK_FOR_ERROR(size==2*4+2*8); nblive = read_u4(&p); nilive = read_u4(&p); tbytes = read_u8(&p); tinsts = read_u8(&p); check_printf("#%d@%d: %s, sz=%d," " nblive=%d, nilive=%d, tbytes=(%d,%d)," " tinsts=(%d,%d)\n", nrecord, npos, label, size, nblive, nilive, jlong_high(tbytes), jlong_low(tbytes), jlong_high(tinsts), jlong_low(tinsts)); break; CASE_TAG(HPROF_START_THREAD) CHECK_FOR_ERROR(size==2*4+4*(int)sizeof(HprofId)); thread_serial_num = read_u4(&p); CHECK_THREAD_SERIAL_NO(thread_serial_num); id = read_id(&p); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); nm = read_id(&p); gr = read_id(&p); gn = read_id(&p); check_printf("#%d@%d: %s, sz=%d, thread_serial_num=%u," " id=0x%x, trace_serial_num=%u, ", nrecord, npos, label, size, thread_serial_num, id, trace_serial_num); check_print_utf8(utab, "nm=", id); check_printf(" trace_serial_num=%u, nm=0x%x," " gr=0x%x, gn=0x%x\n", trace_serial_num, nm, gr, gn); break; CASE_TAG(HPROF_END_THREAD) CHECK_FOR_ERROR(size==4); thread_serial_num = read_u4(&p); CHECK_THREAD_SERIAL_NO(thread_serial_num); check_printf("#%d@%d: %s, sz=%d, thread_serial_num=%u\n", nrecord, npos, label, size, thread_serial_num); break; CASE_TAG(HPROF_HEAP_DUMP) check_printf("#%d@%d: BEGIN: %s, sz=%d\n", nrecord, npos, label, size); nheap_records = check_heap_tags(utab, p, size); check_printf("#%d@%d: END: %s, sz=%d, nheap_recs=%d\n", nrecord, npos, label, size, nheap_records); p += size; break; CASE_TAG(HPROF_HEAP_DUMP_SEGMENT) /* 1.0.2 */ check_printf("#%d@%d: BEGIN SEGMENT: %s, sz=%d\n", nrecord, npos, label, size); nheap_records = check_heap_tags(utab, p, size); check_printf("#%d@%d: END SEGMENT: %s, sz=%d, nheap_recs=%d\n", nrecord, npos, label, size, nheap_records); p += size; break; CASE_TAG(HPROF_HEAP_DUMP_END) /* 1.0.2 */ check_printf("#%d@%d: SEGMENT END: %s, sz=%d\n", nrecord, npos, label, size); break; CASE_TAG(HPROF_CPU_SAMPLES) CHECK_FOR_ERROR(size>=2*4); total_samples = read_u4(&p); trace_count = read_u4(&p); check_printf("#%d@%d: %s, sz=%d, total_samples=%d," " trace_count=%d\n", nrecord, npos, label, size, total_samples, trace_count); for(i=0; i< trace_count; i++) { num_elements = read_u4(&p); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); check_printf("\t %d: samples=%d, trace_serial_num=%u\n", trace_serial_num, num_elements); } break; CASE_TAG(HPROF_CONTROL_SETTINGS) CHECK_FOR_ERROR(size==4+2); flags = read_u4(&p); depth = read_u2(&p); check_printf("#%d@%d: %s, sz=%d, flags=0x%x, depth=%d\n", nrecord, npos, label, size, flags, depth); break; default: label = "UNKNOWN"; check_printf("#%d@%d: %s, sz=%d\n", nrecord, npos, label, size); HPROF_ERROR(JNI_TRUE, "unknown record type"); p += size; break; } CHECK_FOR_ERROR(p<=(pstart+nbytes)); } check_flush(); CHECK_FOR_ERROR(p==(pstart+nbytes)); table_cleanup(utab, &utab_cleanup, NULL); return nrecord; } /* Read the entire file into memory */ static void * get_binary_file_image(char *filename, int *pnbytes) { unsigned char *image; int fd; jlong nbytes; int nread; *pnbytes = 0; fd = md_open_binary(filename); CHECK_FOR_ERROR(fd>=0); if ( (nbytes = md_seek(fd, (jlong)-1)) == (jlong)-1 ) { HPROF_ERROR(JNI_TRUE, "Cannot md_seek() to end of file"); } CHECK_FOR_ERROR(((jint)nbytes)>512); if ( md_seek(fd, (jlong)0) != (jlong)0 ) { HPROF_ERROR(JNI_TRUE, "Cannot md_seek() to start of file"); } image = HPROF_MALLOC(((jint)nbytes)+1); CHECK_FOR_ERROR(image!=NULL); /* Read the entire file image into memory */ nread = md_read(fd, image, (jint)nbytes); if ( nread <= 0 ) { HPROF_ERROR(JNI_TRUE, "System read failed."); } CHECK_FOR_ERROR(((jint)nbytes)==nread); md_close(fd); *pnbytes = (jint)nbytes; return image; } /* ------------------------------------------------------------------ */ void check_binary_file(char *filename) { unsigned char *image; unsigned char *p; unsigned idsize; int nbytes; int nrecords; image = get_binary_file_image(filename, &nbytes); if ( image == NULL ) { check_printf("No file image: %s\n", filename); return; } p = image; CHECK_FOR_ERROR(strcmp((char*)p, gdata->header)==0); check_printf("Filename=%s, nbytes=%d, header=\"%s\"\n", filename, nbytes, p); p+=((int)strlen((char*)p)+1); idsize = read_u4(&p); CHECK_FOR_ERROR(idsize==sizeof(HprofId)); (void)read_u4(&p); (void)read_u4(&p); /* LINTED */ nrecords = check_tags(p, nbytes - (int)( p - image ) ); check_printf("#%d total records found in %d bytes\n", nrecords, nbytes); HPROF_FREE(image); }