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.mdb_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 create_asm_mirbin_label_cache(asm_path, popen_only=False, proc_saved={}): """ Create a dictionary for a given asm file When it is called the first time with a given asm file, it starts a subprocess to handle the asm file and returns None; When called subsequently using the same asm file, it will wait for the first subprocess to finish and return a dictionary created from its output. """ if m_debug.Debug: m_util.mdb_print("ASM Begin gen:" + asm_path) if not asm_path: for p in proc_saved.values(): m_util.proc_communicate(p) return None #TODO: This code prints to stdout on lldb which is a mess if m_debug.Debug: m_debug.dbg_print("asm_path=", asm_path) #if not path.exists(asm_path): if asm_path not in proc_saved: cmd="bash -c \"paste <(grep -bn _mirbin_info: '" + asm_path \ + "') <(grep -Fb .cfi_endproc '" + asm_path \ + "')\" | awk -F: -v a='\"' -v b='\":(' -v c=',' -v d='),' " \ "'BEGIN { print \"import pickle\\nimport sys\\nd={\" } " \ "{ print a$3b$1c$2c$4d } END { print \"}\\no=pickle.dumps(d,3)\\n" \ "sys.stdout.write(o.decode(\\\"latin1\\\"))\" }' | python3" proc_saved[asm_path] = m_util.proc_popen(cmd) if popen_only: return None d = m_util.proc_communicate(proc_saved.pop(asm_path)) if m_debug.Debug: m_util.mdb_print("ASM End/Load gen:" + str(d)) return pickle.loads(d)
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_modules_list(): """ wrapper of 'target modules list -o -s -g' cmd -- basic form is: [ 18] 0x00007fffe8fec000 /.../MAPLE/maple_engine/maple_runtime/lib/x86_64/libcore.so """ buf = m_util.mdb_exec_to_str('target modules list -o -s -g') if m_debug.Debug: m_debug.dbg_print("Module List = ", buf) return buf
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*)" #match_pattern = "libmplre.so`maple::maple_invoke_method(maple::method_header_t const*, maple::MFunction const*)" match_pattern = "maple::maple_invoke_method" buf = buf.split('\n') target = lldb.debugger.GetTargetAtIndex(0) bp_count = target.GetNumBreakpoints() stream = lldb.SBStream() #for line in buf: for i in range(0, bp_count): target.GetBreakpointAtIndex(i).GetDescription(stream) if m_debug.Debug: print("selected bp desc=", stream.GetData()) line = stream.GetData() if m_debug.Debug: m_debug.dbg_print("line=", line) if match_pattern in line or match_pattern == line: #x = line.split(match_pattern) #addr = x[0].split()[-1] info = target.GetBreakpointAtIndex(i).GetLocationAtIndex( 0).GetAddress() #info.GetDescription(stream) #x = " at " + stream.GetData().split(" at ")[1] addr = target.GetBreakpointAtIndex(i).GetLocationAtIndex( 0).GetLoadAddress() #print("x: ", x) #print("Addr Info: ", info) #print("Addr: ", hex(addr)) """ try: addr = int(addr, 16) except: print("Issue Parsing Addr: ", addr, iaddr) 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_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 lldb 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 get_modules_lookup(hdaddr): """ wrapper of 'target modules lookup -v -a' cmd -- basic form is: target modules lookup -v -a 0x7fffeb98cea8 Address: libcore.so[0x00000000029a0ea8] (libcore.so.PT_LOAD[0]..text + 21571096) Summary: libcore.so`Ljava_2Fio_2FPrintStream_3B_7Cprintln_7C_28Ljava_2Flang_2FString_3B_29V_mirbin_info Module: file = "/.../MAPLE/maple_engine/maple_runtime/lib/x86_64/libcore.so", arch = "x86_64" Symbol: id = {0x0003f050}, range = [0x00007fffeb98cea8-0x00007fffeb98cf20), name="Ljava_2Fio_2FPrintStream_3B_7Cprintln_7C_28Ljava_2Flang_2FString_3B_29V_mirbin_info" """ buf = m_util.mdb_exec_to_str('target modules lookup -v -a '+hdaddr) if m_debug.Debug: m_debug.dbg_print("Module Info = ", buf) return buf
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.mdb_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.mdb_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.mdb_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_mirheader_name_by_mirheader_addr(addr): cmd = 'x ' + addr try: result = m_util.mdb_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 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) """ #print("Here the mess starts") 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.mdb_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): mdb_print ("Warning: The header address is lower than lib_addr.") return None if (pc < header): mdb_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 create_mirbin_info_cache(self, asm_file): if m_debug.Debug: print("Entered create_mirbin_info_cache") 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 get_lib_addr_from_proc_mapping(addr): """ for a given Maple method address, find out the base address of the .so lib this address belongs to params: addr: address of a method in int returns: lib so base address in int """ buf = get_modules_lookup(addr) start = None start_min = None end = None end_max = None path = None so_path = None asm_path = None for (hexstart, hexend, path) in re.findall(proc_mapping_re, buf): try: start = int(hexstart, 16) except: start = None try: end = int(hexend, 16) except: end = None if not start or not end or not path: continue if addr >= start and addr <= end: if not start_min: start_min = start else: start_min = start if start < start_min else start if not end_max: end_max = end else: end_max = end if end > end_max else end if m_debug.Debug: m_debug.dbg_print("start = ", hex(start), " start_min = ", hex(start_min), " end = ", hex(end), "end_max = ", hex(end_max), " addr = ", hex(addr)) return start if m_debug.Debug: m_debug.dbg_print("return lib addr None") return None
def create_mirmpl_info_cache(self, mirmpl_path): if m_debug.Debug: print("Entered create_mirmpl_info_cache") 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 look_up_next_opcode(asm_path, asm_line, asm_offset): """ for a given asm file and asm line number and offset of the asm line number, return whether next opcode is going to jump to different source code line (e.g. Java code). If True, return next opcode's short source file name and line. params: asm_path: string. asm (.s) file full path. asm_line: int asm_offset: int. start offset in asm file line return: True if msi cmd should stop at next opcodd, and source code short file name and source line False if msi cmd should not stop. None as source name, None as source line """ if m_debug.Debug: m_debug.dbg_print("asm_path = ", asm_path, "asm_line = ", asm_line, "asm_offset=", asm_offset) f = open(asm_path, "r") f.seek(asm_offset) line = f.readline() short_src_file_name = None short_src_file_linenum = None additional_lines = 0 while True: line = f.readline() if "// LINE " in line: x = line.split() short_src_file_name = x[2] short_src_file_linenum = int(x[4][:-1]) if m_debug.Debug: m_debug.dbg_print("short_src_file_name = ", short_src_file_name,\ "short_src_file_linenum", short_src_file_linenum,\ "found in asm line_num =", asm_line + additional_lines) f.close() return True, short_src_file_name, short_src_file_linenum elif ".byte " in line: f.close() return False, None, None elif ".cfi_endproc" in line: break else: continue f.close() return False, None, None
def lookup_mirmpl_info(mirmpl_path, mirmpl_line_tuple, mir_instidx): """ in file mirmpl_path, and mirmpl_line_tuple, for a given func_addr_offset_pc, lookup the matching line's line-num and its offset params: mirmpl: string. mirmpl file full path. mirmpl_line_tuple: a tuple for a Maple symbol. tuple[0] = mirmpl symbol block line number tuple[1] = mirmpl symbol block start offset tuple[2] = mirmpl symbol block end offset mir_instidx: string. mir_instidx offset_pc e.g. 0008 return: a dict {'mirmpl_line': int, 'mirmpl_line_offset': int} where mirmple_line: func_addr_offset_pc found at this line, and at this mirmpl file offset """ if m_debug.Debug: m_debug.dbg_print("mirmpl_path=", mirmpl_path, "mirmpl_line_tuple=", mirmpl_line_tuple, "mir_instidx=", mir_instidx) offset = mirmpl_line_tuple[1] line_num = mirmpl_line_tuple[0] end_offset = mirmpl_line_tuple[2] if not mir_instidx: # return this symbol block's first address return {'mirmpl_line': line_num, 'mirmpl_line_offset': offset} f = open(mirmpl_path, "r") f.seek(offset) while offset < end_offset: line = f.readline() if mir_instidx in line: if m_debug.Debug: m_debug.dbg_print("found ", mir_instidx, " at line", line_num, "line=", line) f.close() return {'mirmpl_line': line_num, 'mirmpl_line_offset': offset} else: line_num += 1 offset += len(line) f.close() return None
def find_one_file(name, path): """ find the file with specified name and given base path """ if not name: return None exist = m_datastore.mlldb_rdata.in_fullpath_cache(name, path) if exist: return m_datastore.mlldb_rdata.get_fullpath_cache(name, path) res = None for root, dirs, files in os.walk(path): if name in files: res = os.path.join(root, name) if not res: if m_debug.Debug: m_debug.dbg_print( "find_one_file found file with None fullpath") break m_datastore.mlldb_rdata.add_fullpath_cache(name, path, res) if res == None: return (".../" + name) return res
def get_symbol_name_by_current_frame_args(): """ get the Maple symbol name and its address in currect frame stack via 'info args' command """ cmd = 'info args' try: result = m_util.mdb_exec_to_str(cmd) except: return None, None if m_debug.Debug: m_debug.dbg_print("result=", result) offset = result.find('_mirbin_info>') if offset is -1: #no Maple metadata pattern return None, None x = result.split() for i in range(len(x)): if x[i].find('_mirbin_info>') != -1: return x[i - 1], x[i][1:-1] return None, None
def update_mdb_runtime_data(self): if m_debug.Debug: print("update mdb rt data ...") addr_offset, so_path, asm_path, func_header, mirmpl_path = m_frame.get_newest_maple_frame_func_lib_info( ) targ = lldb.debugger.GetSelectedTarget() module_cnt = targ.GetNumModules() #for x in range(0, module_cnt): # mod = targ.GetModuleAtIndex(x) # print("Module:",mod) 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): if m_debug.Debug: mdb_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): if m_debug.Debug: mdb_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: if m_debug.Debug: mdb_print("create def cache using file: " + def_file_path) self.create_class_def(def_file_path)
def lookup_next_src_file_info(asm_path, asm_line, asm_offset): """ for a given asm file and asm line number and offset of the asm line number, return the next source file name and line. params: asm_path: string. asm (.s) file full path. asm_line: int asm_offset: int return: source code short file name or None if not found source code line number or 0 if not found """ if m_debug.Debug: m_debug.dbg_print("asm_path = ", asm_path, "asm_line = ", asm_line, "asm_offset=", asm_offset) f = open(asm_path, "r") f.seek(asm_offset) short_src_file_name = None short_src_file_linenum = None additional_lines = 0 while additional_lines < 5: line = f.readline() if "// LINE " in line: x = line.split() short_src_file_name = x[2] short_src_file_linenum = int(x[4][:-1]) if m_debug.Debug: m_debug.dbg_print("short_src_file_name = ", short_src_file_name, "short_src_file_linenum", short_src_file_linenum,\ "found in asm line_num =", asm_line + additional_lines ) f.close() return short_src_file_name, short_src_file_linenum else: additional_lines += 1 f.close() return None, None
def get_symbol_name_by_current_func_args(): """ get the 'func' symbol name and its address in currect frame stack """ cmd = 'p func' try: result = m_util.mdb_exec_to_str(cmd) except: return None, None if m_debug.Debug: m_debug.dbg_print("result=", result) if 'header = ' in result and '_mirbin_info>' in result: s = result.split('header = ') address = s[1].split()[0] name = s[1].split()[1].split('>')[0][1:] caller = result.split('caller = ')[1].split(',')[0] if m_debug.Debug: m_debug.dbg_print("address=", address, "name=", name, "caller=", caller) return address, name else: return None, None
def get_uninitialized_maple_func_addrs(): """ get func addr information from an uninitialized Maple frame. NOTE: call this when Maple func is NOT initialized yet. returns: 1, func header address in string format of xxxxxx:yyyyyy: format where xxxxxx means (header - lib_base_addr), yyyyyy means (pc - header - header_size) 2, so_path: in string. so library full path. 3, asm_path: in string. asm (.s) file full path 4, func_header: func header address in string. 5, mirmpl_path: in string. .mpl.mir.mpl file full path """ func_header = get_maple_frame_addr() if not func_header: return None, None, None, None, None if m_debug.Debug: m_debug.dbg_print("func_header=", func_header) offset, func_lib_addr, so_path, asm_path, mirmpl_path = get_lib_so_info(func_header) if not func_lib_addr or not so_path or not asm_path or not mirmpl_path: return None, None, None, None, None if m_debug.Debug: m_debug.dbg_print("func_lib_addr=", func_lib_addr) #header = int(func_header, 16) #fla = int(func_lib_addr, 16) #if (header < fla): # if m_debug.Debug: m_debug.dbg_print("Warning: The header address is lower than lib_addr.") # return None, None, None, None, None #offset = header - fla # when a func in a frame is not initialized yet, pc value is 0000 pc = '0000' return hex(int(offset, 16)) + ":" + pc + ":", so_path, asm_path, func_header, mirmpl_path
def get_maple_class_def(self, class_name): if class_name in self.maple_class_def_cache: if m_debug.Debug: m_debug.dbg_print("class_name", class_name, "found") m_debug.dbg_print("return maple_class_def_cache[class_name]:", self.maple_class_def_cache[class_name]) return self.maple_class_def_cache[class_name] if m_debug.Debug: m_debug.dbg_print("class_name", class_name, "Not found") return None
def get_asm_mirbin_item(self, asm, mirbin_name): if not asm in self.mirbin_info_cache: if m_debug.Debug: m_debug.dbg_print("asm", asm, "not found in mirbin info cache ") return None if not mirbin_name in self.mirbin_info_cache[asm]: if m_debug.Debug: m_debug.dbg_print("Maple label", mirbin_name, "not found in mirbin info cache ") m_debug.dbg_print("Maple label", mirbin_name, "not found in mirbin info cache ") return None if m_debug.Debug: m_debug.dbg_print("return ", self.mirbin_info_cache[asm][mirbin_name]) return self.mirbin_info_cache[asm][mirbin_name]
def get_symbol_name_by_current_frame_args(): """ get the Maple symbol name and its address in currect frame stack via 'frame variable' command """ mir_addr = m_info.get_maple_frame_addr() a = int(mir_addr, 0) buf = m_info.get_modules_lookup(mir_addr) start = None mir_name = None """ Address: libcore.so[0x00000000029a0ea8] (libcore.so.PT_LOAD[0]..text + 21571096) Summary: libcore.so`Ljava_2Fio_2FPrintStream_3B_7Cprintln_7C_28Ljava_2Flang_2FString_3B_29V_mirbin_info Module: file = "/vagrant/MAPLE/maple_engine/maple_runtime/lib/x86_64/libcore.so", arch = "x86_64" Symbol: id = {0x0003f050}, range = [0x00007fffeb98cea8-0x00007fffeb98cf20), name="Ljava_2Fio_2FPrintStream_3B_7Cprintln_7C_28Ljava_2Flang_2FS """ if m_debug.Debug: m_debug.dbg_print("result=", buf) infos = buf.split('\n') if not infos: return None, None try: #if m_debug.Debug: m_debug.dbg_print("Infos:", infos) for line in infos: if "Symbol:" in line: y = line[14:].split() z = y[5].split('-') start = z[0][1:] if m_debug.Debug: m_debug.dbg_print("lib start addr:", start) if "Summary:" in line: y = line[14:].split() offset = line.find('_mirbin_info') if offset is -1: #no Maple metadata pattern return None, None mir_name = y if m_debug.Debug: m_debug.dbg_print("name", mir_name) else: #if m_debug.Debug: m_debug.dbg_print("Infos line:", line) continue return start, mir_name except Exception: print("-" * 60) print("Exception caught in m_break code:") traceback.print_stack(file=sys.stdout) print("-" * 60) traceback.print_exc(file=sys.stdout) print("-" * 60) return None, None return None, None
def get_mirmpl_item(self, mirmpl, symbol): if not mirmpl in self.mirmpl_info_cache: if m_debug.Debug: m_debug.dbg_print("mirmpl", mirmpl, "not found in mirmpl info cache ") return None if not symbol in self.mirmpl_info_cache[mirmpl]: if m_debug.Debug: m_debug.dbg_print("Maple label", symbol, "not found in mirmpl_info_cache[", mirmpl, "]") return None if m_debug.Debug: m_debug.dbg_print("return ", self.mirmpl_info_cache[mirmpl][symbol]) return self.mirmpl_info_cache[mirmpl][symbol]
def get_maple_caller_argument_value(arg_idx, arg_num, mtype): """ for a given Maple caller's arg_idx, arg_num and type, get its value from caller's operand_stack params: arg_idx: the argument index in a Maple method. e.g. method1(int a, long b, string c), for argument "a", its arg index is 0, c is 2. arg_num: number of argument a method has mtype : a string. definition in m_asm.py for "a", it could be 'i32', 'i64' returns: the argument value in string. """ if m_debug.Debug: m_debug.dbg_print("pass in arg_idx=", arg_idx, "arg_num=", arg_num, "mtype=", mtype) # get the caller.sp first try: #buffer = m_util.mdb_exec_to_str('p caller.sp') buffer = m_util.mdb_exec_to_str('p caller->sp') except: return None if 'No symbol "caller" in current context.' in buffer: return None if ' = ' in buffer: sp = int(buffer.split(' = ')[-1]) else: return None if arg_idx > sp: #sp must be >= num of args return None if m_debug.Debug: m_debug.dbg_print("sp=", sp) # get the caller.operand_stack length try: buffer = m_util.mdb_exec_to_str('p caller->operand_stack.size()') except: return None if m_debug.Debug: m_debug.dbg_print("ss=", buffer) #if buffer[0] != '$': if not buffer or buffer[0] != '(': return None if ' = ' in buffer: try: length = int(buffer.split(' = ')[1]) except: return None else: return None if m_debug.Debug: m_debug.dbg_print("length=", length) if length < arg_idx: return None # get the caller.operand_stack[arg_idx] idx = sp - arg_num + arg_idx + 1 if m_debug.Debug: m_debug.dbg_print("idx=", idx) try: #buffer = m_util.mdb_exec_to_str('p caller->operand_stack[' + str(idx) + ']') stbuffer = m_util.mdb_exec_to_str('p caller->operand_stack') #if m_debug.Debug: m_debug.dbg_print("stbuffer=", stbuffer) buffer = stbuffer.split('x = (')[(idx+1)] #if m_debug.Debug: m_debug.dbg_print("buffer=", buffer) vline = buffer.split(')')[0] if m_debug.Debug: m_debug.dbg_print("vline=", vline) except: return None #vline = buffer.split('x = ')[1][1:].split('}')[0] v = vline.split(mtype+' = ')[1].split(',')[0] if mtype in vline else None return v
def get_loaded_lib_asm_path(): asm_path_list = [] #objfiles = mdb.objfiles() objfiles = {} for objfile in objfiles: if not lib_file_filter(objfile.filename): continue so_path = os.path.realpath(objfile.filename) if m_debug.Debug: m_debug.dbg_print("realpath so_path=",so_path) asm_path = so_path[:-3] + '.VtableImpl.s' asm_path = os.path.realpath(asm_path) if os.path.exists(so_path) and os.path.exists(asm_path): # both .so file and co-responding .s file exist in same directory if m_debug.Debug: m_debug.dbg_print("return lib info: so_path=",so_path, "asm_path=", asm_path) asm_path_list.append(asm_path) continue asm_path = so_path[:-3] + '.s' asm_path = os.path.realpath(asm_path) if os.path.exists(so_path) and os.path.exists(asm_path): # both .so file and co-responding .s file exist in same directory if m_debug.Debug: m_debug.dbg_print("return lib info: so_path=",so_path, "asm_path=", asm_path) asm_path_list.append(asm_path) continue so_path_short_name = so_path.split('/')[-1][:-3] base = so_path.split('/') asm_path = '' for i in range(len(base) - 4): asm_path += '/' + base[i] asm_path += '/maple_build/out/x86_64/'+ so_path_short_name + '.VtableImpl.s' asm_path = os.path.realpath(asm_path) if os.path.exists(so_path) and os.path.exists(asm_path): # special case where .so and .VtableImpl.s are in such a different folders if m_debug.Debug: m_debug.dbg_print("return lib info: so_path=",so_path, "asm_path=", asm_path) asm_path_list.append(asm_path) continue if not 'maple_lib_asm_path' in m_set.msettings: continue for v in m_set.msettings['maple_lib_asm_path']: asm_path = v + '/' + so_path_short_name + '.VtableImpl.s' asm_path = os.path.realpath(asm_path) #asm_path = path.split('maple/out')[0] + 'maple/out/common/share/' + so_path_short_name + '.VtableImpl.s' if os.path.exists(so_path) and os.path.exists(asm_path): # .s file is in the search path list if m_debug.Debug: m_debug.dbg_print("return lib info: so_path=",so_path, "asm_path=", asm_path) asm_path_list.append(asm_path) continue if m_debug.Debug: m_debug.dbg_print("returning asm_path_list length", len(asm_path_list)) m_debug.dbg_print("returning asm_path_list ", asm_path_list) return asm_path_list
def get_lib_so_info(addr): """ for a given Maple method address, look up the lib so file, and get information about the so library and its co-responding asm file info. params: addr: address of a method in hex string with prefix '0x', i.e 0x7fff6021c308 returns: 1, so lib start address: int 2, lib so file full path in string 3, lib asm file full path in string 4, lib mpl.mir.mpl file full path in string """ start = None end = None path = None so_path = None asm_path = None mirmpl_path = None a = int(addr, 0) buf = get_modules_lookup(addr) """ Address: libcore.so[0x00000000029a0ea8] (libcore.so.PT_LOAD[0]..text + 21571096) Summary: libcore.so`Ljava_2Fio_2FPrintStream_3B_7Cprintln_7C_28Ljava_2Flang_2FString_3B_29V_mirbin_info Module: file = "/vagrant/MAPLE/maple_engine/maple_runtime/lib/x86_64/libcore.so", arch = "x86_64" Symbol: id = {0x0003f050}, range = [0x00007fffeb98cea8-0x00007fffeb98cf20), name="Ljava_2Fio_2FPrintStream_3B_7Cprintln_7C_28Ljava_2Flang_2FS """ infos = buf.split('\n') offset = 0 if not infos: return None, None, None, None, None try: #if m_debug.Debug: m_debug.dbg_print("Infos:", infos) for line in infos: if "Module:" in line: x = line[14:].split() so_path = x[2][1:][:-2] if m_debug.Debug: m_debug.dbg_print("base file:",so_path) elif "Symbol:" in line: y = line[14:].split() z = y[5].split('-') start = z[0][1:] end = z[1][2:] if m_debug.Debug: m_debug.dbg_print("lib start addr:", start,"end:",end) elif "Address:" in line: x = line[14:].split() y = x[0].split('[') offset = y[1][:-1] if m_debug.Debug: m_debug.dbg_print("offset:",offset) else: #if m_debug.Debug: m_debug.dbg_print("Infos line:", line) continue if not so_path.rstrip().lower().endswith('.so'): if m_debug.Debug: m_debug.dbg_print("path does not end with .so, path = ", so_path) return None, None, None, None, None so_path = so_path.rstrip().replace('/./','/') #if m_debug.Debug: m_debug.dbg_print("mdb.solib_name(addr)=", mdb.solib_name(a)) mirmpl_path = so_path[:-3] + '.mpl.mir.mpl' mirmpl_path = os.path.realpath(mirmpl_path) asm_path = so_path[:-3] + '.VtableImpl.s' asm_path = os.path.realpath(asm_path) if os.path.exists(so_path) and os.path.exists(asm_path) and os.path.exists(mirmpl_path): # both .so file and co-responding .s file exist in same directory if m_debug.Debug: m_debug.dbg_print("return lib info: start=", start, "so_path=",so_path,\ "asm_path=", asm_path, "mirmpl_path=", mirmpl_path) return offset, start, so_path, asm_path, mirmpl_path else: if m_debug.Debug: m_debug.dbg_print("first round fails validation, path = ", so_path) asm_path = so_path[:-3] + '.s' asm_path = os.path.realpath(asm_path) mirmpl_path = so_path[:-3] + '.mpl.mir.mpl' mirmpl_path = os.path.realpath(mirmpl_path) if os.path.exists(so_path) and os.path.exists(asm_path) and os.path.exists(mirmpl_path): # both .so file and co-responding .s file exist in same directory if m_debug.Debug: m_debug.dbg_print("return lib info: start=", start, "so_path=",so_path, \ "asm_path=", asm_path, "mirmpl_path=", mirmpl_path) return offset, start, so_path, asm_path, mirmpl_path else: if m_debug.Debug: m_debug.dbg_print("second round fails validation, path = ", so_path) so_path_short_name = so_path.split('/')[-1][:-3] base = so_path.split('/') asm_path = '' for i in range(len(base) - 4): asm_path += '/' + base[i] mirmpl_path = asm_path + '/maple_build/out/x86_64/'+ so_path_short_name + '.mpl.mir.mpl' mirmpl_path = os.path.realpath(mirmpl_path) asm_path += '/maple_build/out/x86_64/'+ so_path_short_name + '.VtableImpl.s' asm_path = os.path.realpath(asm_path) if os.path.exists(so_path) and os.path.exists(asm_path) and os.path.exists(mirmpl_path): # special case where .so and .VtableImpl.s are in such a different folders if m_debug.Debug: m_debug.dbg_print("return lib info: start=", start, "so_path=",so_path, \ "asm_path=", asm_path, "mirmpl_path=", mirmpl_path) return offset, start, so_path, asm_path, mirmpl_path else: if m_debug.Debug: m_debug.dbg_print("third round fails validation, path = ", so_path) if not 'maple_lib_asm_path' in m_set.msettings: return None, None, None, None for v in m_set.msettings['maple_lib_asm_path']: mirmpl_path = v + '/'+ so_path_short_name + '.mpl.mir.mpl' mirmpl_path = os.path.realpath(mirmpl_path) asm_path = v + '/' + so_path_short_name + '.VtableImpl.s' asm_path = os.path.realpath(asm_path) #asm_path = path.split('maple/out')[0] + 'maple/out/common/share/' + so_path_short_name + '.VtableImpl.s' if os.path.exists(so_path) and os.path.exists(asm_path) and os.path.exists(mirmpl_path): # .s file is in the search path list if m_debug.Debug: m_debug.dbg_print("return lib info: start=", start, "so_path=",so_path, \ "asm_path=", asm_path, "mirmpl_path", mirmpl_path) return offset, start, so_path, asm_path, mirmpl_path else: if m_debug.Debug: m_debug.dbg_print("settings round fails validation, path = ", so_path) except Exception: print("-"*60) print("Exception caught in m_break code:") traceback.print_stack(file=sys.stdout) print("-"*60) traceback.print_exc(file=sys.stdout) print("-"*60) return None, None, None, None, None return None, None, None, None, None
def get_stack_frame_data(frame): """ For a given Maple stack frame, get all finds of frame data including 1, function. Header info 2, function. Source code information 3, function. Local variable and argument information. params: frame: a gdb.frame object. A SELECTED Maple frame from current stack. returns: a dict contains following keys and values 'frame_func_src_info': whatever m_asm.lookup_src_file_info() returns {'short_src_file_name': a string. source code short name 'short_src_file_line': a int. source code file line 'asm_line': a int. line number where func_header_name offset is found in asm file 'asm_offset': a int. offset in the asm file co-repsonding to asm_line 'mirmpl_line': a int. symbol block line in mir.mpl file 'mirmpl_line_offset': a int. symbol block line offset in mir.mpl file 'mir_instidx': a string. symbol block mir instidx offset, e.g. 0008 in both .s and .s file } 'frame_func_header_info': {'func_name': func_name, string. 'so_path': so_path full path, a string 'asm_path': asm_path full path,a string 'mirmpl_path': mir.mpl file full path. a string 'func_addr_offset': func_addr_offset, string in xxxx:yyyy: format 'func_header_name' : func_header_name, a string. e.g. xxxxxxxxxxx_mirbin_info 'func_header_asm_tuple': func_header_name_block_asm_tuple, (asm line, asm_start_offset, asm_end_offset) 'func_header_mirmpl_tuple': func_header_name_block_mir_tuple, (mir line, mir_start_offset, mir_end_offset) } 'func_argus_locals': same return as m_asm.get_func_arguments() returns {'locals_type': local variable type list, e.g. ['void', 'v2i64'], 'locals_name': local variable name list['%%retval', '%%thrownval'], 'formals_type': func argument type list. e.g. ['a64'], 'formals_name': func argument name list. e.g. ['%1'] } """ #m_debug.Debug = True if m_debug.Debug: m_debug.dbg_print("==== get_stack_frame_data =====") func_addr_offset, so_path, asm_path, func_header, mirmpl_path = m_frame.get_maple_frame_func_lib_info( frame) if m_debug.Debug: m_debug.dbg_print("func_addr_offset =", func_addr_offset, "func_header=", func_header) m_debug.dbg_print("so_path =", so_path, "asm_path=", asm_path, "mirmpl_path=", mirmpl_path) if not func_addr_offset or not so_path or not asm_path or not func_header or not mirmpl_path: return None ### get the function label of the frame label_addr, func_header_name = m_symbol.get_symbol_name_by_current_frame_args( ) if m_debug.Debug: m_debug.dbg_print("func_header_name=", func_header_name) if func_header_name: fhn = func_header_name[0].split('`') func_header_name = fhn[1] func_name = func_header_name[:-12] if m_debug.Debug: m_debug.dbg_print("func_name=", func_name) else: label_addr, func_header_name = m_symbol.get_symbol_name_by_current_func_args( ) fhn = func_header_name[0].split('`') func_header_name = fhn[1] func_name = func_header_name[:-12] if m_debug.Debug: m_debug.dbg_print("func_name=", func_name) if m_debug.Debug: m_debug.dbg_print("func_header_name=", func_header_name) if not func_header_name: return None # if mirbin_info_cache for this asm file is not created yet in m_datastore, create it # if not m_datastore.mgdb_rdata.mirbin_info_cache_has_key(asm_path): if not mlldb_rdata.mirbin_info_cache_has_key(asm_path): if m_debug.Debug: m_debug.dbg_print("create mirbin info cache for asm file", asm_path) mlldb_rdata.create_mirbin_info_cache(asm_path) # if mirmpl_info_cache for this mir.mpl file is not created yet in m_datastore, create it # if not m_datastore.mgdb_rdata.mirmpl_info_cache_has_key(mirmpl_path): if not mlldb_rdata.mirmpl_info_cache_has_key(mirmpl_path): if m_debug.Debug: m_debug.dbg_print("create mirmpl info cache for mirmpl file", mirmpl_path) mlldb_rdata.create_mirmpl_info_cache(mirmpl_path) asm_line_tuple = mlldb_rdata.get_one_label_mirbin_info_cache( asm_path, func_header_name) if not asm_line_tuple: if m_debug.Debug: m_debug.dbg_print("no asm_line_tuple found", asm_path, "for", func_header_name) return None if m_debug.Debug: m_debug.dbg_print("asm_line_tuple=", asm_line_tuple) m_debug.dbg_print("func_addr_offset=", func_addr_offset) m_debug.dbg_print("func_addr_offset.split(':')[1]=", func_addr_offset.split(':')[1]) func_addr_offset_pc = func_addr_offset.split(':')[1] d = m_asm.lookup_src_file_info(asm_path, asm_line_tuple[0], asm_line_tuple[1], asm_line_tuple[2],\ func_addr_offset_pc) if not d: if m_debug.Debug: m_debug.dbg_print("lookup_src_file_info returns None") return None if m_debug.Debug: m_debug.dbg_print("first round returns dict d:", d) # In some cases, when func_addr_offset's pc partion is 0000, or func_addr_offset is followed by "MPL_CLINIT_CHECK", # the source code file information can be missing. # In this case, we can check few more lines from its reported asm line ONLY for pc = '0000' or "MPI_CLINIT_CHECK" situation if not d['short_src_file_name'] and ( func_addr_offset_pc == '0000' or d['short_src_file_line'] == -1) and d['asm_offset'] != 0 and d['asm_line'] != 0: if m_debug.Debug: m_debug.dbg_print( "func offset pc is 0000, check short_src_file again") d['short_src_file_name'], d['short_src_file_line'] = \ m_asm.lookup_next_src_file_info(asm_path, d['asm_line'], d['asm_offset']) if m_debug.Debug: m_debug.dbg_print( "second round for func offset pc 0000 returns dict d:", d) # read the mpl.mir.mpl file, get the func_addr_offset_pc line and offset at .mpl.mir.mpl file # note, func_header_name ends with symbol_mirbin_info, while mir.mpl's symbol has no '_mirbin_info' #print("mirmpl_path=",mirmpl_path, "func_header_name[:-12]=",func_header_name[:-12]) mirmpl_line_tuple = mlldb_rdata.get_one_label_mirmpl_info_cache( mirmpl_path, func_header_name[:-12]) mir_instidx = d['mir_instidx'] #print("mirmpl_line_tuple=",mirmpl_line_tuple, "mir_instidx=", mir_instidx) d_mirmpl = m_mirmpl.lookup_mirmpl_info(mirmpl_path, mirmpl_line_tuple, mir_instidx) #rint("d_mirmpl=",d_mirmpl) # dictionary of d_mirmpl: {'mirmpl_line': int, 'mirmpl_Line_offset': int} if not d_mirmpl: if m_debug.Debug: m_debug.dbg_print("lookup_mirmpl_info returns None") return None if m_debug.Debug: m_debug.dbg_print( "m_mirmpl.lookup_mirmpl_info() returns dict d_mirmpl:", d_mirmpl) # merge two dictionaries d = {**d, **d_mirmpl} if m_debug.Debug: m_debug.dbg_print("After merging asm_d and mirmpl_d:", d) asm_line_offset = asm_line_tuple[1] asm_line_num = d['asm_line'] mirmpl_line_num = d['mirmpl_line'] mirmpl_line_offset = d['mirmpl_line_offset'] src_file_short_name = d['short_src_file_name'] src_file_line = d['short_src_file_line'] if not asm_line_offset: return None ### get the method arguments and local variables func_argus_locals = m_asm.get_func_arguments(asm_path, func_header_name, asm_line_offset) if m_debug.Debug: m_debug.dbg_print("func_argus_locals:", func_argus_locals) if not func_argus_locals: return None rdata = {} rdata['frame_func_src_info'] = d rdata['frame_func_header_info'] = { 'so_path': so_path, \ 'asm_path': asm_path, \ 'mirmpl_path': mirmpl_path, \ 'func_addr_offset': func_addr_offset, \ 'func_name': func_name, \ 'func_header_name' : func_header_name, \ 'func_header_asm_tuple': asm_line_tuple, \ 'func_header_mirmpl_tuple': mirmpl_line_tuple \ } rdata['func_argus_locals'] = func_argus_locals return rdata
def does_mbp_exist(): """ determine where a Maple breakpoint exists """ target = lldb.debugger.GetSelectedTarget() #namelist = lldb.SBStringList() #namelist.AppendString('maple::maple_invoke_method') #print(dir(namelist)) #namelist.AppendString('maple::maple_invoke_method') #print ("namelist.GetSize()=", namelist.GetSize()) #print ("namelist.GetStringAtIndex(0)=", namelist.GetStringAtIndex(0)) #print (dir(target.GetBreakpointNames(namelist))) #print (target.GetBreakpointNames(namelist)) #print (dir(namelist)) #print ("namelist.IsValid()=", namelist.IsValid()) #print ("namelist.GetSize()=", namelist.GetSize()) #print ("namelist.GetStringAtIndex(0)=", namelist.GetStringAtIndex(0)) num_bp = target.GetNumBreakpoints() if m_debug.Debug: m_debug.dbg_print("does_mbp_exist: num_bp=", num_bp) for i in range(num_bp): bp = target.GetBreakpointAtIndex(i) if m_debug.Debug: m_debug.dbg_print("\nbp=", bp) enabled_bool = bp.IsEnabled() if m_debug.Debug: m_debug.dbg_print("id=", bp.GetID(), "enabled_bool=", enabled_bool, "isValid()=", bp.IsValid()) if m_debug.Debug: m_debug.dbg_print("num_location=", bp.GetNumLocations(), "num_resolved_loc=", bp.GetNumResolvedLocations()) #print("bp.GetThreadName()=", bp.GetThreadName(), "bp.GetQueueName()=", bp.GetQueueName()) #print("bp.MatchesName(maple::maple_invoke_method)=", bp.MatchesName('maple::maple_invoke_method')) stream = lldb.SBStream() bp.GetDescription(stream) if m_debug.Debug: m_debug.dbg_print("selected bp desc=", stream.GetData()) bp_name = stream.GetData().split("name = ")[1].split(",")[0].replace( "'", "") if m_debug.Debug: m_debug.dbg_print("bp_name=", bp_name) if bp_name == 'maple::maple_invoke_method': return True, bp #__getattr__ = lambda self, name: _swig_getattr(self, SBBreakpointLocation, name) #print ("__getattr__=", __getattr) # using GetLocatioAtIndex() could help to get the breakpoint name Once we run the # the program. ''' bl = bp.GetLocationAtIndex(0) print ("bl=", bl) if not bl: continue print("bl.GetAddress()=", bl.GetAddress()) print("bl.GetAddress().GetSymbol().GetName()=", bl.GetAddress().GetSymbol().GetName()) bp_name = bl.GetAddress().GetSymbol().GetName() print("bl.GetLoadAddress()=", bl.GetLoadAddress()) ''' ''' for bl in bp: print("bl=", bl) bl_load_addr = bl.GetLoadAddress() bl_addr = bl.GetAddress() print("bp", bp.GetID(), "loc addr=", bl_addr, "loc_load_addr=", loc_load_addr) if 'maple::maple_invoke_method' in bl_addr.GetSymbol().GetName() and enabled_bool: print("found match") return True, bp else: print("no match") ''' return False, None