void java_bytecode_parsert::rmethod(classt &parsed_class) { methodt &method=parsed_class.add_method(); u2 access_flags=read_u2(); u2 name_index=read_u2(); u2 descriptor_index=read_u2(); method.is_final=(access_flags&ACC_FINAL)!=0; method.is_static=(access_flags&ACC_STATIC)!=0; method.is_abstract=(access_flags&ACC_ABSTRACT)!=0; method.is_public=(access_flags&ACC_PUBLIC)!=0; method.is_protected=(access_flags&ACC_PROTECTED)!=0; method.is_private=(access_flags&ACC_PRIVATE)!=0; method.is_synchronized=(access_flags&ACC_SYNCHRONIZED)!=0; method.is_native=(access_flags&ACC_NATIVE)!=0; method.name=pool_entry(name_index).s; method.base_name=pool_entry(name_index).s; method.signature=id2string(pool_entry(descriptor_index).s); u2 attributes_count=read_u2(); for(std::size_t j=0; j<attributes_count; j++) rmethod_attribute(method); }
void java_bytecode_parsert::rinterfaces(classt &parsed_class) { u2 interfaces_count=read_u2(); for(std::size_t i=0; i<interfaces_count; i++) parsed_class.implements .push_back(constant(read_u2()).type().get(ID_C_base_name)); }
void java_bytecode_parsert::relement_value_pairs( annotationt::element_value_pairst &element_value_pairs) { u2 num_element_value_pairs=read_u2(); element_value_pairs.resize(num_element_value_pairs); for(auto &element_value_pair : element_value_pairs) { u2 element_name_index=read_u2(); element_value_pair.element_name=pool_entry(element_name_index).s; relement_value_pair(element_value_pair); } }
/* 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; }
void java_bytecode_parsert::rmethods(classt &parsed_class) { u2 methods_count=read_u2(); for(std::size_t j=0; j<methods_count; j++) rmethod(parsed_class); }
void java_bytecode_parsert::rRuntimeAnnotation( annotationt &annotation) { u2 type_index=read_u2(); annotation.type=type_entry(type_index); relement_value_pairs(annotation.element_value_pairs); }
void java_bytecode_parsert::rclass_attribute(classt &parsed_class) { u2 attribute_name_index=read_u2(); u4 attribute_length=read_u4(); irep_idt attribute_name=pool_entry(attribute_name_index).s; if(attribute_name=="SourceFile") { u2 sourcefile_index=read_u2(); irep_idt sourcefile_name; std::string fqn(id2string(parsed_class.name)); size_t last_index=fqn.find_last_of("."); if(last_index==std::string::npos) sourcefile_name=pool_entry(sourcefile_index).s; else { std::string package_name=fqn.substr(0, last_index+1); std::replace(package_name.begin(), package_name.end(), '.', '/'); const std::string &full_file_name= package_name+id2string(pool_entry(sourcefile_index).s); sourcefile_name=full_file_name; } for(methodst::iterator m_it=parsed_class.methods.begin(); m_it!=parsed_class.methods.end(); m_it++) { m_it->source_location.set_file(sourcefile_name); for(instructionst::iterator i_it=m_it->instructions.begin(); i_it!=m_it->instructions.end(); i_it++) { if(!i_it->source_location.get_line().empty()) i_it->source_location.set_file(sourcefile_name); } } } else if(attribute_name=="RuntimeInvisibleAnnotations" || attribute_name=="RuntimeVisibleAnnotations") { rRuntimeAnnotation_attribute(parsed_class.annotations); } else skip_bytes(attribute_length); }
void java_bytecode_parsert::rRuntimeAnnotation_attribute( annotationst &annotations) { u2 num_annotations=read_u2(); for(u2 number=0; number<num_annotations; number++) { annotationt annotation; rRuntimeAnnotation(annotation); annotations.push_back(annotation); } }
void java_bytecode_parsert::read_verification_type_info( methodt::verification_type_infot &v) { u1 tag=read_u1(); switch(tag) { case VTYPE_INFO_TOP: v.type=methodt::verification_type_infot::TOP; break; case VTYPE_INFO_INTEGER: v.type=methodt::verification_type_infot::INTEGER; break; case VTYPE_INFO_FLOAT: v.type=methodt::verification_type_infot::FLOAT; break; case VTYPE_INFO_LONG: v.type=methodt::verification_type_infot::LONG; break; case VTYPE_INFO_DOUBLE: v.type=methodt::verification_type_infot::DOUBLE; break; case VTYPE_INFO_ITEM_NULL: v.type=methodt::verification_type_infot::ITEM_NULL; break; case VTYPE_INFO_UNINIT_THIS: v.type=methodt::verification_type_infot::UNINITIALIZED_THIS; break; case VTYPE_INFO_OBJECT: v.type=methodt::verification_type_infot::OBJECT; v.cpool_index=read_u2(); break; case VTYPE_INFO_UNINIT: v.type=methodt::verification_type_infot::UNINITIALIZED; v.offset=read_u2(); break; default: throw "error: unknown verification type info encountered"; } }
void java_bytecode_parsert::relement_value_pair( annotationt::element_value_pairt &element_value_pair) { u1 tag=read_u1(); switch(tag) { case 'e': { UNUSED u2 type_name_index=read_u2(); UNUSED u2 const_name_index=read_u2(); // todo: enum } break; case 'c': { UNUSED u2 class_info_index=read_u2(); // todo: class } break; case '@': { // another annotation, recursively annotationt annotation; rRuntimeAnnotation(annotation); } break; case '[': { u2 num_values=read_u2(); for(std::size_t i=0; i<num_values; i++) { annotationt::element_value_pairt element_value; relement_value_pair(element_value); // recursive call } } break; case 's': { u2 const_value_index=read_u2(); element_value_pair.value=string_constantt( pool_entry(const_value_index).s); } break; default: { u2 const_value_index=read_u2(); element_value_pair.value=constant(const_value_index); } break; } }
void java_bytecode_parsert::rfields(classt &parsed_class) { u2 fields_count=read_u2(); for(std::size_t i=0; i<fields_count; i++) { fieldt &field=parsed_class.add_field(); u2 access_flags=read_u2(); u2 name_index=read_u2(); u2 descriptor_index=read_u2(); u2 attributes_count=read_u2(); field.name=pool_entry(name_index).s; field.is_static=(access_flags&ACC_STATIC)!=0; field.is_final=(access_flags&ACC_FINAL)!=0; field.is_enum=(access_flags&ACC_ENUM)!=0; field.signature=id2string(pool_entry(descriptor_index).s); for(std::size_t j=0; j<attributes_count; j++) rfield_attribute(field); } }
void java_bytecode_parsert::rClassFile() { parse_tree.loading_successful=false; u4 magic=read_u4(); u2 UNUSED minor_version=read_u2(); u2 major_version=read_u2(); if(magic!=0xCAFEBABE) { error() << "wrong magic" << eom; throw 0; } if(major_version<44) { error() << "unexpected major version" << eom; throw 0; } rconstant_pool(); classt &parsed_class=parse_tree.parsed_class; u2 access_flags=read_u2(); u2 this_class=read_u2(); u2 super_class=read_u2(); parsed_class.is_abstract=(access_flags&ACC_ABSTRACT)!=0; parsed_class.is_enum=(access_flags&ACC_ENUM)!=0; parsed_class.name= constant(this_class).type().get(ID_C_base_name); if(super_class!=0) parsed_class.extends= constant(super_class).type().get(ID_C_base_name); rinterfaces(parsed_class); rfields(parsed_class); rmethods(parsed_class); // count elements of enum if(parsed_class.is_enum) for(fieldt &field : parse_tree.parsed_class.fields) if(field.is_enum) parse_tree.parsed_class.enum_elements++; u2 attributes_count=read_u2(); for(std::size_t j=0; j<attributes_count; j++) rclass_attribute(parsed_class); get_class_refs(); parse_tree.loading_successful=true; }
void java_bytecode_parsert::rfield_attribute(fieldt &field) { u2 attribute_name_index=read_u2(); u4 attribute_length=read_u4(); irep_idt attribute_name=pool_entry(attribute_name_index).s; if(attribute_name=="RuntimeInvisibleAnnotations" || attribute_name=="RuntimeVisibleAnnotations") { rRuntimeAnnotation_attribute(field.annotations); } else skip_bytes(attribute_length); }
/* 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; }
void java_bytecode_parsert::rcode_attribute(methodt &method) { u2 attribute_name_index=read_u2(); u4 attribute_length=read_u4(); irep_idt attribute_name=pool_entry(attribute_name_index).s; if(attribute_name=="LineNumberTable") { // address -> instructiont typedef std::map<unsigned, methodt::instructionst::iterator> instruction_mapt; instruction_mapt instruction_map; for(methodt::instructionst::iterator it=method.instructions.begin(); it!=method.instructions.end(); it++) { instruction_map[it->address]=it; } u2 line_number_table_length=read_u2(); for(std::size_t i=0; i<line_number_table_length; i++) { u2 start_pc=read_u2(); u2 line_number=read_u2(); // annotate the bytecode program instruction_mapt::const_iterator it= instruction_map.find(start_pc); if(it!=instruction_map.end()) it->second->source_location.set_line(line_number); } } else if(attribute_name=="LocalVariableTable") { u2 local_variable_table_length=read_u2(); method.local_variable_table.resize(local_variable_table_length); for(std::size_t i=0; i<local_variable_table_length; i++) { u2 start_pc=read_u2(); u2 length=read_u2(); u2 name_index=read_u2(); u2 descriptor_index=read_u2(); u2 index=read_u2(); method.local_variable_table[i].index=index; method.local_variable_table[i].name=pool_entry(name_index).s; method.local_variable_table[i].signature= id2string(pool_entry(descriptor_index).s); method.local_variable_table[i].start_pc=start_pc; method.local_variable_table[i].length=length; } } else if(attribute_name=="StackMapTable") { u2 stack_map_entries=read_u2(); method.stack_map_table.resize(stack_map_entries); for(size_t i=0; i<stack_map_entries; i++) { u1 frame_type=read_u1(); if(0<=frame_type && frame_type<=63) { method.stack_map_table[i].type=methodt::stack_map_table_entryt::SAME; method.stack_map_table[i].locals.resize(0); method.stack_map_table[i].stack.resize(0); } else if(64<=frame_type && frame_type<=127) { method.stack_map_table[i].type= methodt::stack_map_table_entryt::SAME_LOCALS_ONE_STACK; method.stack_map_table[i].locals.resize(0); method.stack_map_table[i].stack.resize(1); methodt::verification_type_infot verification_type_info; read_verification_type_info(verification_type_info); method.stack_map_table[i].stack[0]=verification_type_info; } else if(frame_type==247) { method.stack_map_table[i].type= methodt::stack_map_table_entryt::SAME_LOCALS_ONE_STACK_EXTENDED; method.stack_map_table[i].locals.resize(0); method.stack_map_table[i].stack.resize(1); methodt::verification_type_infot verification_type_info; u2 offset_delta=read_u2(); read_verification_type_info(verification_type_info); method.stack_map_table[i].stack[0]=verification_type_info; method.stack_map_table[i].offset_delta=offset_delta; } else if(248<=frame_type && frame_type<=250) { method.stack_map_table[i].type=methodt::stack_map_table_entryt::CHOP; method.stack_map_table[i].locals.resize(0); method.stack_map_table[i].stack.resize(0); u2 offset_delta=read_u2(); method.stack_map_table[i].offset_delta=offset_delta; } else if(frame_type==251) { method.stack_map_table[i].type =methodt::stack_map_table_entryt::SAME_EXTENDED; method.stack_map_table[i].locals.resize(0); method.stack_map_table[i].stack.resize(0); u2 offset_delta=read_u2(); method.stack_map_table[i].offset_delta=offset_delta; } else if(252<=frame_type && frame_type<=254) { size_t new_locals=(size_t) (frame_type-251); method.stack_map_table[i].type=methodt::stack_map_table_entryt::APPEND; method.stack_map_table[i].locals.resize(new_locals); method.stack_map_table[i].stack.resize(0); u2 offset_delta=read_u2(); method.stack_map_table[i].offset_delta=offset_delta; for(size_t k=0; k<new_locals; k++) { method.stack_map_table[i].locals .push_back(methodt::verification_type_infot()); methodt::verification_type_infot &v= method.stack_map_table[i].locals.back(); read_verification_type_info(v); } } else if(frame_type==255) { method.stack_map_table[i].type=methodt::stack_map_table_entryt::FULL; u2 offset_delta=read_u2(); method.stack_map_table[i].offset_delta=offset_delta; u2 number_locals=read_u2(); method.stack_map_table[i].locals.resize(number_locals); for(size_t k=0; k<(size_t) number_locals; k++) { method.stack_map_table[i].locals .push_back(methodt::verification_type_infot()); methodt::verification_type_infot &v= method.stack_map_table[i].locals.back(); read_verification_type_info(v); } u2 number_stack_items=read_u2(); method.stack_map_table[i].stack.resize(number_stack_items); for(size_t k=0; k<(size_t) number_stack_items; k++) { method.stack_map_table[i].stack .push_back(methodt::verification_type_infot()); methodt::verification_type_infot &v= method.stack_map_table[i].stack.back(); read_verification_type_info(v); } } else throw "error: unknown stack frame type encountered"; } } else skip_bytes(attribute_length); }
void java_bytecode_parsert::rmethod_attribute(methodt &method) { u2 attribute_name_index=read_u2(); u4 attribute_length=read_u4(); irep_idt attribute_name=pool_entry(attribute_name_index).s; if(attribute_name=="Code") { u2 UNUSED max_stack=read_u2(); u2 UNUSED max_locals=read_u2(); rbytecode(method.instructions); u2 exception_table_length=read_u2(); method.exception_table.resize(exception_table_length); for(std::size_t e=0; e<exception_table_length; e++) { u2 start_pc=read_u2(); u2 end_pc=read_u2(); u2 handler_pc=read_u2(); u2 catch_type=read_u2(); method.exception_table[e].start_pc=start_pc; method.exception_table[e].end_pc=end_pc; method.exception_table[e].handler_pc=handler_pc; if(catch_type!=0) method.exception_table[e].catch_type= to_symbol_type(pool_entry(catch_type).expr.type()); } u2 attributes_count=read_u2(); for(std::size_t j=0; j<attributes_count; j++) rcode_attribute(method); irep_idt line_number; // add missing line numbers for(methodt::instructionst::iterator it=method.instructions.begin(); it!=method.instructions.end(); it++) { if(!it->source_location.get_line().empty()) line_number=it->source_location.get_line(); else if(!line_number.empty()) it->source_location.set_line(line_number); it->source_location .set_function( "java::"+id2string(parse_tree.parsed_class.name)+"."+ id2string(method.name)+":"+method.signature); } // line number of method if(!method.instructions.empty()) method.source_location.set_line( method.instructions.begin()->source_location.get_line()); } else if(attribute_name=="RuntimeInvisibleAnnotations" || attribute_name=="RuntimeVisibleAnnotations") { rRuntimeAnnotation_attribute(method.annotations); } else skip_bytes(attribute_length); }
void java_bytecode_parsert::rbytecode( methodt::instructionst &instructions) { u4 code_length=read_u4(); u4 address; size_t bytecode_index=0; // index of bytecode instruction for(address=0; address<code_length; address++) { bool wide_instruction=false; u4 start_of_instruction=address; u1 bytecode=read_u1(); if(bytecode==0xc4) // wide { wide_instruction=true; address++; bytecode=read_u1(); } instructions.push_back(instructiont()); instructiont &instruction=instructions.back(); instruction.statement=bytecodes[bytecode].mnemonic; instruction.address=start_of_instruction; instruction.source_location .set_java_bytecode_index(std::to_string(bytecode_index)); switch(bytecodes[bytecode].format) { case ' ': // no further bytes break; case 'c': // a constant_pool index (one byte) if(wide_instruction) { instruction.args.push_back(constant(read_u2())); address+=2; } else { instruction.args.push_back(constant(read_u1())); address+=1; } break; case 'C': // a constant_pool index (two bytes) instruction.args.push_back(constant(read_u2())); address+=2; break; case 'b': // a signed byte { s1 c=read_u1(); instruction.args.push_back(from_integer(c, integer_typet())); } address+=1; break; case 'o': // two byte branch offset, signed { s2 offset=read_u2(); instruction .args.push_back(from_integer(address+offset, integer_typet())); } address+=2; break; case 'O': // four byte branch offset, signed { s4 offset=read_u4(); instruction .args.push_back(from_integer(address+offset, integer_typet())); } address+=4; break; case 'v': // local variable index (one byte) { u1 v=read_u1(); instruction.args.push_back(from_integer(v, integer_typet())); } address+=1; break; case 'V': // local variable index (two bytes) plus two signed bytes if(wide_instruction) { u2 v=read_u2(); instruction.args.push_back(from_integer(v, integer_typet())); s2 c=read_u2(); instruction.args.push_back(from_integer(c, integer_typet())); address+=4; } else // local variable index (one byte) plus one signed byte { u1 v=read_u1(); instruction.args.push_back(from_integer(v, integer_typet())); s1 c=read_u1(); instruction.args.push_back(from_integer(c, integer_typet())); address+=2; } break; case 'I': // two byte constant_pool index plus two bytes { u2 c=read_u2(); instruction.args.push_back(constant(c)); u1 b1=read_u1(); instruction.args.push_back(from_integer(b1, integer_typet())); u1 b2=read_u1(); instruction.args.push_back(from_integer(b2, integer_typet())); } address+=4; break; case 'L': // lookupswitch { u4 base_offset=address; // first a pad to 32-bit align while(((address+1)&3)!=0) { read_u1(); address++; } // now default value s4 default_value=read_u4(); instruction.args .push_back(from_integer(base_offset+default_value, integer_typet())); address+=4; // number of pairs u4 npairs=read_u4(); address+=4; for(std::size_t i=0; i<npairs; i++) { s4 match=read_u4(); s4 offset=read_u4(); instruction.args.push_back(from_integer(match, integer_typet())); instruction.args .push_back(from_integer(base_offset+offset, integer_typet())); address+=8; } } break; case 'T': // tableswitch { size_t base_offset=address; // first a pad to 32-bit align while(((address+1)&3)!=0) { read_u1(); address++; } // now default value s4 default_value=read_u4(); instruction.args .push_back(from_integer(base_offset+default_value, integer_typet())); address+=4; // now low value s4 low_value=read_u4(); address+=4; // now high value s4 high_value=read_u4(); address+=4; // there are high-low+1 offsets, and they are signed for(s4 i=low_value; i<=high_value; i++) { s4 offset=read_u4(); instruction.args.push_back(from_integer(i, integer_typet())); instruction.args .push_back(from_integer(base_offset+offset, integer_typet())); address+=4; } } break; case 'm': // multianewarray: constant-pool index plus one unsigned byte { u2 c=read_u2(); // constant-pool index instruction.args.push_back(constant(c)); u1 dimensions=read_u1(); // number of dimensions instruction.args.push_back(from_integer(dimensions, integer_typet())); address+=3; } break; case 't': // array subtype, one byte { typet t; switch(read_u1()) { case T_BOOLEAN: t.id(ID_bool); break; case T_CHAR: t.id(ID_char); break; case T_FLOAT: t.id(ID_float); break; case T_DOUBLE: t.id(ID_double); break; case T_BYTE: t.id(ID_byte); break; case T_SHORT: t.id(ID_short); break; case T_INT: t.id(ID_int); break; case T_LONG: t.id(ID_long); break; default:{}; } instruction.args.push_back(type_exprt(t)); } address+=1; break; case 's': // a signed short { s2 s=read_u2(); instruction.args.push_back(from_integer(s, integer_typet())); } address+=2; break; default: throw "unknown JVM bytecode instruction"; } bytecode_index++; } if(address!=code_length) { error() << "bytecode length mismatch" << eom; throw 0; } }
void java_bytecode_parsert::rconstant_pool() { u2 constant_pool_count=read_u2(); if(constant_pool_count==0) { error() << "invalid constant_pool_count" << eom; throw 0; } constant_pool.resize(constant_pool_count); for(constant_poolt::iterator it=constant_pool.begin(); it!=constant_pool.end(); it++) { // the first entry isn't used if(it==constant_pool.begin()) continue; it->tag=read_u1(); switch(it->tag) { case CONSTANT_Class: it->ref1=read_u2(); break; case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: case CONSTANT_NameAndType: case CONSTANT_InvokeDynamic: it->ref1=read_u2(); it->ref2=read_u2(); break; case CONSTANT_String: case CONSTANT_MethodType: it->ref1=read_u2(); break; case CONSTANT_Integer: case CONSTANT_Float: it->number=read_u4(); break; case CONSTANT_Long: case CONSTANT_Double: it->number=read_u8(); // Eight-byte constants take up two entires // in the constant_pool table, for annoying this programmer. if(it==constant_pool.end()) { error() << "invalid double entry" << eom; throw 0; } it++; it->tag=0; break; case CONSTANT_Utf8: { u2 bytes=read_u2(); std::string s; s.resize(bytes); for(std::string::iterator s_it=s.begin(); s_it!=s.end(); s_it++) *s_it=read_u1(); it->s=s; // hashes } break; case CONSTANT_MethodHandle: it->ref1=read_u1(); it->ref2=read_u2(); break; default: error() << "unknown constant pool entry (" << it->tag << ")" << eom; throw 0; } } // we do a bit of post-processing after we have them all for(constant_poolt::iterator it=constant_pool.begin(); it!=constant_pool.end(); it++) { // the first entry isn't used if(it==constant_pool.begin()) continue; switch(it->tag) { case CONSTANT_Class: { const std::string &s=id2string(pool_entry(it->ref1).s); it->expr=type_exprt(java_classname(s)); } break; case CONSTANT_Fieldref: { const pool_entryt &nameandtype_entry=pool_entry(it->ref2); const pool_entryt &name_entry=pool_entry(nameandtype_entry.ref1); const pool_entryt &class_entry=pool_entry(it->ref1); const pool_entryt &class_name_entry=pool_entry(class_entry.ref1); typet type=type_entry(nameandtype_entry.ref2); symbol_typet class_symbol= java_classname(id2string(class_name_entry.s)); exprt fieldref("fieldref", type); fieldref.set(ID_class, class_symbol.get_identifier()); fieldref.set(ID_component_name, name_entry.s); it->expr=fieldref; } break; case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: { const pool_entryt &nameandtype_entry=pool_entry(it->ref2); const pool_entryt &name_entry=pool_entry(nameandtype_entry.ref1); const pool_entryt &class_entry=pool_entry(it->ref1); const pool_entryt &class_name_entry=pool_entry(class_entry.ref1); typet type=type_entry(nameandtype_entry.ref2); symbol_typet class_symbol= java_classname(id2string(class_name_entry.s)); irep_idt component_name= id2string(name_entry.s)+ ":"+id2string(pool_entry(nameandtype_entry.ref2).s); irep_idt class_name= class_symbol.get_identifier(); irep_idt identifier= id2string(class_name)+"."+id2string(component_name); exprt virtual_function(ID_virtual_function, type); virtual_function.set(ID_component_name, component_name); virtual_function.set(ID_C_class, class_name); virtual_function.set(ID_C_base_name, name_entry.s); virtual_function.set(ID_identifier, identifier); it->expr=virtual_function; } break; case CONSTANT_String: { // ldc turns these into references to java.lang.String exprt string_literal(ID_java_string_literal); string_literal.set(ID_value, pool_entry(it->ref1).s); it->expr=string_literal; } break; case CONSTANT_Integer: it->expr=from_integer(it->number, java_int_type()); break; case CONSTANT_Float: { ieee_floatt value(ieee_float_spect::single_precision()); value.unpack(it->number); it->expr=value.to_expr(); } break; case CONSTANT_Long: it->expr=from_integer(it->number, java_long_type()); break; case CONSTANT_Double: { ieee_floatt value(ieee_float_spect::double_precision()); value.unpack(it->number); it->expr=value.to_expr(); } break; case CONSTANT_NameAndType: { it->expr.id("nameandtype"); } break; case CONSTANT_MethodHandle: { it->expr.id("methodhandle"); } break; case CONSTANT_MethodType: { it->expr.id("methodtype"); } break; case CONSTANT_InvokeDynamic: { it->expr.id("invokedynamic"); const pool_entryt &nameandtype_entry=pool_entry(it->ref2); typet type=type_entry(nameandtype_entry.ref2); it->expr.type()=type; } break; default:{}; } } }