def invoke(self, arg, from_tty): argv = gdb.string_to_argv(arg) if len(argv) != 2: raise gdb.GdbError('hex-dump takes exactly 2 arguments.') addr = gdb.parse_and_eval(argv[0]).cast( gdb.lookup_type('void').pointer()) try: bytes = int(gdb.parse_and_eval(argv[1])) except ValueError: raise gdb.GdbError('Byte count numst be an integer value.') inferior = gdb.selected_inferior() align = gdb.parameter('hex-dump-align') width = gdb.parameter('hex-dump-width') if width == 0: width = 16 mem = inferior.read_memory(addr, bytes) pr_addr = int(str(addr), 16) pr_offset = width if align: pr_offset = width - (pr_addr % width) pr_addr -= pr_addr % width for group in groups_of(mem, width, pr_offset): print '0x%x: ' % (pr_addr, ) + ' ' * (width - pr_offset), print ' '.join(['%02X' % (ord(g),) for g in group]) + \ ' ' * (width - len(group) if pr_offset == width else 0) + ' ', print ' ' * (width - pr_offset) + ''.join( [g if isgraph(g) or g == ' ' else '.' for g in group]) pr_addr += width pr_offset = width
def invoke(self, arg, from_tty): processes = _get_process_list() # Translating gdb values to python often trips over these. Heads up. save_print_address = "yes" if gdb.parameter("print address") else "no" save_print_symbol = "yes" if gdb.parameter("print symbol") else "no" gdb.execute("set print address on") gdb.execute("set print symbol off") # Make sure we restore these when we're done. try: for p in processes: handles = _get_handle_list(p) num_handles = len(handles) print("Process %u" % (p["id_"])) print(" %3s %-18s %4s %8s %s" % ( "Num", "Handle*", "Pid", "Rights", "Dispatcher")) num = 1 for handle_ptr in handles: _print_handle_summary(handle_ptr.dereference(), num) num += 1 if not num_handles: print(" <no handles>") finally: gdb.execute("set print address %s" % (save_print_address)) gdb.execute("set print symbol %s" % (save_print_symbol))
def call(args, **kw): cmd = [str(gdb.parameter('adb-path'))] dev = str(gdb.parameter('adb-device')) if dev: cmd.extend(['-s', dev]) cmd.extend(args) async = False if 'async' in kw: async = kw['async'] del kw['async'] if 'stdin' not in kw: kw['stdin'] = subprocess.PIPE if 'stdout' not in kw: kw['stdout'] = subprocess.PIPE try: adb = subprocess.Popen(cmd, **kw) if async: return adb out = adb.communicate()[0] returncode = adb.returncode except OSError as e: raise gdb.GdbError('cannot run adb: ' + str(e)) if adb.returncode != 0: raise gdb.GdbError('adb returned exit code ' + str(adb.returncode) + ' for arguments ' + str(args)) return out
def invoke(self, argument, from_tty): if self._loader: print 'Already running.' return libdir = feninit.default.libdir \ if hasattr(feninit.default, 'libdir') else None if not libdir: return force = True idfile = os.path.join(libdir, '.id') devid = adb.call(['shell', 'cat', '/proc/version', '/system/build.prop'])[0:2048].strip() try: with open(idfile, 'r') as libid: if libid.read(2048) == devid: force = False if argument == 'quick': return except IOError: pass self._loader = FastLoad.Loader() self._loader.solibs = gdb.execute('info sharedlibrary', False, True) self._loader.force = force self._loader.idfile = idfile self._loader.devid = devid gdb.events.cont.connect(self.cont_handler) gdb.events.stop.connect(self.stop_handler) gdb.events.exited.connect(self.exit_handler) # load modules self._loader.continuing = False self._loader.adbcmd = str(gdb.parameter('adb-path')) self._loader.adbdev = str(gdb.parameter('adb-device')) self._loader.start()
def call(args, **kw): cmd = [str(gdb.parameter('adb-path'))] dev = str(gdb.parameter('adb-device')) if dev: cmd.extend(['-s', dev]) cmd.extend(args) async = False if 'async' in kw: async = kw['async'] del kw['async'] if 'stdin' not in kw: kw['stdin'] = subprocess.PIPE if 'stdout' not in kw: kw['stdout'] = subprocess.PIPE if 'stderr' not in kw: kw['stderr'] = subprocess.STDOUT try: adb = subprocess.Popen(cmd, **kw) if async: return adb out = adb.communicate()[0] returncode = adb.returncode except OSError as e: raise gdb.GdbError('cannot run adb: ' + str(e)) if adb.returncode != 0: raise gdb.GdbError('adb returned exit code ' + str(adb.returncode) + ' for arguments ' + str(args)) return out
def gdb_parse_and_eval(exp): """Evaluate an expression and return the gdb.Value or None which correspond to the result of the evaluation.""" # Work around non-existing gdb.parse_and_eval as in released 7.0 overwrite = gdb.parameter("logging overwrite") redirect = gdb.parameter("logging redirect") file = gdb.parameter("logging file") # Unfortunately there is no mean to check if the logging is enabled or # not. TODO: So we look for the modification date of the logging file # to check if it is enabled. logging = False def restore(): gdb.execute("set logging off") gdb.execute("set logging redirect off") gdb.execute("set logging overwrite off") gdb.execute("set logging file " + file) gdb.execute("set logging redirect " + ("on" if redirect else "off")) gdb.execute("set logging logging " + ("on" if logging else "off")) # re-enable it after the start of the logging. gdb.execute("set logging overwrite " + ("on" if overwrite else "off")) gdb.execute("set logging off") gdb.execute("set logging file .gdb.python.tmp") gdb.execute("set logging overwrite on") gdb.execute("set logging redirect on") gdb.execute("set logging on") try: gdb.execute("print %s" % exp) except: restore() return None restore() return gdb.history(0)
def filter(self, frame_iter): # first check for multi-regex option squash_regexes = gdb.parameter('backtrace-strip-regexes') # If present we compress stack frames with matching capture groups if squash_regexes: prog = re.compile(squash_regexes) # if there are no (or one) capture groups, treat this like squash_regex if prog.groups < 2: squash_regex = squash_regexes else: # wrap the current iterator in a squash-matching-subsequences iterator # with the predicate "function name matches same regex" ufi = UserFilter.__adjacent_squash( frame_iter, lambda a, b: UserFilter.__same_cgroup(prog, a, b)) # further wrap in a decorator and return return imap(CommonAliasDecorator, ufi) else: # single regex is simpler - we compress based on match/nomatch squash_regex = gdb.parameter('backtrace-strip-regex') if squash_regex: ufi = UserFilter.__cond_squash( frame_iter, lambda x: ((x.function() != x.address()) and re.match( squash_regex, x.function()))) return imap(CommonAliasDecorator, ufi) else: # just add the decorator to the original iterator return imap(CommonAliasDecorator, frame_iter)
def trace (self): self.type = 'list' self.curr = None self.main = gdb.eval('rb_main_thread') self.height = gdb.parameter('height') or 26 self.unwind = gdb.parameter('unwindonsignal') gdb.execute('set height 0') gdb.execute('set unwindonsignal on') gdb.execute('watch rb_curr_thread') gdb.breakpoints()[-1].silent = True num = gdb.breakpoints()[-1].number try: prev = None while True: gdb.execute('continue') curr = gdb.eval('rb_curr_thread') if curr == prev: break self.print_thread(curr) prev = curr except KeyboardInterrupt: None gdb.execute('delete %d' % num) gdb.execute('set unwindonsignal %s' % ('on' if self.unwind else 'off')) gdb.execute('set height %d' % self.height)
def is_in_safe_path(pdir): if (not honor_sp.value): return True pdir = os.path.normpath(pdir) + "/" sp = gdb.parameter("auto-load safe-path") debugdir = gdb.parameter("debug-file-directory") datadir = gdb.execute("show data-directory", False, True) datadir = datadir.split('"')[1] global vdb_dir vdir = os.path.normpath(vdb_dir) sp = sp.replace("$datadir", datadir) sp = sp.replace("$debugdir", debugdir) sp = sp.split(":") sp.append(vdir) for p in sp: p = os.path.normpath(p) + "/" if (pdir.startswith(p)): return True return False
def invoke(self, arg, from_tty): argv = gdb.string_to_argv(arg) if len(argv) != 2: raise gdb.GdbError('hex-dump takes exactly 2 arguments.') addr = gdb.parse_and_eval(argv[0]).cast( gdb.lookup_type('void').pointer()) try: bytes = int(gdb.parse_and_eval(argv[1])) except ValueError: raise gdb.GdbError('Byte count numst be an integer value.') inferior = gdb.selected_inferior() align = gdb.parameter('hex-dump-align') width = gdb.parameter('hex-dump-width') if width == 0: width = 16 mem = inferior.read_memory(addr, bytes) pr_addr = int(str(addr), 16) pr_offset = width if align: pr_offset = width - (pr_addr % width) pr_addr -= pr_addr % width for group in groups_of(mem, width, pr_offset): print '0x%x: ' % (pr_addr,) + ' '*(width - pr_offset), print ' '.join(['%02X' % (ord(g),) for g in group]) + \ ' ' * (width - len(group) if pr_offset == width else 0) + ' ', print ' '*(width - pr_offset) + ''.join( [g if isgraph(g) or g == ' ' else '.' for g in group]) pr_addr += width pr_offset = width
def invoke(self, arg, from_tty): processes = _get_process_list() # Translating gdb values to python often trips over these. Heads up. save_print_address = "yes" if gdb.parameter("print address") else "no" save_print_symbol = "yes" if gdb.parameter("print symbol") else "no" gdb.execute("set print address on") gdb.execute("set print symbol off") # Make sure we restore these when we're done. try: for p in processes: handles = _get_handle_list(p) num_handles = len(handles) print("Process %u" % (p["id_"])) print(" %3s %-18s %4s %8s %s" % ("Num", "Handle*", "Pid", "Rights", "Dispatcher")) num = 1 for handle_ptr in handles: _print_handle_summary(handle_ptr.dereference(), num) num += 1 if not num_handles: print(" <no handles>") finally: gdb.execute("set print address %s" % (save_print_address)) gdb.execute("set print symbol %s" % (save_print_symbol))
def __init__(self): width = gdb.parameter('width') height = gdb.parameter('height') sys_terminal = SysTerminal() depth = sys_terminal.depth() if not width: width = sys_terminal.width() if not height: height = sys_terminal.height() super(GdbTerminal, self).__init__(width, height, depth)
def cont_handler(event): if not isinstance(event, gdb.ContinueEvent): return if not bool(gdb.parameter('adb-log-redirect')): exit_handler(event) return global adblog, log_width, log_colorfn if not adblog: adb.chooseDevice() adblog = ADBLog() adblog.start() log_width = int(gdb.parameter('width')) log_colorfn = _getColorFn(str(gdb.parameter('adb-log-color'))) adblog.running = True
def invoke(self, arg, from_tty): argv = gdb.string_to_argv(arg) addr = gdb.parse_and_eval(argv[0]).cast( gdb.lookup_type('void').pointer()) if len(argv) == 2: try: bytes = int(gdb.parse_and_eval(argv[1])) except ValueError: raise gdb.GdbError('Byte count numst be an integer value.') else: bytes = 512 inferior = gdb.selected_inferior() align = gdb.parameter('hex-dump-align') width = gdb.parameter('hex-dump-width') if width == 0: width = 16 mem = inferior.read_memory(addr, bytes) pr_addr = int(str(addr), 16) pr_offset = width if align: pr_offset = width - (pr_addr % width) pr_addr -= pr_addr % width start = (pr_addr) & 0xff print(' ', end="") print(' '.join( ['%01X' % (i & 0x0f, ) for i in range(start, start + width)]), end="") print(' ', end="") print(''.join( ['%01X' % (i & 0x0f, ) for i in range(start, start + width)])) for group in groups_of(mem, width, pr_offset): print('0x%x: ' % (pr_addr, ) + ' ' * (width - pr_offset), end="") print (' '.join(['%02X' % (ord(g),) for g in group]) + \ ' ' * (width - len(group) if pr_offset == width else 0) + ' ', end="") print(' ' * (width - pr_offset) + ''.join([ chr(int.from_bytes(g, byteorder='big')) if isgraph( int.from_bytes(g, byteorder='big')) or g == ' ' else '.' for g in group ])) pr_addr += width pr_offset = width
def invoke (self, arg, from_tty): f = '' l = 1 if arg == '': line_info = gdb.execute('info line', False, True) match = self.regex.search(line_info) if match is None: raise gdb.GdbError ('No file to open') f = match.group(2) l = match.group(1) else: f = arg try: server = gdb.parameter('vi-server') except gdb.error: server = 'gdb' cmd = ['gvim'] gviminit_file = os.path.join(os.getcwd(), 'gviminit.vim') if os.path.exists(gviminit_file): cmd.append('-S %s' % (gviminit_file)) cmd.append('--servername %s' % (server)) cmd.append('--remote-tab-silent +%s "%s"' % (l, f)) cmd.append('2>/dev/null') os.system(' '.join(cmd))
def add_tracer(symbol, arch): '''Trace the function defined by symbol. `symbol` should have a `value()` method, a `symtab.filename` member (i.e. a symtab member that itself has a filename member), and a `name` member. ''' addr = int(as_uintptr(symbol.value())) # Use hex just because it's pretty for `info call-graph exact`. entry_loc, *names = ('*{}'.format(hex(addr)), symbol.name, symbol.symtab.filename) # Avoid duplicate symbols by checking if the address already has a # breakpoint -- very often happens in non-debug symbols where the same # function has many names (e.g. __GI___libc_longjmp, __libc_longjmp, # __libc_siglongjmp, _longjmp, longjmp, siglongjmp) all have the same # address. # This also means that if the given regexp matches functions already # traced, we don't end up with duplicate tracers. should_enable = gdb.parameter('call-graph-enabled') if addr not in CallGraph.entry_breaks: new_bp = EntryBreak(entry_loc, *names) new_bp.enabled = should_enable CallGraph.entry_breaks[addr] = new_bp if addr not in CallGraph.ret_breaks: new_bps = [ ReturnBreak(retloc, retdesc, *names) for retloc, retdesc in fn_return_addresses(addr, arch)] for bp in new_bps: bp.enabled = should_enable CallGraph.ret_breaks[addr] = new_bps
def _get_thread_list(): """ Return a list of all thread_t threads. The result is constrained by "magenta max-info-threads". """ threads = [] head = gdb.parse_and_eval("&thread_list") t = head["next"] count = 0 max_threads = gdb.parameter("%s max-info-threads" % (_MAGENTA_COMMAND_PREFIX)) int_type = gdb.lookup_type("int") ptr_size = int_type.pointer().sizeof # Note: A "corrupted" list can happen for a short time while an # element is being added/removed. And, in non-stop mode, the list can # change while we're at it. This isn't a problem in all-stop mode, but # non-stop mode is generally preferable. We'll see how this works in # practice. while t and t != head: if max_threads is not None and count >= max_threads: break # Catch misaligned pointers. # Casting to int shouldn't be necessary, but the python API doesn't # support creating an int from a pointer. # We assume the object is aligned at least as great as a pointer. if (t.cast(int_type) & (ptr_size - 1)) != 0: break # TODO(dje): Do a range check? thread_ptr = containerof(t, "thread", "thread_list_node") if thread_ptr["magic"] != _THREAD_MAGIC: break # TODO(dje): Move this to a routine, more list printers will want this. threads.append(thread_ptr) t = t["next"] count += 1 return threads
def sysroot(): cmd = 'set sysroot remote:/' if is_android(): if gdb.parameter('sysroot') == 'target:': gdb.execute(cmd) else: print(pwndbg.color.bold("sysroot is already set, skipping %r" % cmd))
def report_backedge(g, e, pred): print('Pointer loop detected:') print_backtrace = gdb.parameter('ppl-backtrace') # e is the final edge that completes the loop # we want to display the previous edges, in order, followed by e # the predecessor map gives them to us in reverse path = [int(e.target()), int(e.source())] # reversed path by vertex index v = int(e.source()) while v is not int(e.target()): v = pred[v] path.append(v) # now print "path" by edge, reversed, followed by the final edge # zip (reversed) path with itself, offset, to get pairs of vertices # see "pairwise" recipe in itertools docs sources = iter(path) targets = iter(path) next(targets, None) # shift targets by one so edges line up for u, v in zip(sources, targets): print('block %s has pointers to block %s' % (g.vaddr_pmap[u], g.vaddr_pmap[v])) if print_backtrace: print(g.backtraces[u]) # terminate loop search raise StopSearch()
def sysroot(): cmd = "set sysroot remote:/" if is_android(): if gdb.parameter("sysroot") == "target:": gdb.execute(cmd) else: print(message.notice("sysroot is already set, skipping %r" % cmd))
def sysroot(): cmd = 'set sysroot remote:/' if is_android(): if gdb.parameter('sysroot') == 'target:': gdb.execute(cmd) else: print(message.notice("sysroot is already set, skipping %r" % cmd))
def _get_handle_list(process): """Return list of all handles of process. The result is constrained by "magenta max-info-handles". """ handles = [] head = process["handles_"] head = head["head_"] h = head count = 0 max_handles = gdb.parameter("%s max-info-handles" % (_MAGENTA_COMMAND_PREFIX)) int_type = gdb.lookup_type("int") ptr_size = int_type.pointer().sizeof # Note: A "corrupted" list can happen for a short time while an # element is being added/removed. And, in non-stop mode, the list can # change while we're at it. This isn't a problem in all-stop mode, but # non-stop mode is generally preferable. We'll see how this works in # practice. while h: if max_handles is not None and count >= max_handles: break # Catch misaligned pointers. # Casting to int shouldn't be necessary, but the python API doesn't # support creating an int from a pointer. # We assume the object is aligned at least as great as a pointer. if (h.cast(int_type) & (ptr_size - 1)) != 0: break # TODO(dje): Do a range check? # TODO(dje): Move this to a routine, more list printers will want this. handles.append(h) h = h["next_"] count += 1 if h == head: break return handles
def register_xmethod_matcher(locus, matcher, replace=False): """Registers a xmethod matcher MATCHER with a LOCUS. Arguments: locus: The locus in which the xmethods should be registered. It can be 'None' to indicate that the xmethods should be registered globally. Or, it could be a gdb.Objfile or a gdb.Progspace object in which the xmethods should be registered. matcher: The xmethod matcher to register with the LOCUS. It should be an instance of 'XMethodMatcher' class. replace: If True, replace any existing xmethod matcher with the same name in the locus. Otherwise, if a matcher with the same name exists in the locus, raise an exception. """ err = _validate_xmethod_matcher(matcher) if err: raise err if not locus: locus = gdb if locus == gdb: locus_name = "global" else: locus_name = locus.filename index = _lookup_xmethod_matcher(locus, matcher.name) if index >= 0: if replace: del locus.xmethods[index] else: raise RuntimeError("Xmethod matcher already registered with " "%s: %s" % (locus_name, matcher.name)) if gdb.parameter("verbose"): gdb.write("Registering xmethod matcher '%s' with %s' ...\n") locus.xmethods.insert(0, matcher)
def trace_regexp(regexp): 'Trace all functions matching `regexp` in the current symbol table.' file_regex, func_regex = file_func_split(regexp) if file_regex is None: file_regex = '.*' if gdb.parameter('call-graph-nondebug') else '.+' arch = gdb.current_arch() # We have to break on address to distinguish symbols with the same name in # different files. # # In order to have nice output, we create a string that describes the # function for a human -- though symbols with the same name will have the # same output for entry tracepoints. for symbol in gdb.search_symbols(func_regex, file_regex, gdb.parameter('call-graph-dynlibs')): add_tracer(symbol, arch)
def invoke(self, argument, from_tty): try: saved_height = gdb.parameter('height') saved_height = int(saved_height) if saved_height else 0 gdb.execute('set height 0') # suppress pagination if hasattr(self, 'gdbserver') and self.gdbserver: if self.gdbserver.poll() is None: print 'Already in remote debug mode.' return delattr(self, 'gdbserver') self._chooseDevice() self._chooseObjdir() self._pullLibsAndSetPaths() self._launchAndAttach() self.dont_repeat() except: # if there is an error, a gdbserver might be left hanging if hasattr(self, 'gdbserver') and self.gdbserver: if self.gdbserver.poll() is None: self.gdbserver.terminate() print 'Terminated gdbserver.' delattr(self, 'gdbserver') raise finally: gdb.execute('set height ' + str(saved_height), False, False)
def invoke(self, arg, from_tty): for name in sorted(self.REGISTRY): print( "{name}: {value}".format( name=name, value=gdb.parameter("fiber " + name) ) )
def invoke (self, arg, from_tty): f = '' l = 1 if arg == '': line_info = gdb.execute('info line', False, True) match = self.regex.search(line_info) if match is None: raise gdb.GdbError ('No file to open') f = match.group(2) l = match.group(1) else: f = arg try: server = gdb.parameter('emacs-server') except gdb.error: server = 'gdb' cmd = [whichPerl()] current_script_path = os.path.realpath(__file__) d = os.path.dirname(current_script_path) while (os.path.basename(d) != 'scripts'): d = os.path.dirname(d) cmd.append(os.path.join(d, 'perl-scripts', 'emacs.pl')) cmd.append('-s %s' % (server)) cmd.append('-f %s' % (f)) cmd.append('-l %s' %(l)) os.system(' '.join(cmd))
def trace(self): self.type = 'list' self.curr = None self.main = gdb.parse_and_eval('rb_main_thread') self.unwind = gdb.parameter('unwindonsignal') gdb.execute('set unwindonsignal on') gdb.execute('watch rb_curr_thread') gdb.breakpoints()[-1].silent = True num = gdb.breakpoints()[-1].number try: prev = None while True: gdb.execute('continue') curr = gdb.parse_and_eval('rb_curr_thread') if curr == prev: break self.print_thread(curr) prev = curr except KeyboardInterrupt: None gdb.execute('delete %d' % num) gdb.execute('set unwindonsignal %s' % (self.unwind and 'on' or 'off'))
def _get_handle_list(process): """Return list of all handles of process. The result is constrained by "zircon max-info-handles". """ handles = [] head = process["handles_"] head = head["head_"] h = head count = 0 max_handles = gdb.parameter("%s max-info-handles" % (_ZIRCON_COMMAND_PREFIX)) int_type = gdb.lookup_type("int") ptr_size = int_type.pointer().sizeof # Note: A "corrupted" list can happen for a short time while an # element is being added/removed. And, in non-stop mode, the list can # change while we're at it. This isn't a problem in all-stop mode, but # non-stop mode is generally preferable. We'll see how this works in # practice. while h: if max_handles is not None and count >= max_handles: break # Catch misaligned pointers. # Casting to int shouldn't be necessary, but the python API doesn't # support creating an int from a pointer. # We assume the object is aligned at least as great as a pointer. if (h.cast(int_type) & (ptr_size - 1)) != 0: break # TODO(dje): Do a range check? # TODO(dje): Move this to a routine, more list printers will want this. handles.append(h) h = h["next_"] count += 1 if h == head: break return handles
def save_user_state(self): self.pagination = gdb.parameter("pagination") if self.pagination: gdb.execute("set pagination off") self.user_selected_thread = gdb.selected_thread() self.user_selected_frame = gdb.selected_frame()
def _get_thread_list(): """ Return a list of all thread_t threads. The result is constrained by "zircon max-info-threads". """ threads = [] head = gdb.parse_and_eval("&thread_list") t = head["next"] count = 0 max_threads = gdb.parameter("%s max-info-threads" % (_ZIRCON_COMMAND_PREFIX)) int_type = gdb.lookup_type("int") ptr_size = int_type.pointer().sizeof # Note: A "corrupted" list can happen for a short time while an # element is being added/removed. And, in non-stop mode, the list can # change while we're at it. This isn't a problem in all-stop mode, but # non-stop mode is generally preferable. We'll see how this works in # practice. while t and t != head: if max_threads is not None and count >= max_threads: break # Catch misaligned pointers. # Casting to int shouldn't be necessary, but the python API doesn't # support creating an int from a pointer. # We assume the object is aligned at least as great as a pointer. if (t.cast(int_type) & (ptr_size - 1)) != 0: break # TODO(dje): Do a range check? thread_ptr = containerof(t, "thread", "thread_list_node") if thread_ptr["magic"] != _THREAD_MAGIC: break # TODO(dje): Move this to a routine, more list printers will want this. threads.append(thread_ptr) t = t["next"] count += 1 return threads
def gtkwave_tcl(cmd): p = gtkwave_socket_param(gdb.parameter("gtkwave-socket")) if p is None: raise gdb.GdbError('gtkwave-socket parameter is unset') s = socket.socket() s.connect(p) s.send((cmd + "\n").encode("ascii")) s.close()
def cont_handler(event): if not isinstance(event, gdb.ContinueEvent): return global continuing continuing = True if not bool(gdb.parameter('adb-log-redirect')): exit_handler(event) continuing = True return global adblog, log_width, log_colorfn if not adblog: adb.chooseDevice() adblog = ADBLog() adblog.start() log_width = int(gdb.parameter('width')) log_colorfn = _getColorFn(str(gdb.parameter('adb-log-color'))) adblog.running = True
def wrapped(*args, **kwds): orig = gdb.parameter("language") if lang == orig: return fn(*args, **kwds) try: gdb.execute("set language " + lang) return fn(*args, **kwds) finally: gdb.execute("set language " + orig)
def invoke(self, argument, from_tty): if self._loader: return libdir = feninit.default.libdir \ if hasattr(feninit.default, 'libdir') else None if not libdir or (argument == 'quick' and os.path.exists( os.path.join(libdir, 'system', 'lib', 'libdvm.so'))): return self._loader = FastLoad.Loader() self._loader.solibs = gdb.execute('info sharedlibrary', False, True) gdb.events.cont.connect(self.cont_handler) gdb.events.stop.connect(self.stop_handler) gdb.events.exited.connect(self.exit_handler) # load modules self._loader.continuing = False self._loader.adbcmd = str(gdb.parameter('adb-path')) self._loader.adbdev = str(gdb.parameter('adb-device')) self._loader.start()
def _NewObjfileHandler(event): """Handle new objfiles being loaded.""" # TODO(dje): Use this hook to automagically fetch debug info. verbosity = gdb.parameter( "%s verbosity" % (_FUCHSIA_COMMAND_PREFIX)) if verbosity >= 3: print "Hi, I'm the new_objfile event handler." objfile = event.new_objfile progspace = objfile.progspace # Assume the first objfile we see is the main executable. # There's nothing else we can do at this point. seen_exec = hasattr(progspace, "seen_exec") and progspace.seen_exec # Early exit if nothing to do. # We don't handle multiple arches so we KISS. if seen_exec: if verbosity >= 3: print "Already seen exec, ignoring: %s" % (basename) return progspace.seen_exec = True filename = objfile.username basename = os.path.basename(filename) if objfile.owner is not None: if verbosity >= 3: print "Separate debug file, ignoring: %s" % (basename) return # If we're debugging a native executable, unset the solib search path. if not _IsFuchsiaFile(objfile): if verbosity >= 3: print "Debugging non-Fuchsia file: %s" % (basename) print "Note: Unsetting solib-search-path." gdb.execute("set solib-search-path") return # The sysroot to use is dependent on the architecture of the program. # TODO(dje): IWBN if objfiles exposed their arch field. arch_string = gdb.execute("show arch", to_string=True) if arch_string.find("aarch64") >= 0: sysroot_dir = "out/sysroot/aarch64-fuchsia" elif arch_string.find("x86-64") >= 0: sysroot_dir = "out/sysroot/x86_64-fuchsia" else: print "WARNING: unsupported architecture\n%s" % (arch_string) return # TODO(dje): We can't use sysroot to find ld.so.1 because it doesn't # have a path on Fuchsia. Plus files in Fuchsia are intended to be # "ephemeral" by nature. So we punt on setting sysroot for now, even # though IWBN if we could use it. solib_search_path = "%s/debug-info" % (sysroot_dir) print "Note: Setting solib-search-path to %s" % (solib_search_path) gdb.execute("set solib-search-path %s" % (solib_search_path))
def to_string(self): if self.value['px']: print_object = gdb.parameter('print object') value = self.value['px'].dereference() if print_object: dynamic_type = self.value['px'].dynamic_type value = self.value['px'].cast(dynamic_type).dereference() return "%s %s" % (self.typename, value) else: return "empty %s" % (self.typename)
def invoke(self, arg, from_tty): # Do this first to make sure the previous value gets cleared out. # There's no way to unset a convenience var, so KISS. gdb.execute("set $zx_threads = (Thread*[1]) { 0 }") tls_entry_lkuser = gdb.parse_and_eval("TLS_ENTRY_LKUSER") threads = _get_thread_list() num_threads = len(threads) # The array is origin-1-indexed. Have a null first entry to KISS. gdb.execute("set $zx_threads = (Thread*[%d]) { 0 }" % (num_threads + 1)) # Populate the array first, before printing the summary, to make sure this # gets done even if there's an error during printing. num = 1 for thread_ptr in threads: gdb.execute("set $zx_threads[%d] = (Thread*) %u" % (num, thread_ptr)) num += 1 # Translating gdb values to python often trips over these. Heads up. save_print_address = "yes" if gdb.parameter("print address") else "no" save_print_symbol = "yes" if gdb.parameter("print symbol") else "no" gdb.execute("set print address off") gdb.execute("set print symbol off") print("%3s %5s %-18s %-32s %s" % ("Num", "Pid", "Thread*", "Name", "State")) # Make sure we restore these when we're done. try: user_thread_ptr_t = gdb.lookup_type("UserThread").pointer() num = 1 for thread_ptr in threads: # TODO(dje): remove dereference _print_thread_summary(thread_ptr.dereference(), num, tls_entry_lkuser, user_thread_ptr_t) num += 1 finally: gdb.execute("set print address %s" % (save_print_address)) gdb.execute("set print symbol %s" % (save_print_symbol)) if num_threads: print("Note: Each thread is now available in $zx_threads[num].") else: print("<no threads>")
def register_unwinder(locus, unwinder, replace=False): """Register unwinder in given locus. The unwinder is prepended to the locus's unwinders list. Unwinder name should be unique. Arguments: locus: Either an objfile, progspace, or None (in which case the unwinder is registered globally). unwinder: An object of a gdb.Unwinder subclass replace: If True, replaces existing unwinder with the same name. Otherwise, raises exception if unwinder with the same name already exists. Returns: Nothing. Raises: RuntimeError: Unwinder name is not unique TypeError: Bad locus type """ if locus is None: if gdb.parameter("verbose"): gdb.write("Registering global %s unwinder ...\n" % unwinder.name) locus = gdb elif isinstance(locus, gdb.Objfile) or isinstance(locus, gdb.Progspace): if gdb.parameter("verbose"): gdb.write("Registering %s unwinder for %s ...\n" % (unwinder.name, locus.filename)) else: raise TypeError("locus should be gdb.Objfile or gdb.Progspace or None") i = 0 for needle in locus.frame_unwinders: if needle.name == unwinder.name: if replace: del locus.frame_unwinders[i] else: raise RuntimeError("Unwinder %s already exists." % unwinder.name) i += 1 locus.frame_unwinders.insert(0, unwinder) gdb.invalidate_cached_frames()
def invoke(self, arg, from_tty): argv = gdb.string_to_argv(arg) addr = gdb.parse_and_eval(argv[0]).cast( gdb.lookup_type('void').pointer()) if len(argv) == 2: try: bytes = int(gdb.parse_and_eval(argv[1])) except ValueError: raise gdb.GdbError('Byte count numst be an integer value.') else: bytes = 256 inferior = gdb.selected_inferior() align = gdb.parameter('hex-dump-align') width = gdb.parameter('hex-dump-width') if width == 0: width = 16 mem = inferior.read_memory(addr, bytes) pr_addr = int(str(addr).split()[0], 16) pr_offset = width if align: pr_offset = width - (pr_addr % width) pr_addr -= pr_addr % width start=(pr_addr) & 0xff; print (' ' , end="") print (' '.join(['%01X' % (i&0x0f,) for i in range(start,start+width)]) , end="") print (' ' , end="") print (''.join(['%01X' % (i&0x0f,) for i in range(start,start+width)]) ) for group in groups_of(mem, width, pr_offset): print ('0x%x: ' % (pr_addr,) + ' '*(width - pr_offset), end="") print (' '.join(['%02X' % (ord(g),) for g in group]) + \ ' ' * (width - len(group) if pr_offset == width else 0) + ' ', end="") print (' '*(width - pr_offset) + ''.join( [chr( int.from_bytes(g, byteorder='big')) if isgraph( int.from_bytes(g, byteorder='big') ) or g == ' ' else '.' for g in group])) pr_addr += width pr_offset = width
def setup (self): commands = """ set $func = malloc(1) p ((char*)$func)[0] = '\xc3' p mprotect(($func&0xfffffffffffff000), 1, 0x7) p rb_add_event_hook($func, RUBY_EVENT_C_CALL|RUBY_EVENT_CALL) b *$func """.split("\n") for c in commands: gdb.execute(c) gdb.breakpoints()[-1].silent = True self.func = gdb.eval('$func') self.height = gdb.parameter('height') or 26 self.unwind = gdb.parameter('unwindonsignal') gdb.execute('set height 0') gdb.execute('set unwindonsignal on')
def limit_with_dots(fibers_iterator): num_items = 0 fiber_print_limit = gdb.parameter("fiber manager-print-limit") for fiber in fibers_iterator: if fiber_print_limit and num_items >= fiber_print_limit: yield ("address", "...") yield ("fiber", "...") return yield ("address", str(fiber.address)) yield ("fiber", fiber) num_items += 1
def to_string(self): # Look up the target encoding as late as possible. encoding = self.encoding result = [] begin = self.val['_M_dataplus']['_M_p'] length = self.get_length() limit = gdb.parameter('print elements') if limit != None: nchars = min(length, limit) else: nchars = length if encoding == 0: encoding = gdb.parameter('target-charset') try: return begin.string(encoding, length=length) except: return begin elif encoding == 1: encoding = gdb.parameter('target-wide-charset') # GRTE python does not understand UCS-4 # Hack courtesy jyasskin. if encoding == 'UCS-4': for i in range(nchars): # Don't crash on bad characters. try: result.append(unichr(begin[i])) except: result.append("\\x%x/" % begin[i]) if nchars < length: result.append('...') return ''.join(result) # End GRTE hack. # FIXME: WideEncoding didn't get brought over from archer. #elif isinstance(encoding, WideEncoding): # encoding = encoding.value return self.val['_M_dataplus']['_M_p'].string(encoding)
def to_string(self): # Look up the target encoding as late as possible. encoding = self.encoding result = [] begin = self.val['_M_dataplus']['_M_p'] length = self.get_length() limit = gdb.parameter('print elements') if limit != None: nchars = min(length, limit) else: nchars = length if encoding == 0: encoding = gdb.parameter('target-charset') try: return begin.string(encoding, length = length) except: return begin elif encoding == 1: encoding = gdb.parameter('target-wide-charset') # GRTE python does not understand UCS-4 # Hack courtesy jyasskin. if encoding == 'UCS-4': for i in range(nchars): # Don't crash on bad characters. try: result.append(unichr(begin[i])) except: result.append("\\x%x/" % begin[i]) if nchars < length: result.append('...') return ''.join(result) # End GRTE hack. # FIXME: WideEncoding didn't get brought over from archer. #elif isinstance(encoding, WideEncoding): # encoding = encoding.value return self.val['_M_dataplus']['_M_p'].string(encoding)
def invoke(self, arg, from_tty): # Do this first to make sure the previous value gets cleared out. # There's no way to unset a convenience var, so KISS. gdb.execute("set $zx_threads = (thread_t*[1]) { 0 }") tls_entry_lkuser = gdb.parse_and_eval("TLS_ENTRY_LKUSER") threads = _get_thread_list() num_threads = len(threads) # The array is origin-1-indexed. Have a null first entry to KISS. gdb.execute("set $zx_threads = (thread_t*[%d]) { 0 }" % (num_threads + 1)) # Populate the array first, before printing the summary, to make sure this # gets done even if there's an error during printing. num = 1 for thread_ptr in threads: gdb.execute("set $zx_threads[%d] = (thread_t*) %u" % (num, thread_ptr)) num += 1 # Translating gdb values to python often trips over these. Heads up. save_print_address = "yes" if gdb.parameter("print address") else "no" save_print_symbol = "yes" if gdb.parameter("print symbol") else "no" gdb.execute("set print address off") gdb.execute("set print symbol off") print("%3s %5s %-18s %-32s %s" % ( "Num", "Pid", "thread_t*", "Name", "State")) # Make sure we restore these when we're done. try: user_thread_ptr_t = gdb.lookup_type("UserThread").pointer() num = 1 for thread_ptr in threads: # TODO(dje): remove dereference _print_thread_summary(thread_ptr.dereference(), num, tls_entry_lkuser, user_thread_ptr_t) num += 1 finally: gdb.execute("set print address %s" % (save_print_address)) gdb.execute("set print symbol %s" % (save_print_symbol)) if num_threads: print("Note: Each thread is now available in $zx_threads[num].") else: print("<no threads>")
def to_string(self): # Look up the target encoding as late as possible. encoding = self.encoding if encoding == 0: encoding = gdb.parameter('target-charset') elif encoding == 1: encoding = gdb.parameter('target-wide-charset') # Make sure &string works, too. type = self.val.type if type.code == gdb.TYPE_CODE_REF: type = type.target () # Calculate the length of the string so that to_string returns # the string according to length, not according to first null # encountered. ptr = self.val ['_M_dataplus']['_M_p'] realtype = type.unqualified ().strip_typedefs () reptype = gdb.lookup_type (str (realtype) + '::_Rep').pointer () header = ptr.cast(reptype) - 1 len = header.dereference ()['_M_length'] return self.val['_M_dataplus']['_M_p'].string (encoding, length = len)
def invoke(self, arg, from_tty): # Do this first to make sure the previous value gets cleared out. # There's no way to unset a convenience var, so KISS. gdb.execute("set $zx_processes = (ProcessDispatcher*[1]) { 0 }") tls_entry_lkuser = gdb.parse_and_eval("TLS_ENTRY_LKUSER") processes = _get_process_list() num_processes = len(processes) # The array is origin-1-indexed. Have a null first entry to KISS. gdb.execute("set $zx_processes = (ProcessDispatcher*[%d]) { 0 }" % (num_processes + 1)) # Populate the array first, before printing the summary, to make sure this # gets done even if there's an error during printing. num = 1 for process_ptr in processes: gdb.execute("set $zx_processes[%d] = (ProcessDispatcher*) %u" % (num, process_ptr)) num += 1 # Translating gdb values to python often trips over these. Heads up. save_print_address = "yes" if gdb.parameter("print address") else "no" save_print_symbol = "yes" if gdb.parameter("print symbol") else "no" gdb.execute("set print address off") gdb.execute("set print symbol off") print("%3s %-18s %4s %s" % ( "Num", "ProcessDispatcher*", "Pid", "State")) # Make sure we restore these when we're done. try: num = 1 for process_ptr in processes: _print_process_summary(process_ptr.dereference(), num) num += 1 finally: gdb.execute("set print address %s" % (save_print_address)) gdb.execute("set print symbol %s" % (save_print_symbol)) if num_processes: print("Note: Each process is now available in $zx_processes[num].") else: print("<no processes>")
def _add_google3_paths(google3_path, with_google3_import): # Start with a canonicalized path. google3_parent_path = os.path.abspath(os.path.dirname(google3_path)) # For consistency, reestablish google3 relative to that. google3_path = "%s/google3" % google3_parent_path readonly_path = None readonly_google3_path = None directories = gdb.parameter("directories") if directories.find("/google3/") < 0 \ and directories.find ("/google3:") < 0: # Update the source search paths. if os.path.exists("%s/READONLY/google3" % google3_parent_path): readonly_path = "%s/READONLY" % google3_parent_path readonly_google3_path = "%s/google3" % readonly_path gdb.execute("dir %s" % readonly_google3_path) gdb.execute("dir %s" % google3_path) if with_google3_import: # Google3 python files are looked up from a starting point of the parent # of google3. # Only add the google3 parent. The "import google3" we do later will # add the necessary support for finding things in READONLY. _append_sys_path(google3_parent_path) # Import google3/__init__.py. # It provides the necessary support to handle importing modules across a # split srcfs tree. E.g., google3/devtools/__init__.py and # READONLY/google3/devtools/gdb/component/__init__.py. # Without help, python can't find google3.devtools.gdb.component. # http://b/4088983 if os.path.exists("%s/__init__.py" % google3_path): import google3 else: # Alas, google3/__init__.py may not exist. It must be in # ../READONLY/google3/__init__.py. Oy vey! if os.path.exists("%s/__init__.py" % readonly_google3_path): # Python2 canonicalizes directories in sys.path, so we do too. abs_readonly_path = os.path.abspath(readonly_path) was_in_sys_path = abs_readonly_path in sys.path if not was_in_sys_path: _append_sys_path(abs_readonly_path) import google3 if not was_in_sys_path: sys.path.remove(abs_readonly_path) else: raise RuntimeError("Can't find google3/__init__.py") else: if readonly_google3_path is not None: _append_sys_path(readonly_google3_path) _append_sys_path(google3_path)
def invoke(self, arg, from_tty): b = gdb.parameter('boost-directory') if not b: return modules = arg.split() for m in modules: d = os.path.join(b, m) print d for root, dirs, files in os.walk(d): for f in files: fn = os.path.join(root, f) if os.path.exists(fn): print fn gdb.execute('skip file %s' % fn)
def invoke (self, arg, from_tty): self.height = gdb.parameter('height') or 26 gdb.execute('set height 0') if arg == 'classes': self.print_classes() elif arg == 'nodes': self.print_nodes() elif arg == 'strings': self.print_strings() else: self.print_stats() gdb.execute('set height %d' % self.height)
def chooseDevice(): # identify device devs = getDevices() # wait for a device if no device is found while not devs: try: print('ADB: waiting for device... (Ctrl+C to stop)') waitForDevice() except gdb.GdbError: raise gdb.GdbError(' ADB: no device') devs = getDevices() # use saved setting if possible; also allows gdbinit to set device dev = str(gdb.parameter('adb-device')) if dev and dev not in devs: print('feninit.default.device (%s) is not connected' % dev) # use only device if len(devs) == 1: dev = devs[0] # otherwise, let user decide while not dev in devs: print('Found multiple devices:') for i in range(len(devs)): print('%d. %s' % (i + 1, devs[i])) dev = readinput.call('Choose device: ', '-l', str(devs)) if dev.isdigit() and int(dev) > 0 and int(dev) <= len(devs): dev = devs[int(dev) - 1] elif len(dev) > 0: matchDev = filter( lambda x: x.lower().startswith(dev.lower()), devs) # if only one match, use it if len(matchDev) == 1: dev = matchDev[0] if str(gdb.parameter('adb-device')) != dev: gdb.execute('set adb-device ' + dev) return dev
def _pullLibsAndSetPaths(self): DEFAULT_FILE = 'system/bin/app_process' # libraries/binaries to pull from device DEFAULT_LIBS = ['system/lib/libdl.so', 'system/lib/libc.so', 'system/lib/libm.so', 'system/lib/libstdc++.so', 'system/lib/liblog.so', 'system/lib/libz.so', 'system/lib/libGLESv2.so', 'system/bin/linker'] # search path for above libraries/binaries DEFAULT_SEARCH_PATHS = ['system/lib', 'system/bin'] datadir = str(gdb.parameter('data-directory')) libdir = os.path.abspath( os.path.join(datadir, os.pardir, 'lib', self.device)) self.datadir = datadir self.libdir = libdir self.bindir = os.path.abspath( os.path.join(datadir, os.pardir, 'bin')) # always pull the executable file dstpath = os.path.join(libdir, DEFAULT_FILE.replace('/', os.sep)) if not os.path.exists(dstpath): adb.pull('/' + DEFAULT_FILE, dstpath) # only pull libs and set paths if automatically loading symbols if hasattr(self, 'skipPull') and not self.skipPull: sys.stdout.write('Pulling libraries to %s... ' % libdir) sys.stdout.flush() for lib in DEFAULT_LIBS: try: dstpath = os.path.join(libdir, lib.replace('/', os.sep)) if not os.path.exists(dstpath): adb.pull('/' + lib, dstpath) except gdb.GdbError: sys.stdout.write('\n cannot pull %s... ' % lib) sys.stdout.flush() print 'Done' gdb.execute('set sysroot ' + libdir, False, True) print 'Set sysroot to "%s".' % libdir searchPaths = [os.path.join(libdir, d) \ for d in DEFAULT_SEARCH_PATHS] if self.objdir: searchPaths.append(os.path.join(self.objdir, 'dist', 'bin')) searchPaths.append(os.path.join(self.objdir, 'dist', 'lib')) gdb.execute('set solib-search-path ' + os.pathsep.join(searchPaths), False, True) print 'Updated solib-search-path.'