/* 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; }
/* 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; }
/* Verify field data */ static void verify_field(RefIndex list, FieldInfo *fields, jvalue *fvalues, int n_fields, jint index, jvalue value, jvmtiPrimitiveType primType) { HPROF_ASSERT(fvalues != NULL); HPROF_ASSERT(n_fields > 0); HPROF_ASSERT(index < n_fields); HPROF_ASSERT(index >= 0 ); if ( primType!=fields[index].primType ) { dump_fields(list, fields, fvalues, n_fields); debug_message("\nPROBLEM WITH:\n"); dump_field(fields, fvalues, n_fields, index, value, primType); debug_message("\n"); HPROF_ERROR(JNI_FALSE, "Trouble with fields and heap data"); } if ( primType == JVMTI_PRIMITIVE_TYPE_BOOLEAN && ( value.b != 1 && value.b != 0 ) ) { dump_fields(list, fields, fvalues, n_fields); debug_message("\nPROBLEM WITH:\n"); dump_field(fields, fvalues, n_fields, index, value, primType); debug_message("\n"); HPROF_ERROR(JNI_FALSE, "Trouble with fields and heap data"); } }
/* 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); }
/* Walk all references for an ObjectIndex and construct the hprof INST dump. */ static void dump_instance(JNIEnv *env, ObjectIndex object_index, RefIndex list) { jvmtiPrimitiveType primType; SiteIndex site_index; SerialNumber trace_serial_num; RefIndex index; ObjectIndex class_index; jlong size; ClassIndex cnum; char *sig; void *elements; jint num_elements; jint num_bytes; ObjectIndex *values; FieldInfo *fields; jvalue *fvalues; jint n_fields; jboolean skip_fields; jint n_fields_set; ObjectKind kind; TraceIndex trace_index; jboolean is_array; jboolean is_prim_array; HPROF_ASSERT(object_index!=0); kind = object_get_kind(object_index); if ( kind == OBJECT_CLASS ) { return; } site_index = object_get_site(object_index); HPROF_ASSERT(site_index!=0); cnum = site_get_class_index(site_index); HPROF_ASSERT(cnum!=0); size = (jlong)object_get_size(object_index); trace_index = site_get_trace_index(site_index); HPROF_ASSERT(trace_index!=0); trace_serial_num = trace_get_serial_number(trace_index); sig = string_get(class_get_signature(cnum)); class_index = class_get_object_index(cnum); values = NULL; elements = NULL; num_elements = 0; num_bytes = 0; n_fields = 0; skip_fields = JNI_FALSE; n_fields_set = 0; fields = NULL; fvalues = NULL; index = list; is_array = JNI_FALSE; is_prim_array = JNI_FALSE; if ( sig[0] != JVM_SIGNATURE_ARRAY ) { if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) { /* Trouble getting all the fields, can't trust field index values */ skip_fields = JNI_TRUE; /* It is assumed that the reason why we didn't get the fields * was because the class is not prepared. */ if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) { if ( list != 0 ) { dump_ref_list(list); debug_message("Instance of unprepared class with refs: %s\n", sig); } else { debug_message("Instance of unprepared class without refs: %s\n", sig); } HPROF_ERROR(JNI_FALSE, "Big Trouble with unprepared class instances"); } } if ( n_fields > 0 ) { fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue)); (void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue)); } } else { is_array = JNI_TRUE; if ( sig[0] != 0 && sigToPrimSize(sig+1) != 0 ) { is_prim_array = JNI_TRUE; } } while ( index != 0 ) { RefInfo *info; jvalue ovalue; static jvalue empty_value; info = get_info(index); /* Process reference objects, many not used right now. */ switch ( info->flavor ) { case INFO_OBJECT_REF_DATA: switch ( info->refKind ) { case JVMTI_HEAP_REFERENCE_SIGNERS: case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN: case JVMTI_HEAP_REFERENCE_CLASS_LOADER: case JVMTI_HEAP_REFERENCE_INTERFACE: case JVMTI_HEAP_REFERENCE_STATIC_FIELD: case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: /* Should never be seen on an instance dump */ HPROF_ASSERT(0); break; case JVMTI_HEAP_REFERENCE_FIELD: if ( skip_fields == JNI_TRUE ) { break; } HPROF_ASSERT(is_array!=JNI_TRUE); ovalue = empty_value; ovalue.i = info->object_index; fill_in_field_value(list, fields, fvalues, n_fields, info->index, ovalue, 0); n_fields_set++; HPROF_ASSERT(n_fields_set <= n_fields); break; case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: /* We get each object element one at a time. */ HPROF_ASSERT(is_array==JNI_TRUE); HPROF_ASSERT(is_prim_array!=JNI_TRUE); if ( num_elements <= info->index ) { int nbytes; if ( values == NULL ) { num_elements = info->index + 1; nbytes = num_elements*(int)sizeof(ObjectIndex); values = (ObjectIndex*)HPROF_MALLOC(nbytes); (void)memset(values, 0, nbytes); } else { void *new_values; int new_size; int obytes; obytes = num_elements*(int)sizeof(ObjectIndex); new_size = info->index + 1; nbytes = new_size*(int)sizeof(ObjectIndex); new_values = (void*)HPROF_MALLOC(nbytes); (void)memcpy(new_values, values, obytes); (void)memset(((char*)new_values)+obytes, 0, nbytes-obytes); HPROF_FREE(values); num_elements = new_size; values = new_values; } } HPROF_ASSERT(values[info->index]==0); values[info->index] = info->object_index; break; default: /* Ignore, not needed */ break; } break; case INFO_PRIM_FIELD_DATA: if ( skip_fields == JNI_TRUE ) { break; } HPROF_ASSERT(info->primType!=0); HPROF_ASSERT(info->length==-1); HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_FIELD); HPROF_ASSERT(is_array!=JNI_TRUE); ovalue = get_key_value(index); fill_in_field_value(list, fields, fvalues, n_fields, info->index, ovalue, info->primType); n_fields_set++; HPROF_ASSERT(n_fields_set <= n_fields); break; case INFO_PRIM_ARRAY_DATA: /* Should only be one, and it's handled below */ HPROF_ASSERT(info->refKind==0); /* We assert that nothing else was saved with this array */ HPROF_ASSERT(index==list&&info->next==0); HPROF_ASSERT(is_array==JNI_TRUE); HPROF_ASSERT(is_prim_array==JNI_TRUE); primType = info->primType; elements = get_key_elements(index, primType, &num_elements, &num_bytes); HPROF_ASSERT(info->length==num_elements); size = num_bytes; break; default: HPROF_ASSERT(0); break; } index = info->next; } if ( is_array == JNI_TRUE ) { if ( is_prim_array == JNI_TRUE ) { HPROF_ASSERT(values==NULL); io_heap_prim_array(object_index, trace_serial_num, (jint)size, num_elements, sig, elements); } else { HPROF_ASSERT(elements==NULL); io_heap_object_array(object_index, trace_serial_num, (jint)size, num_elements, sig, values, class_index); } } else { io_heap_instance_dump(cnum, object_index, trace_serial_num, class_index, (jint)size, sig, fields, fvalues, n_fields); } if ( values != NULL ) { HPROF_FREE(values); } if ( fvalues != NULL ) { HPROF_FREE(fvalues); } if ( elements != NULL ) { /* Do NOT free elements, it's a key in the table, leave it be */ } }
/* Walk all references for an ObjectIndex and construct the hprof CLASS dump. */ static void dump_class_and_supers(JNIEnv *env, ObjectIndex object_index, RefIndex list) { SiteIndex site_index; SerialNumber trace_serial_num; RefIndex index; ClassIndex super_cnum; ObjectIndex super_index; LoaderIndex loader_index; ObjectIndex signers_index; ObjectIndex domain_index; FieldInfo *fields; jvalue *fvalues; jint n_fields; jboolean skip_fields; jint n_fields_set; jlong size; ClassIndex cnum; char *sig; ObjectKind kind; TraceIndex trace_index; Stack *cpool_values; ConstantPoolValue *cpool; jint cpool_count; HPROF_ASSERT(object_index!=0); kind = object_get_kind(object_index); if ( kind != OBJECT_CLASS ) { return; } site_index = object_get_site(object_index); HPROF_ASSERT(site_index!=0); cnum = site_get_class_index(site_index); HPROF_ASSERT(cnum!=0); if ( class_get_status(cnum) & CLASS_DUMPED ) { return; } class_add_status(cnum, CLASS_DUMPED); size = (jlong)object_get_size(object_index); super_index = 0; super_cnum = class_get_super(cnum); if ( super_cnum != 0 ) { super_index = class_get_object_index(super_cnum); if ( super_index != 0 ) { dump_class_and_supers(env, super_index, object_get_references(super_index)); } } trace_index = site_get_trace_index(site_index); HPROF_ASSERT(trace_index!=0); trace_serial_num = trace_get_serial_number(trace_index); sig = string_get(class_get_signature(cnum)); loader_index = class_get_loader(cnum); signers_index = 0; domain_index = 0; /* Get field information */ n_fields = 0; skip_fields = JNI_FALSE; n_fields_set = 0; fields = NULL; fvalues = NULL; if ( class_get_all_fields(env, cnum, &n_fields, &fields) == 1 ) { /* Problems getting all the fields, can't trust field index values */ skip_fields = JNI_TRUE; /* Class with no references at all? (ok to be unprepared if list==0?) */ if ( list != 0 ) { /* It is assumed that the reason why we didn't get the fields * was because the class is not prepared. */ if ( gdata->debugflags & DEBUGFLAG_UNPREPARED_CLASSES ) { dump_ref_list(list); debug_message("Unprepared class with references: %s\n", sig); } HPROF_ERROR(JNI_FALSE, "Trouble with unprepared classes"); } /* Why would an unprepared class contain references? */ } if ( n_fields > 0 ) { fvalues = (jvalue*)HPROF_MALLOC(n_fields*(int)sizeof(jvalue)); (void)memset(fvalues, 0, n_fields*(int)sizeof(jvalue)); } /* We use a Stack just because it will automatically expand as needed */ cpool_values = stack_init(16, 16, sizeof(ConstantPoolValue)); cpool = NULL; cpool_count = 0; index = list; while ( index != 0 ) { RefInfo *info; jvalue ovalue; static jvalue empty_value; info = get_info(index); switch ( info->flavor ) { case INFO_OBJECT_REF_DATA: switch ( info->refKind ) { case JVMTI_HEAP_REFERENCE_FIELD: case JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT: /* Should never be seen on a class dump */ HPROF_ASSERT(0); break; case JVMTI_HEAP_REFERENCE_STATIC_FIELD: if ( skip_fields == JNI_TRUE ) { break; } ovalue = empty_value; ovalue.i = info->object_index; fill_in_field_value(list, fields, fvalues, n_fields, info->index, ovalue, 0); n_fields_set++; HPROF_ASSERT(n_fields_set <= n_fields); break; case JVMTI_HEAP_REFERENCE_CONSTANT_POOL: { ConstantPoolValue cpv; ObjectIndex cp_object_index; SiteIndex cp_site_index; ClassIndex cp_cnum; cp_object_index = info->object_index; HPROF_ASSERT(cp_object_index!=0); cp_site_index = object_get_site(cp_object_index); HPROF_ASSERT(cp_site_index!=0); cp_cnum = site_get_class_index(cp_site_index); cpv.constant_pool_index = info->index; cpv.sig_index = class_get_signature(cp_cnum); cpv.value.i = cp_object_index; stack_push(cpool_values, (void*)&cpv); cpool_count++; break; } case JVMTI_HEAP_REFERENCE_SIGNERS: signers_index = info->object_index; break; case JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN: domain_index = info->object_index; break; case JVMTI_HEAP_REFERENCE_CLASS_LOADER: case JVMTI_HEAP_REFERENCE_INTERFACE: default: /* Ignore, not needed */ break; } break; case INFO_PRIM_FIELD_DATA: if ( skip_fields == JNI_TRUE ) { break; } HPROF_ASSERT(info->primType!=0); HPROF_ASSERT(info->length==-1); HPROF_ASSERT(info->refKind==JVMTI_HEAP_REFERENCE_STATIC_FIELD); ovalue = get_key_value(index); fill_in_field_value(list, fields, fvalues, n_fields, info->index, ovalue, info->primType); n_fields_set++; HPROF_ASSERT(n_fields_set <= n_fields); break; case INFO_PRIM_ARRAY_DATA: default: /* Should never see these */ HPROF_ASSERT(0); break; } index = info->next; } /* Get constant pool data if we have any */ HPROF_ASSERT(cpool_count==stack_depth(cpool_values)); if ( cpool_count > 0 ) { cpool = (ConstantPoolValue*)stack_element(cpool_values, 0); } io_heap_class_dump(cnum, sig, object_index, trace_serial_num, super_index, loader_object_index(env, loader_index), signers_index, domain_index, (jint)size, cpool_count, cpool, n_fields, fields, fvalues); stack_term(cpool_values); if ( fvalues != NULL ) { HPROF_FREE(fvalues); } }
/* 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; }
/* 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<num_elements; i++) { (void)read_u2(&p); ty = read_u1(&p); (void)read_val(&p, ty); } num_elements = read_u2(&p); for(i=0; i<num_elements; i++) { (void)read_id(&p); ty = read_u1(&p); (void)read_val(&p, ty); } num_elements = read_u2(&p); for(i=0; i<num_elements; i++) { HprofType ty; HprofId id; id = read_id(&p); ty = read_u1(&p); add_inst_field_to_cmap(&cmap, id, ty); } (void)table_create_entry(ctab, &id, sizeof(id), &cmap); break; CASE_HEAP(HPROF_GC_INSTANCE_DUMP) id = read_id(&p); trace_serial_num = read_u4(&p); id2 = read_id(&p); /* class id */ num_bytes = read_u4(&p); p += num_bytes; break; CASE_HEAP(HPROF_GC_OBJ_ARRAY_DUMP) id = read_id(&p); trace_serial_num = read_u4(&p); num_elements = read_u4(&p); id2 = read_id(&p); p += num_elements*(int)sizeof(HprofId); break; CASE_HEAP(HPROF_GC_PRIM_ARRAY_DUMP) id = read_id(&p); trace_serial_num = read_u4(&p); num_elements = read_u4(&p); ty = read_u1(&p); p += type_size[ty]*num_elements; 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); /* Scan again once we have our cmap */ 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); check_printf("H#%d@%d %s: id=0x%x\n", nrecords, npos, label, id); break; CASE_HEAP(HPROF_GC_ROOT_JNI_GLOBAL) id = read_id(&p); id2 = read_id(&p); check_printf("H#%d@%d %s: id=0x%x, id2=0x%x\n", nrecords, npos, label, id, id2); break; CASE_HEAP(HPROF_GC_ROOT_JNI_LOCAL) id = read_id(&p); thread_serial_num = read_u4(&p); fr = read_u4(&p); check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u, fr=0x%x\n", nrecords, npos, label, id, thread_serial_num, fr); break; CASE_HEAP(HPROF_GC_ROOT_JAVA_FRAME) id = read_id(&p); thread_serial_num = read_u4(&p); fr = read_u4(&p); check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u, fr=0x%x\n", nrecords, npos, label, id, thread_serial_num, fr); break; CASE_HEAP(HPROF_GC_ROOT_NATIVE_STACK) id = read_id(&p); thread_serial_num = read_u4(&p); check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u\n", nrecords, npos, label, id, thread_serial_num); break; CASE_HEAP(HPROF_GC_ROOT_STICKY_CLASS) id = read_id(&p); check_printf("H#%d@%d %s: id=0x%x\n", nrecords, npos, label, id); break; CASE_HEAP(HPROF_GC_ROOT_THREAD_BLOCK) id = read_id(&p); thread_serial_num = read_u4(&p); check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u\n", nrecords, npos, label, id, thread_serial_num); break; CASE_HEAP(HPROF_GC_ROOT_MONITOR_USED) id = read_id(&p); check_printf("H#%d@%d %s: id=0x%x\n", nrecords, npos, label, id); break; CASE_HEAP(HPROF_GC_ROOT_THREAD_OBJ) id = read_id(&p); thread_serial_num = read_u4(&p); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); check_printf("H#%d@%d %s: id=0x%x, thread_serial_num=%u," " trace_serial_num=%u\n", nrecords, npos, label, id, thread_serial_num, trace_serial_num); break; CASE_HEAP(HPROF_GC_CLASS_DUMP) id = read_id(&p); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u\n", nrecords, npos, label, id, trace_serial_num); { 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); check_printf(" su=0x%x, ld=0x%x, si=0x%x," " pr=0x%x, re1=0x%x, re2=0x%x\n", sup, ld, si, pr, re1, re2); } inst_size = read_u4(&p); check_printf(" instance_size=%d\n", inst_size); num_elements = read_u2(&p); for(i=0; i<num_elements; i++) { HprofType ty; unsigned cpi; jvalue val; cpi = read_u2(&p); ty = read_u1(&p); val = read_val(&p, ty); check_printf(" constant_pool %d: cpi=%d, ty=%d, val=", i, cpi, ty); check_printf_val(ty, val, 1); check_printf("\n"); } num_elements = read_u2(&p); check_printf(" static_field_count=%d\n", num_elements); for(i=0; i<num_elements; i++) { HprofType ty; HprofId id; jvalue val; id = read_id(&p); ty = read_u1(&p); val = read_val(&p, ty); check_printf(" static field %d: ", i); check_print_utf8(utab, "id=", id); check_printf(", ty=%d, val=", ty); check_printf_val(ty, val, 1); check_printf("\n"); } num_elements = read_u2(&p); check_printf(" instance_field_count=%d\n", num_elements); for(i=0; i<num_elements; i++) { HprofType ty; HprofId id; id = read_id(&p); ty = read_u1(&p); check_printf(" instance_field %d: ", i); check_print_utf8(utab, "id=", id); check_printf(", ty=%d\n", ty); } break; CASE_HEAP(HPROF_GC_INSTANCE_DUMP) id = read_id(&p); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); id2 = read_id(&p); /* class id */ num_bytes = read_u4(&p); check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u," " cid=0x%x, nbytes=%d\n", nrecords, npos, label, id, trace_serial_num, id2, num_bytes); /* This is a packed set of bytes for the instance fields */ if ( num_bytes > 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;i<map->n_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<num_elements; i++) { HprofId id; id = read_id(&p); check_printf(" [%d]: id=0x%x\n", i, id); } break; CASE_HEAP(HPROF_GC_PRIM_ARRAY_DUMP) id = read_id(&p); trace_serial_num = read_u4(&p); CHECK_TRACE_SERIAL_NO(trace_serial_num); num_elements = read_u4(&p); ty = read_u1(&p); psave = p; check_printf("H#%d@%d %s: id=0x%x, trace_serial_num=%u, " "nelems=%d, ty=%d\n", nrecords, npos, label, id, trace_serial_num, num_elements, ty); HPROF_ASSERT(HPROF_TYPE_IS_PRIMITIVE(ty)); if ( num_elements > 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<num_elements; i++) { jvalue val; if ( 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; }