def mstep_func(self, args): frame = m_frame.get_selected_frame() ds = m_datastore.get_stack_frame_data(frame) if not ds: return if m_debug.Debug: m_debug.dbg_print("retrieved ds=", ds) asm_path = ds['frame_func_header_info']['asm_path'] asm_line = ds['frame_func_src_info']['asm_line'] asm_offset = ds['frame_func_src_info']['asm_offset'] stop = False short_src_file_name = None short_src_file_line = None count = 0 while not stop: # before we execute msi command, we must know should we stop keep executing msi after the current msi # is executed. If current msi command is executed and found it should stop, then we need the source file # information after stop. stop, short_src_file_name, short_src_file_line = m_asm.look_up_next_opcode( asm_path, asm_line, asm_offset) if m_debug.Debug: m_debug.dbg_print("stop =", stop, "short_src_file_name=", short_src_file_name, "short_src_file_line=", short_src_file_line) m_util.gdb_exec("msi -internal") count += 1 if m_debug.Debug: m_debug.dbg_print("executed %d opcodes", count) # retrieve the new frame data since one opcode can change to a different frame frame = m_frame.get_selected_frame() ds = m_datastore.get_stack_frame_data(frame) if not ds: gdb_print("Warning: Failed to get new stack frame to continue") return if m_debug.Debug: m_debug.dbg_print("retrieved ds=", ds) asm_path = ds['frame_func_header_info']['asm_path'] asm_line = ds['frame_func_src_info']['asm_line'] asm_offset = ds['frame_func_src_info']['asm_offset'] gdb_print("Info: executed %d %s" % (count, 'opcode' if count == 1 else 'opcodes')) if m_debug.Debug: m_debug.dbg_print("short_src_file_name = ", short_src_file_name, "short_src_file_line=", short_src_file_line) file_full_path = None for source_path in m_list.maple_source_path_list: file_full_path = m_list.find_one_file(short_src_file_name, source_path) if not file_full_path: continue else: break if not file_full_path: gdb_print("Warning: source file %s not found" % (short_src_file_name)) else: m_list.display_src_file_lines(file_full_path, short_src_file_line) return
def display_symbol_detail(symbol_name, symbol_asm_path): if m_debug.Debug: m_debug.dbg_print("symbol_asm_path=", symbol_asm_path, "symbol_name=", symbol_name) if not symbol_name or not symbol_asm_path: return data = m_datastore.mgdb_rdata.get_one_label_mirbin_info_cache( symbol_asm_path, symbol_name) d = m_asm.lookup_src_file_info(symbol_asm_path, data[0], data[1], data[2], "0000") if not d: return short_src_file_name, short_src_file_line = m_asm.lookup_next_src_file_info(symbol_asm_path,\ d["asm_line"], d['asm_offset']) file_full_path = None for source_path in m_list.maple_source_path_list: file_full_path = m_list.find_one_file(short_src_file_name, source_path) if not file_full_path: continue else: break gdb_print("assembly file : " + symbol_asm_path) if not file_full_path: gdb_print("source : unknown") else: gdb_print("source : " + file_full_path) gdb_print("demangled name: " + m_symbol.get_demangled_maple_symbol( m_util.color_symbol(MColors.SP_SNAME, symbol_name[:-12])))
def display_array_char_values(self, addr, type_size, item_num): if item_num > 32: item_list = [i for i in range(24)] item_list = item_list + [i for i in range(item_num - 8, item_num)] else: item_list = [i for i in range(item_num)] steps = 0 show_snip = True buf = 'String Value: "' + MColors.MP_STR_V for i in item_list: obj_addr = addr + 4 + type_size * i # class reference is a pointer, 8 bytes cmd = 'x/1hx ' + hex(obj_addr) if m_debug.Debug: m_debug.dbg_print("cmd=", cmd) try: buffer = m_util.gdb_exec_to_str(cmd) except: buf = ' {}'.format('no-data') gdb_print(buf) steps += 1 return steps += 1 v = buffer.split(':')[1].strip() buf = buf + int(v, 16).to_bytes( 2, byteorder='big').decode("utf-16-be") if item_num > 32 and steps >= 24 and show_snip == True: buf = buf + '...' show_snip = False gdb_print(buf + MColors.ENDC + '"') return
def get_demangled_maple_symbol(symbol, to_filename=False): """ for a given Maple symbol, convert it to demangled symbol name """ if not '_7C' in symbol: return None s = symbol s = s.replace('_7C', '') # use the jni format s = s.replace('_3B', ';') s = s.replace('_2F', '.') s = s.replace('_28', '(') s = s.replace('_29', ')') s = s.replace('_3C', '<') s = s.replace('_3E', '>') s = s.replace('_24', '$') if to_filename == False: return s # to here, label becomes something like "Ljava.lang.Class;|getComponentType|()Ljava.lang.Class;" s = s.split('|')[0] s = s.replace(';', '') s = s[1:] f = s.replace('.', '/') f = f + '.java' if m_debug.Debug: m_debug.dbg_print("s=", s, "f=", f) return f
def get_current_frame_rip(frame): """ for a given frame, get its register "pc" value, and use the pc value to get the first instruction's memory address, return it as frame's rip params: frame: a gdb.Frame object returns: rip address, or frame's first instruction address: an int """ if not frame: return None arch = frame.architecture() current_pc = frame.read_register("pc") if m_debug.Debug: m_debug.dbg_print("current_pc obj=", current_pc) current_pc = int(current_pc) # arch.disassemble(start_pc) returns a list of disassembled instructions from start_pc. # each element of the list is a dict contains 'addr', 'asm', 'length' which addr is the # memory address of the instruction. # see https://sourceware.org/gdb/onlinedocs/gdb/Architectures-In-Python.html#Architectures-In-Python disa = arch.disassemble(current_pc)[0] if m_debug.Debug: m_debug.dbg_print("disa=", disa) return disa['addr']
def update_gdb_runtime_data(self): addr_offset, so_path, asm_path, func_header, mirmpl_path = m_frame.get_newest_maple_frame_func_lib_info( ) if m_debug.Debug: m_debug.dbg_print("addr_offset=", addr_offset) m_debug.dbg_print("so_path=", so_path) m_debug.dbg_print("asm_path=", asm_path) m_debug.dbg_print("func_header=", func_header) m_debug.dbg_print("mirmpl_path=", mirmpl_path) if not addr_offset or not so_path or not asm_path or not func_header or not mirmpl_path: return if not self.mirmpl_info_cache_has_key(mirmpl_path): gdb_print("create Maple mir.mpl cache using file: " + mirmpl_path) self.create_mirmpl_info_cache(mirmpl_path) if not self.mirbin_info_cache_has_key(asm_path): gdb_print("create Maple symbol cache using file: " + asm_path) self.create_mirbin_info_cache(asm_path) def_file_path = asm_path[: -1] + 'macros.def' if 'VtableImpl' in asm_path else asm_path[: -1] + 'VtableImpl.macros.def' if not def_file_path in self.class_def.def_paths: gdb_print("create def cache using file: " + def_file_path) self.create_class_def(def_file_path)
def mni_display_last_opcodes(): # to display the latest instructions will be executed after this command frame = m_frame.get_selected_frame() if not frame: return ds = m_datastore.get_stack_frame_data(frame) if not ds: return if m_debug.Debug: m_debug.dbg_print("retrieved ds=", ds) if m_set.msettings['stack'] == 'on': m_util.gdb_exec('mlocal -stack') asm_path = ds['frame_func_header_info']['asm_path'] asm_line = ds['frame_func_src_info']['asm_line'] asm_offset = ds['frame_func_src_info']['asm_offset'] gdb_print("asm file: %s%s%s" % (MColors.BT_SRC, asm_path, MColors.ENDC)) f = open(asm_path, 'r') f.seek(asm_offset) line = f.readline() gdb_print(str(asm_line) + " : " + line.rstrip()) line = f.readline() gdb_print(str(asm_line+1) + " : " + line.rstrip()) line = f.readline() gdb_print(str(asm_line+2) + " : " + line.rstrip()) f.close()
def get_maple_invoke_bp_stop_addr(buf): """ get Maple breakpoint address and its coresponding information params: buf: a string output of m_util.gdb_exec_to_str("info b") Return: None on address and None on breakpoint information if no information found, or 1, addr: int. breakpoint stop address 2, info: additional breakpoint information stating breakpoint source code and line Return data example: addr = 0x00007ffff5b5f061 info = at /home/test/gitee/maple_engine/maple_engine/src/invoke_method.cpp:151 """ match_pattern = "in maple::maple_invoke_method(maple::method_header_t const*, maple::MFunction const*)" buf = buf.split('\n') for line in buf: if m_debug.Debug: m_debug.dbg_print("line=", line) if match_pattern in line: x = line.split(match_pattern) addr = x[0].split()[-1] try: addr = int(addr, 16) except: return None, None info = match_pattern + " ".join(x[1:]) if m_debug.Debug: m_debug.dbg_print("addr = ", addr, "info = ", info) return addr, info return None, None
def get_obj_prop_list_head(addr): cmd = "p *(struct __jsobject *)" + str(addr) # example of output could be: # 1. when prop_list is not available meaning nothing should be interpreted. # "$40 = {prop_list = 0x0, prototype = {obj = 0x2, id = JSBUILTIN_OBJECTPROTOTYPE}, extensible = 1 '\001', object_class = JSGLOBAL, object_type = 0 '\000', # is_builtin = 1 '\001', proto_is_builtin = 1 '\001', builtin_id = JSBUILTIN_GLOBALOBJECT, shared = {fast_props = 0x0, array_props = 0x0, fun = 0x0, # prim_string = 0x0, prim_regexp = 0x0, prim_number = 0, prim_bool = 0, arr = 0x0, primDouble = 0}} # # 2. when prop_list is available, we should get the list and traverse the prop list # $85 = {prop_list = 0x7ffff63d4178, prototype = {obj = 0x2, id = JSBUILTIN_OBJECTPROTOTYPE}, extensible = 1 '\001', object_class = JSGLOBAL, object_type = 0 '\000' # , is_builtin = 1 '\001', proto_is_builtin = 1 '\001', builtin_id = JSBUILTIN_GLOBALOBJECT, shared = {fast_props = 0x0, array_props = 0x0, fun = 0x0, # prim_string = 0x0, prim_regexp = 0x0, prim_number = 0, prim_bool = 0, arr = 0x0, primDouble = 0}} buf = gdb.execute(cmd, to_string = True) buf = buf.rstrip() if m_debug.Debug: m_debug.dbg_print("get_obj_prop_list_head buf = ", buf) if buf[0] != '$' or 'prop_list = ' not in buf: return None prop_list = buf.split("prop_list = ")[1].split(',')[0] try: prop_list_addr = int(prop_list, 16) except: return None if m_debug.Debug: m_debug.dbg_print("prop_list_addr=", prop_list_addr) if prop_list_addr == 0: return None else: return prop_list
def update_mbp(self): """ when enabled maple breakpoints reach to 0, we disable the breakpint of maple::maple_invoke_method for better performance. When enabled maple breakpoints changes from 0 to 1 or more, we enable the breakpoint maple::maple_invoke_method. However, if the maple::maple_invoke_method is pending, we do not do anything since it is not activated yet However, the beter way to do this is to use mbp_id.enabled = True or False to enable or disable the maple::maple_invoke_method. We chose not to do it this way, because our regression test suite needs an output pattern that can be checked easily. changing enabled=True or False does not make this easier. """ mbp_id = get_mbp_id() if not mbp_id: return # if maple:maple_invoke_method breakpoint is pending, we do not have to do anything. if mbp_id.pending: return # get the maple breakpoint number for those are enabled mbp_num = self.get_enabled_mbp_number() if m_debug.Debug: m_debug.dbg_print("mbp_num returned =", mbp_num) # disable maple:maple_invoke_method breakpoint buf = m_util.gdb_exec_to_str("info b") if mbp_num == 0: # disable this breakpoint update_maple_invoke_bp(buf, False) else: # enable this breakpoint update_maple_invoke_bp(buf, True)
def get_maple_frame_stack_sp_index(func_header_name): """ for a given func header name, find out its sp value reported in operand_stack """ # get the func.operand_stack length try: buffer = m_util.gdb_exec_to_str('p func') except: return None if 'No symbol "func" in current context.' in buffer: return None stack_header_name = buffer.split('header = ')[1].split()[1][1:-2] if stack_header_name != func_header_name: if m_debug.Debug: m_debug.dbg_print("func_header_name=", func_header_name, "stack_header_name=", stack_header_name) return None sp_str = buffer.split('sp = ')[1].split()[0][:-1] if not sp_str: return None try: sp = int(sp_str) except: return None return sp
def mstepi_update_and_display(self, frame): # this will update the Maple gdb runtime metadata store. m_datastore.mgdb_rdata.update_gdb_runtime_data() m_datastore.mgdb_rdata.update_frame_change_counter() ds = m_datastore.get_stack_frame_data(frame) if not ds: return if m_debug.Debug: m_debug.dbg_print("retrieved ds=", ds) if m_set.msettings['stack'] == 'on': m_util.gdb_exec('mlocal -stack') asm_path = ds['frame_func_header_info']['asm_path'] asm_line = ds['frame_func_src_info']['asm_line'] asm_offset = ds['frame_func_src_info']['asm_offset'] gdb_print("asm file: %s%s%s" % (MColors.BT_SRC, asm_path, MColors.ENDC)) f = open(asm_path, 'r') f.seek(asm_offset) gdb_print("=> %d : %s" % (asm_line, f.readline().rstrip())) gdb_print(" %d : %s" % (asm_line + 1, f.readline().rstrip())) gdb_print(" %d : %s" % (asm_line + 2, f.readline().rstrip())) f.close() m_util.gdb_exec('display')
def get_array_length(self, addr): cmd = 'x/1xw ' + hex(addr) try: buffer = m_util.gdb_exec_to_str(cmd) except: return 0 item_num = int(buffer.split(':')[1].strip(), 16) if m_debug.Debug: m_debug.dbg_print("item_num=", item_num) return item_num
def get_mbp_id(): """ get a Maple breakpoint gdb.Breakpoint object id """ blist = gdb.breakpoints() for b in blist: if m_debug.Debug: m_debug.dbg_print("b.type=", b.type, "b.location=", b.location, "b.thread=", b.thread, "b.enabled=", b.enabled,\ "b.is_valid()=", b.is_valid()) if 'maple::maple_invoke_method' in b.location and b.is_valid(): return b return None
def is_mbp_existed(): """ determine where a Maple breakpoint exists """ blist = gdb.breakpoints() for b in blist: if m_debug.Debug: m_debug.dbg_print("b.type=", b.type, "b.location=", b.location, "b.thread=", b.thread, "b.enabled=", b.enabled,\ "b.is_valid()=", b.is_valid()) if 'maple::maple_invoke_method' in b.location and b.is_valid(): return True, b return False, None
def get_prop_list_node_data(node_addr): # input: node_addr is the address of node, a pointer value to 'struct __jsprop' # output: return node data in dict format. # dict: # {'tag': 'JSTYPE_NUMBER' # 'ascii_name': 'var' # 'utf16_name : 'ㅶ' # 'next': 0x12323434 # 'name_addr': 0x55555576d1a8 # 'value': 6 (if tag JSTYPE_NUMBER) # : hello world (if tag = JSTYPE_STRING # : index (if tag = JSTYPE_OBJECT) # : None: if tag = JSTYPE_UNDEFINED or JSTYPE_NONE or JSTYPE_NULL # cmd = "p *(struct __jsprop *)" + node_addr if m_debug.Debug: m_debug.dbg_print("cmd=", cmd) buf = gdb.execute(cmd, to_string = True) buf = buf.rstrip() if m_debug.Debug: m_debug.dbg_print("get_prop_list_data buf=", buf) # example of output: # "$86 = {n = {index = 1433850280, name = 0x55555576d1a8}, next = 0x0, desc = {{named_data_property = {value = {asbits = 34359738368, s = {payload = {i32 = 0,u32 = 0, boo = 0, str = 0, obj = 0, ptr = 0}, tag = JSTYPE_UNDEFINED}}}, named_accessor_property = {get = 0x800000000, set = 0x0}}, {s = {attr_writable = 3 '\003', attr_enumerable = 3 '\003', attr_configurable = 2 '\002', fields = 0 '\000'}, attrs = 131843}}, isIndex = false}" if buf[0] != '$' or 'next = ' not in buf or 'desc = ' not in buf: return data prop_next = buf.split("next = ")[1].split(',')[0] prop_name_addr = buf.split("name = ")[1].split(',')[0][:-1] tag = buf.split("tag = ")[1].split('}}}')[0] if m_debug.Debug: m_debug.dbg_print("prop_next=", prop_next, "prop_name_addr=", prop_name_addr, "tag=", tag) ascii_name, utf16_name = get_prop_name_value(prop_name_addr) if m_debug.Debug: m_debug.dbg_print("ascii_name=", ascii_name, "utf16_name=", utf16_name) element = {} element['tag'] = tag element['ascii_name'] = ascii_name element['utf16_name'] = utf16_name element['next'] = prop_next element['name_addr'] = prop_name_addr if tag == 'JSTYPE_UNDEFINED' or tag == 'JSTYPE_NONE' or tag == 'JSTYPE_NULL': element['value'] = "" elif tag == 'JSTYPE_NUMBER': value = buf.split('payload = {i32 = ')[1].split(',')[0] element['value'] = value elif tag == 'JSTYPE_BOOLEAN': value = buf.split('boo = ')[1].split(',')[0] element['value'] = value elif tag == 'JSTYPE_STRING': index = buf.split('str = ')[1].split(',')[0] ascii_v, utf16_v = get_string_value_from_index(index) element['value'] = ascii_v else: element['value'] = "" if m_debug.Debug: m_debug.dbg_print("element=", element) return element
def get_msi_bp_dync_id(): """ gets an msi breakpoint gdb.Breakpoint object id """ blist = gdb.breakpoints() for b in blist: if m_debug.Debug: m_debug.dbg_print("b.type=", b.type, "b.location=", b.location, "b.thread=", \ b.thread, "b.enabled=", b.enabled, "b.is_valid()=", b.is_valid()) if '__inc_opcode_cnt_dyn' == b.location and b.is_valid(): return b return None
def is_msi_bp_dync_existed(): """ determines if the msi breakpoints exist or not """ blist = gdb.breakpoints() for b in blist: if m_debug.Debug: m_debug.dbg_print("b.type=", b.type, "b.location=", b.location, "b.thread=", \ b.thread, "b.enabled=", b.enabled, "b.is_valid()=", b.is_valid()) if '__inc_opcode_cnt_dyn' == b.location and b.is_valid(): return True, b return False, None
def get_maple_symbol_full_syntax(symbol): """ for a given Maple symbol, return its full syntax, also known as its symbol description. params symbol: string. symbol we can see in gdb stack data. e.g. __cinf_Ljava_2Flang_2FString_3B, __cinf_ALjava_2Flang_2FString_3B __cinf_ZLsun_xxxxxxxxxxxxxxxxxxxx __cinf_JLjavax_yyyyyyyyyyyyyyy __cinf_FLsun_xxxxxxxxxxxxxxxxx return: type_size: int. object size full syntax in string. examples of full syntax: array int my_array[] boolean my_var """ if m_debug.Debug: m_debug.dbg_print("symbol=", symbol) # check a special symbol for Java native array string if symbol is '__cinf_Ljava_2Flang_2FString_3B': return 'array string', 0 # if it is class object, not primitive nor array if symbol[:8] in maple_symbol_type_dict: if symbol[7] == 'L': # if it is a Maple java object full_syntax = maple_symbol_type_dict[symbol[:8]] else: full_syntax = maple_symbol_type_dict[symbol[:8]] + ' ' + symbol[8:] if symbol[7] in java_type_to_size_dict: type_size = java_type_to_size_dict[symbol[7]] else: type_size = 1 if m_debug.Debug: m_debug.dbg_print("full_syntax=", full_syntax, "type_size=", type_size) return full_syntax, type_size # to check if it is array of class, or array of primitive type. array_type_prefix = symbol[3:8] if array_type_prefix == 'inf_A': dimension = 0 while array_type_prefix in symbol: dimension += 1 array_type_prefix += 'A' array_type_prefix = 'inf_' + 'A' * dimension name = symbol.split(array_type_prefix)[1] return 'array ' + name + '[]' * dimension, java_type_to_size_dict[ name[0]] else: return 'unknown ' + symbol, 0
def mfinish_func(self, args): frame = m_frame.get_newest_frame() if not frame: return silent_finish() frame = m_frame.get_selected_frame() if m_debug.Debug: m_debug.dbg_print("frame.name()=", frame.name()) m_util.gdb_exec("msi") m_util.gdb_exec("mlist") m_datastore.mgdb_rdata.update_frame_change_counter()
def create_mirmpl_info_cache(self, mirmpl_path): if self.mirmpl_info_cache_has_key(mirmpl_path): return self.mirmpl_info.init_new_mirmpl(mirmpl_path) d = m_mirmpl.create_mirmpl_label_cache(mirmpl_path) self.mirmpl_info_cache_assign(mirmpl_path, d) if m_debug.Debug: count = len(self.mirmpl_info.mirmpl_info_cache[mirmpl_path].keys()) m_debug.dbg_print("mirmpl path ", mirmpl_path, count, "labels found")
def create_mirbin_info_cache(self, asm_file): if self.mirbin_info_cache_has_key(asm_file): return self.mirbin_info.init_new_asm(asm_file) d = m_asm.create_asm_mirbin_label_cache(asm_file) self.mirbin_info_cache_assign(asm_file, d) if m_debug.Debug: count = len(self.mirbin_info.mirbin_info_cache[asm_file].keys()) m_debug.dbg_print("asm file ", asm_file, count, "labels found")
def display_array_primitive_values(self, addr, full_syntax, type_size): buffer = 'Object Type: {}'.format(MColors.MP_FSYNTAX + full_syntax + MColors.ENDC) gdb_print(buffer) item_num = self.get_array_length(addr) buffer = 'Level 1 {}: length={}'.format( MColors.MP_FSYNTAX + full_syntax + MColors.ENDC, item_num) gdb_print(buffer) if item_num > 10: item_list = [ 0, 1, 2, 3, 4, 5, 6, item_num - 3, item_num - 2, item_num - 1 ] else: item_list = [i for i in range(item_num)] steps = 0 show_snip = True for i in item_list: obj_addr = addr + 4 + type_size * i # class reference is a pointer, 8 bytes if type_size == 8: cmd = 'x/1gx ' + hex(obj_addr) elif type_size == 4: cmd = 'x/1xw ' + hex(obj_addr) elif type_size == 2: cmd = 'x/1xh ' + hex(obj_addr) elif type_size == 1: cmd = 'x/1xb ' + hex(obj_addr) else: return if m_debug.Debug: m_debug.dbg_print("cmd=", cmd) try: buffer = m_util.gdb_exec_to_str(cmd) except: buf = ' [{}] {}'.format(i, 'no-data') gdb_print(buf) steps += 1 continue steps += 1 v = buffer.split(':')[1].strip() v = hex(int(v, 16)) #remove leading 0s. e.g. 0x000123 to 0x123 if full_syntax == 'array C[]': # display unicode character v = v + ", '" + int(v, 16).to_bytes( 2, byteorder='big').decode("utf-16-be") + "'" buf = ' [{}] {}'.format(i, v) gdb_print(buf) if item_num > 10 and steps > 6 and show_snip == True: gdb_print(" ...") show_snip = False return
def get_one_frame_stack_dynamic(sp, idx): """ for a given sp and index number in a dynamic caller operand_stack data, return its data type and value. Note, at runtime, caller.operand_stack is dynamic, sp, idx, types and values are all changing during the run time. """ if idx > sp: return None, None # get the caller.operand_stack length length = None try: buffer = m_util.gdb_exec_to_str('p func.operand_stack.size()') except: return None, None if buffer[0] != '$': return None, None if ' = ' in buffer: try: length = int(buffer.split(' = ')[1]) except: return None, None else: return None, None if m_debug.Debug: m_debug.dbg_print("length=", length) if length <= sp or length < idx: return None, None try: maple_type = m_util.gdb_exec_to_str('p func.operand_stack[' + str(idx) + '].ptyp') except: return None, None maple_type = maple_type.split(' = ')[1].split('maple::PTY_')[1].rstrip() try: buffer = m_util.gdb_exec_to_str('p func.operand_stack[' + str(idx) + ']') except: return None, None value = buffer.split('x = ')[1][1:].split('}')[0] if maple_type in value: v = value.split(maple_type + ' = ')[1].split(',')[0] else: return None, None if m_debug.Debug: m_debug.dbg_print("return maple_type=", maple_type, "v=", v) return maple_type, v
def get_maple_frame_func_lib_info(frame): """ for a given Maple frame, find and return function related frame information params: frame: a gdb.Frame object. returns: 1, func_header_offset: in string. 2, so_path: string. so library file full path. 3, asm_path: string. asm file full path. 4, func_header: int. address of function header. 5, mirmpl_path: in string. .mpl.mir.mpl file full path """ frame_rip = get_current_frame_rip(frame) buf = m_util.gdb_exec_to_str("info b") bp_addr, bp_info = m_breakpoint.get_maple_invoke_bp_stop_addr(buf) if m_debug.Debug: m_debug.dbg_print("frame_rip =", frame_rip, "bp_addr=", bp_addr) # if breakpoint address is not same to frame_rip (first instruction address of the frame), # this means program already passed first instruction of the function if bp_addr != frame_rip: func_addr_offset = m_info.get_initialized_maple_func_addrs() # func_addr_offset in string if not func_addr_offset: if m_debug.Debug: m_debug.dbg_print("func_addr_offset=None") return None, None, None, None, None func_header = m_info.get_initialized_maple_func_attr('func.header') start_addr, so_path, asm_path, mirmpl_path = m_info.get_lib_so_info( func_header) if m_debug.Debug: m_debug.dbg_print("func_addr_offset=", func_addr_offset, "so_path=", so_path, \ "asm_path=", asm_path, "func_header=", func_header, "mirmpl_path=", mirmpl_path) return func_addr_offset, so_path, asm_path, func_header, mirmpl_path # the breakpoint address is same to frame.rip (first instruction address in the memory), # this means program just stops at the first instruction of the function, so the func is NOT # initialized yet func_addr_offset, so_path, asm_path, func_header, mirmpl_path = m_info.get_uninitialized_maple_func_addrs( ) # func_addr_offset in string , format of func_addr:offset: if not func_addr_offset or not so_path or not asm_path or not func_header or not mirmpl_path: if m_debug.Debug: m_debug.dbg_print("func_addr_offset=", func_addr_offset, "so_path=", so_path, "asm_path=", asm_path) if m_debug.Debug: m_debug.dbg_print("func_header=", func_header, "mirmpl_path=", mirmpl_path) return None, None, None, None, None return func_addr_offset, so_path, asm_path, func_header, mirmpl_path
def get_mirheader_name_by_mirheader_addr(addr): cmd = 'x ' + addr try: result = m_util.gdb_exec_to_str(cmd) except: return None result = result.rstrip() if m_debug.Debug: m_debug.dbg_print("result=", result, "addr=", addr) if addr in result: return result.split()[1][1:-2] else: return None
def mtype_func(self, args, from_tty): s = args.split() if len(s) == 0 or len(s) > 1: self.usage() return # create a re.recompile pattern reg = r"(%s)+" % s[0] pattern = re.compile(reg) # class_list is a sorted list that contains class names class_list = m_datastore.mgdb_rdata.get_class_def_list() if m_debug.Debug: m_debug.dbg_print("return class_list length:", len(class_list)) if len(class_list) == 0: gdb_print("The class information table is not available yet") gdb_print( "Retry this after running Maple breakpoint and Maple stack commands" ) return count = 0 last_matching_class_name = None for class_name in class_list: m = pattern.search(class_name) if not m: continue count += 1 buffer = '#{} class name: {}'.format( count, MColors.TP_CNAME + class_name + MColors.ENDC) gdb_print(buffer) last_matching_class_name = class_name if count > 1: return inheritance_list = self.get_class_inheritance_list( last_matching_class_name) if not inheritance_list: return if m_debug.Debug: m_debug.dbg_print("return inheritance_list length:", len(inheritance_list)) self.display_class_list(inheritance_list) gdb_print("\n Method list:") updated_asm_path_list = get_updated_lib_asm_path_list() symbol = "^" + last_matching_class_name + "_7C" print_prefix = "" search_display_symbol_list(symbol, 4, print_prefix, updated_asm_path_list)
def get_initialized_maple_func_addrs(): """ get an initialized Maple frame func header address returns: func header address in string format of xxxxxx:yyyyyy: format where xxxxxx means (header - lib_base_addr), yyyyyy means (pc - header - header_size) """ header = get_initialized_maple_func_attr('func.header') pc = get_initialized_maple_func_attr('func.pc') if m_debug.Debug: m_debug.dbg_print("header=", header, "pc=", pc) if not header or not pc: return None try: header = int(header, 16) except: return None try: pc = int(pc, 16) except: return None lib_addr = get_lib_addr_from_proc_mapping(header) if m_debug.Debug: m_debug.dbg_print("header=", header, "lib_addr=",lib_addr, "pc=", pc) if not lib_addr: return None try: buf = m_util.gdb_exec_to_str('x/1xw ' + str(header)) except: return None if not buf: return None header_size = int(buf.split(':')[1],16) if (header < lib_addr): gdb_print ("Warning: The header address is lower than lib_addr.") return None if (pc < header): gdb_print ("Warning: The pc address is lower than the header address.") return None xxxxxx = header - lib_addr yyyyyy = pc - header - header_size return hex(xxxxxx) + ":" + "{:04x}".format(yyyyyy)+":"
def search_display_symbol_list(sym_regexp, indent, print_prefix, asm_path_list): """ search symbols using symb_regexp, print matching symbol name with given prefix. params: sym_regexp: string. regular expression for the symbol to be searched print_prefix: string. the prefix for print. asm_path_list: search with the asm paths in asm_path_list indent: int. number of space characters returns: count: number of matched symbol last_matchimg_symbol_name: string, or None if count = 0 last_matching_symbol_path: string, or None if count = 0 """ # create a re.recompile pattern reg = r"(%s)+" % sym_regexp pattern = re.compile(reg) count = 0 last_matching_symbol_name = None last_matching_symbol_path = None asm_path = None for asm_path in asm_path_list: # asm_symbol_list is a sorted list contains all the symbols from asm_path asm_symbol_list = m_datastore.mgdb_rdata.get_mirbin_cache_symbol_list( asm_path) if m_debug.Debug: m_debug.dbg_print("asm=", asm_path, ", len(asm_symbol_list)=", len(asm_symbol_list)) for symbol_name in asm_symbol_list: m = pattern.search(symbol_name) if not m: continue count += 1 indent_str = ' ' * indent if print_prefix: buffer = '{}#{} {}: {}'.format( indent_str, count, print_prefix, m_util.color_symbol(MColors.SP_SNAME, symbol_name[:-12])) else: buffer = '{}#{} {}'.format( indent_str, count, m_util.color_symbol(MColors.TP_MNAME, symbol_name[:-12])) gdb_print(buffer) last_matching_symbol_name = symbol_name last_matching_symbol_path = asm_path return count, last_matching_symbol_name, last_matching_symbol_path
def get_class_inheritance_list(self, class_name): inherit_list = [] name = class_name count = 0 while True: obj_class_dict = m_datastore.mgdb_rdata.get_class_def(name) if m_debug.Debug: m_debug.dbg_print("count=", count, "obj_class_dict=", obj_class_dict) if not obj_class_dict: return None inherit_list = [{ 'class_name': name, 'obj_class': obj_class_dict }] + inherit_list count += 1 if obj_class_dict['base_class'] == 'THIS_IS_ROOT': break else: name = obj_class_dict['base_class'] if m_debug.Debug: m_debug.dbg_print("count=", count, "obj_class_dict=", obj_class_dict) for i, v in enumerate(inherit_list): if m_debug.Debug: m_debug.dbg_print(" inherit_list #", i, v) if m_debug.Debug: m_debug.dbg_print() return inherit_list