def invoke(self, *args): self.process.set_inferior(gdb.selected_inferior(), gdb.selected_thread()) selected_thread = gdb.selected_thread() if selected_thread is None: raise Exception("You are calling the 'NotifySyscall' function with no thread running. This should never happen because only the catchpoint-syscall should call this function and by definition those require an running thread.") my_id = (gdb.selected_inferior().num, selected_thread.num) syscall_tracer = self._syscall_tracer_by_invokation_id.get(my_id) am_at_syscall_enter = syscall_tracer is None # if None no tracing was started so we must be at the enter of a syscall if am_at_syscall_enter: syscall_tracer = PtraceSyscallPublisher(self.gdb_module, self.process, Opts()) self._syscall_tracer_by_invokation_id[my_id] = syscall_tracer # save this tracer to be called at the syscall's exit syscall_tracer.enter() else: syscall_tracer = self._syscall_tracer_by_invokation_id[my_id] # created at the syscall's enter syscall_tracer.exit() del self._syscall_tracer_by_invokation_id[my_id] # clean up # publish the data from the syscall's enter/exit syscall_tracer.publish_syscall() return False
def is_running(): """Return True if the inferior is running.""" # This seems good enough for now. # We can deal with scheduler locking and the rest later. if gdb.selected_thread() and gdb.selected_thread().is_running(): return True return False
def gdb_stopped(): try: th = gdb.selected_thread() if th == None: return True return gdb.selected_thread().is_stopped() except: return True
def get_thread_names(): # thread_regex = re.compile("(\d+)\s+Thread\s+0x[0-9a-f]+\s+\(LWP (\d+)\)") thread_regex = re.compile("(\d+)\s+Thread\s\d+\.(\d+)\s0x[0-9a-f].*") # Capture the result of 'info threads' to a string thread_info = gdb.execute("info threads", False, True) # Store the currently-selected thread so that we can go back to it original_thread = gdb.selected_thread() if original_thread is not None: original_thread_num = original_thread.num else: original_thread_num = None for line in thread_info.split('\n'): line = line.strip() thread_match = thread_regex.search(line) if thread_match != None: thread_number = int(thread_match.group(1)) thread_tid = int(thread_match.group(2)) # Get a pointer to the current thread from GDB gdb.execute("thread %d" % (thread_number), False, True) current_thread = gdb.selected_thread() # Read this thread's stat file in /proc thread_stat_file = "/proc/%d/stat" % (thread_tid) if os.path.exists(thread_stat_file): with open(thread_stat_file, 'r') as fp: stat_file_contents = fp.read() # Extract the thread's name from the stat file (it should be in # parens, after the thread ID itself) stat_file_regex = re.compile("^%d \((.*?)\)" % (thread_tid)) stat_match = stat_file_regex.search(stat_file_contents) if stat_match is not None: # Set the thread's name to the string extracted from stat thread_name = stat_match.group(1) print "Got thread name '%s' for thread %d (%d)" % ( thread_name, thread_number, thread_tid) current_thread.name = thread_name else: print "No thread name match for thread %d (%d)" % ( thread_number, thread_tid) # Switch back to original thread (if any) if original_thread_num != None: gdb.execute("thread %d" % (original_thread_num), False, True)
def get_current_thread(inferior_repository, inferior_factory, thread_factory): if gdb.selected_thread() is not None: thread_num = gdb.selected_thread().num inferior = get_current_inferior(inferior_repository, inferior_factory) if not inferior.has_thread(thread_num): thread_factory.create_thread(inferior, thread_num) if inferior.has_thread(thread_num): return inferior.thread(thread_num) return None
def get_current_cpu(): if utils.get_gdbserver_type() == utils.GDBSERVER_QEMU: return gdb.selected_thread().num - 1 elif utils.get_gdbserver_type() == utils.GDBSERVER_KGDB: tid = gdb.selected_thread().ptid[2] if tid > (0x100000000 - MAX_CPUS - 2): return 0x100000000 - tid - 2 else: return tasks.get_thread_info(tasks.get_task_by_pid(tid))['cpu'] else: raise gdb.GdbError("Sorry, obtaining the current CPU is not yet " "supported with this gdb server.")
def switch_thread(self, current_thread_id=None, first_thread_id=None): if len(self.threads) == 0: TraceFunctionsI.printf("warning: no known threads, no thread switch performed.") return all_threads = sorted(self.threads.keys()) if current_thread_id is None: current_thread_id = gdb.selected_thread().global_num if first_thread_id is None: first_thread_id = current_thread_id try: next_thread_idx = all_threads.index(current_thread_id) + 1 if next_thread_idx >= len(all_threads): next_thread_idx = 0 except ValueError: next_thread_idx = 0 #TraceFunctionsI.printf("Attempting to switch to thread at idx %d of %s" % (next_thread_idx, all_threads)) next_thread_id = all_threads[next_thread_idx] if next_thread_id == first_thread_id: if len(all_threads) > 0: TraceFunctionsI.printf("error: failed to find any next thread to execute. Not performing context switch.") next_thread = self.threads[next_thread_id] if next_thread.is_exited() or not next_thread.is_valid(): TraceFunctionsI.printf("thread %s has become invalid or exited, removing from watch list." % (next_thread.ptid,)) del self.threads[next_thread_id] self.switch_thread(current_thread_id, first_thread_id) else: # TODO this doesn't work at all gdb.execute("set scheduler-locking off", to_string=True) TraceFunctionsI.printf("switching to thread %s" % (next_thread.ptid,)) next_thread.switch() #brk = gdb.FinishBreakpoint(gdb.newest_frame(), internal=True) #brk.thread = int(next_thread.global_num) gtid = gdb.selected_thread().global_num frame = gdb.newest_frame() sal = frame.find_sal() if sal.symtab: filename = sal.symtab.filename else: filename = None linenumber = sal.line function = frame.function() gdb.execute("finish", to_string=True) self.log("returned from", frame.pc(), function, filename, linenumber) gdb.execute("set scheduler-locking on", to_string=True) TraceFunctionsI.printf("switch to thread %s completed" % (next_thread.ptid,))
def thread_name(name, threadnum=None): """Set name to thread `threadnum`. If threadnum is not given, set name to current thread. For example: threadnum('foo', 2) will set thread 2's name to 'foo'.""" if threadnum is not None: threads = info_threads() for th in threads: if th[1] == threadnum: original_thread_num = gdb.selected_thread().num gdb.execute('thread %d' % th[1], to_string=True) current_thread = gdb.selected_thread() current_thread.name = name gdb.execute('thread %d' % original_thread_num, to_string=True) else: gdb.execute('thread name %s' % name)
def __init__(self, thread_ctx): self.thread_ctx = thread_ctx self.old_frame = gdb.selected_frame() self.old_regs = self.save_regs() self.old_gdb_thread = gdb.selected_thread() self.gdb_thread = get_thread_owning_memory(thread_ctx.address) self.new_regs = None
def reactor_threads(): orig = gdb.selected_thread() for t in gdb.selected_inferior().threads(): t.switch() if has_reactor(): yield t orig.switch()
def invoke (self, arg, from_tty): thread = gdb.selected_thread() if thread == None: print 'No thread selected.' return for thread in gdb.inferiors(): frame = gdb.newest_frame() while frame: # if that matches our regexp, select that. try: match = re.match(arg, frame.name(), flags=re.IGNORECASE) except Exception, e: print "Error: invalid regex: %s" % str(e) return if match: sal = frame.find_sal() print "Found: %s, thread %s, file %s:%s, in function %s" % (frame.name(), thread.num,sal.symtab.filename, sal.line, frame.function()) frame.select() return frame = frame.older() if not frame: return
def get_heap_address(self, mp=None): """Read heap address from glibc's mp_ structure if available, otherwise fall back to /proc/self/maps which is unreliable. """ start, end = None, None if mp is not None: from libheap.ptmalloc.malloc_par import malloc_par if isinstance(mp, malloc_par): start = mp.sbrk_base else: print_error("Please specify a valid malloc_par variable") # XXX: add end from arena(s).system_mem ? else: pid, task_id, thread_id = gdb.selected_thread().ptid maps_file = "/proc/%d/task/%d/maps" maps_data = open(maps_file % (pid, task_id)).readlines() for line in maps_data: if any(x.strip() == '[heap]' for x in line.split(' ')): heap_range = line.split(' ')[0] start, end = [int(h, 16) for h in heap_range.split('-')] break return start, end
def stop(self): caller = gdb.newest_frame().older() caller_name = caller.name() if caller else 'none' print('{};{};{}'.format(gdb.selected_thread().num, caller_name, gdb.newest_frame().name())) return False
def update(): """ For each running thread, updates the known address range for its stack. """ curr_thread = gdb.selected_thread() try: for thread in gdb.selected_inferior().threads(): thread.switch() sp = pwndbg.regs.sp # If we don't already know about this thread, create # a new Page mapping for it. page = stacks.get(thread.ptid, None) if page is None: start = pwndbg.memory.find_lower_boundary(sp) stop = find_upper_stack_boundary(sp) page = pwndbg.memory.Page(start, stop-start, 6 if not is_executable() else 7, 0, '[stack]') stacks[thread.ptid] = page continue elif page.objfile is None: page.objfile = '[stack]' # If we *DO* already know about this thread, just # update the lower boundary. low = pwndbg.memory.find_lower_boundary(page.vaddr) if low != page.vaddr: page.memsz += (page.vaddr - low) page.vaddr = low finally: curr_thread.switch()
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 _fs_gs_helper(self, regname, which): """Supports fetching based on segmented addressing, a la fs:[0x30]. Requires ptrace'ing the child directly for GDB < 8.""" # For GDB >= 8.x we can use get_register directly # Elsewhere we have to get the register via ptrace if get_register == gdb79_get_register: return get_register(regname) # We can't really do anything if the process is remote. if pwndbg.remote.is_remote(): return 0 # Use the lightweight process ID pid, lwpid, tid = gdb.selected_thread().ptid # Get the register ppvoid = ctypes.POINTER(ctypes.c_void_p) value = ppvoid(ctypes.c_void_p()) value.contents.value = 0 libc = ctypes.CDLL("libc.so.6") result = libc.ptrace(PTRACE_ARCH_PRCTL, lwpid, value, which) if result == 0: return (value.contents.value or 0) & pwndbg.arch.ptrmask return 0
def find_lock_manager_holders(graph, thread_dict, show): # pylint: disable=too-many-locals """Find lock manager holders.""" frame = find_frame(r'mongo::LockerImpl\<.*\>::') if not frame: return frame.select() (_, lock_waiter_lwpid, _) = gdb.selected_thread().ptid lock_waiter = thread_dict[lock_waiter_lwpid] locker_ptr_type = gdb.lookup_type("mongo::LockerImpl<false>").pointer() lock_head = gdb.parse_and_eval( "mongo::getGlobalLockManager()->_getBucket(resId)->findOrInsert(resId)") granted_list = lock_head.dereference()["grantedList"] lock_request_ptr = granted_list["_front"] while lock_request_ptr: lock_request = lock_request_ptr.dereference() locker_ptr = lock_request["locker"] locker_ptr = locker_ptr.cast(locker_ptr_type) locker = locker_ptr.dereference() lock_holder_id = int(locker["_threadId"]["_M_thread"]) if lock_holder_id == 0: locker_id = int(locker["_id"]) lock_holder = NonExecutingThread(locker_id) else: lock_holder = find_thread(thread_dict, lock_holder_id) if show: print("MongoDB Lock at {} ({}) held by {} waited on by {}".format( lock_head, lock_request["mode"], lock_holder, lock_waiter)) if graph: graph.add_edge(lock_waiter, Lock(long(lock_head), "MongoDB lock")) graph.add_edge(Lock(long(lock_head), "MongoDB lock"), lock_holder) lock_request_ptr = lock_request["next"]
def action(self, arg, from_tty): thread = gdb.selected_thread() # `global_num` was introduced in GDB 7.11 num = getattr(thread, 'global_num', None) or thread.num if thread else None inferior = gdbjsThreadGroup.action(arg, from_tty) return {"id": num or None, "group": inferior}
def valcache(self, value_or_path, **kwargs): '''return value from cache if exists else return argument value''' if type(value_or_path) in (str, unicode): path = value_or_path frnum = get_this_frame_num() th = gdb.selected_thread() if frnum == None or th == None: valcache1 = None else: key = (frnum, path, th.global_num) valcache1 = self.value_str_cache.get(key) if valcache1 == None: valcache1 = gdb.parse_and_eval(path) self.value_cache[key] = valcache1 self.add_valcache_byaddr(valcache1) else: value = value_or_path if value.is_optimized_out: #can't cache this value return value addr = valueaddress_to_ulong(value.address) if addr == None: return value key = (addr, str(value.type)) valcache1 = self.value_cache.get(key) if valcache1 == None: self.add_valcache_byaddr(value) valcache1 = value return valcache1
def _Inject(self, position, call): """Injects evaluation of 'call' in a safe location in the inferior. Due to the way these injected function calls work, gdb must not be killed until the call has returned. If that happens, the inferior will be sent SIGTRAP upon attempting to return from the dummy frame gdb constructs for us, and will most probably crash. Args: position: array of pid, tid, framedepth specifying the requested position. call: Any expression gdb can evaluate. Usually a function call. Raises: RuntimeError: if gdb is not being run in synchronous exec mode. """ self.EnsureGdbPosition(position[0], position[1], None) self.ClearBreakpoints() self._AddThreadSpecificBreakpoint(position) gdb.parse_and_eval('%s = 1' % GdbCache.PENDINGCALLS_TO_DO) gdb.parse_and_eval('%s = 1' % GdbCache.PENDINGBUSY) try: # We're "armed", risk the blocking call to Continue self.Continue(position) # Breakpoint was hit! if not gdb.selected_thread().is_stopped(): # This should not happen. Depending on how gdb is being used, the # semantics of self.Continue change, so I'd rather leave this check in # here, in case we ever *do* end up changing to async mode. raise RuntimeError( 'Gdb is not acting as expected, is it being run in ' 'async mode?') finally: gdb.parse_and_eval('%s = 0' % GdbCache.PENDINGBUSY) self.Call(position, call)
def invoke(self, basevar, cpu=None): if not (basevar.type.tag and basevar.type.tag.startswith('static_percpu<')): raise gdb.GdbError('Not a static_percpu') if cpu is None: cpu = gdb.selected_thread().num - 1 else: cpu = int(cpu) # Get the key. Unfortunately, G++ optimizes out the second # template argument, so we have to do this the dumb way. m = re.search(r'&([^ ,]+_key),', str(basevar.type)) if not m: raise gdb.GdbError('Failed to parse type string %r' % str(basevar.type)) key = gdb.lookup_global_symbol(m.group(1)) if key is None: raise gdb.GdbError('Failed to find per-cpu key %r' % m.group(1)) # Compute the offset start = gdb.lookup_global_symbol('__percpu_start') offset = int(key.value().address) - int(start.value().address) # Get CPU's base cpubase = gdb.lookup_global_symbol('percpu_offsets').value()[cpu] # Put together new pointer return (cpubase + offset).cast(key.type.pointer()).dereference()
def saveCurrentState(state): curr_thread = gdb.selected_thread() for thread in gdb.selected_inferior().threads(): if not thread.num in state: thread.switch() state[thread.num] = HermitTaskState() curr_thread.switch()
def _fs_gs_helper(self, which): """Supports fetching based on segmented addressing, a la fs:[0x30]. Requires ptrace'ing the child directly.""" # We can't really do anything if the process is remote. if pwndbg.remote.is_remote(): return 0 # Use the lightweight process ID pid, lwpid, tid = gdb.selected_thread().ptid # Get the register ppvoid = ctypes.POINTER(ctypes.c_void_p) value = ppvoid(ctypes.c_void_p()) value.contents.value = 0 libc = ctypes.CDLL('libc.so.6') result = libc.ptrace(PTRACE_ARCH_PRCTL, lwpid, value, which) if result == 0: return (value.contents.value or 0) & pwndbg.arch.ptrmask return 0
def invoke(self, arg, from_tty): if self.tunnel and not self.tunnel.is_up(): self.tunnel = None if not self.tunnel: if arg == "": arg = self.cfg.host self.tunnel = Tunnel(arg, self.cfg.port) if not self.tunnel.is_up(): rs_log("sync failed") return id = self.identity() self.tunnel.send( "[notice]{\"type\":\"new_dbg\",\"msg\":\"dbg connect - %s\",\"dialect\":\"gdb\"}\n" % id) rs_log("sync is now enabled with host %s" % str(arg)) # make sure there is an active thread before running the Poller if gdb.selected_thread(): self.create_poll_timer() else: print('(update)') if self.poller: self.poller.enable()
def update_symbols(self, current_thread_only): """Updates the mapping between symbols as seen from GDB and local library files. If current_thread_only is True, only update symbols for the current thread. """ logging.info("Updating symbols") mapped_files = _get_mapped_files() # Map all symbols from native libraries packages with the APK. for file_mappings in mapped_files: filename = file_mappings[0].filename if ((filename.startswith('/data/data/') or filename.startswith('/data/app')) and not filename.endswith('.apk') and not filename.endswith('.dex')): logging.info('Pre-mapping: %s' % file_mappings[0].filename) self._try_to_map(file_mappings) if current_thread_only: self._map_symbols_on_current_thread(mapped_files) else: logging.info('Updating all threads\' symbols') current_thread = gdb.selected_thread() nb_threads = len(_gdb_execute("info threads").split("\n")) - 2 for i in xrange(nb_threads): try: _gdb_execute("thread %d" % (i + 1)) self._map_symbols_on_current_thread(mapped_files) except gdb.error: traceback.print_exc() current_thread.switch()
def need_update(self): pkgs = [] threads_info = self.get_threads_info() exited_threads = set(self.saved_threads_info.keys()) - set( threads_info.keys()) rm_rowids = [] for global_num in exited_threads: #remove from GUI win exited threads rm_rowids.append(self.id_threadrow(global_num)) if rm_rowids: pkgs.append(self.pkg_drop_rows(rm_rowids)) new_threads = [] append_rows = [] for global_num in threads_info: thread_info = threads_info[global_num] if global_num not in self.saved_threads_info: #появился новый поток row = self.new_threadrow(thread_info) append_rows.append(row) #добавляем для него строку else: saved_thread_info = self.saved_threads_info[global_num] pkgs.append( self.compare_infos(global_num, old=saved_thread_info, new=thread_info)) if append_rows: pkgs.append(self.pkg_append_rows(append_rows)) self.saved_threads_info = threads_info self.selected_global_num = gdb.selected_thread().global_num return pkgs
def find_lock_manager_holders(graph, thread_dict, show): frame = find_frame(r'mongo::LockerImpl\<.*\>::') if not frame: return frame.select() (_, lwpid, _) = gdb.selected_thread().ptid locker_ptr_type = gdb.lookup_type("mongo::LockerImpl<false>").pointer() lock_head = gdb.parse_and_eval( "mongo::getGlobalLockManager()->_getBucket(resId)->findOrInsert(resId)") grantedList = lock_head.dereference()["grantedList"] lock_request_ptr = grantedList["_front"] while lock_request_ptr: lock_request = lock_request_ptr.dereference() locker_ptr = lock_request["locker"] locker_ptr = locker_ptr.cast(locker_ptr_type) locker = locker_ptr.dereference() lock_thread_id = int(locker["_threadId"]["_M_thread"]) lock_thread_lwpid = find_lwpid(thread_dict, lock_thread_id) if show: print("MongoDB Lock at {} ({}) held by thread id 0x{:x} (LWP {})".format( lock_head, lock_request["mode"], lock_thread_id, lock_thread_lwpid) + " waited on by thread 0x{:x} (LWP {})".format(thread_dict[lwpid], lwpid)) if graph: graph.add_edge(Thread(thread_dict[lwpid], lwpid), Lock(long(lock_head), "MongoDB lock")) graph.add_edge(Lock(long(lock_head), "MongoDB lock"), Thread(lock_thread_id, lock_thread_lwpid)) lock_request_ptr = lock_request["next"]
def pkg_update_bps(self, bps): bps_data = [] for bp in bps: if not bp.is_valid( ) or not bp.visible or bp.type != gdb.BP_BREAKPOINT: continue bp_data = {} for name in [ 'silent', 'thread', 'ignore_count', 'number', 'temporary', 'hit_count', 'condition', 'commands', 'enabled' ]: value = getattr(bp, name) bp_data[name] = value external_id = self.bp_gdb_mc.get(bp.number) if external_id is not None: bp_data['external_id'] = external_id else: self.bp_gdb_mc[bp.number] = None bp_data['locations'] = map( lambda fl: { 'filename': fl[0], 'line': fl[1] }, get_bp_locations(bp)) bps_data.append(bp_data) if len(bps_data) == 0: return sel_th = gdb.selected_thread() return { 'cmd': 'bpsupd', 'bps_data': bps_data, }
def get_current_slab_cache_cpu(self, slab_cache): void = gdb.lookup_type("void").pointer() kmem_cache_cpu = gdb.lookup_type("struct kmem_cache_cpu") current_cpu = gdb.selected_thread().num - 1 cpu_offset = self.per_cpu_offset[current_cpu] cpu_slab = gdb.Value(slab_cache["cpu_slab"].cast(void) + cpu_offset) return cpu_slab.cast(kmem_cache_cpu.pointer()).dereference()
def find_mutex_holder(graph, thread_dict, show): frame = find_frame(r'std::mutex::lock\(\)') if frame is None: return frame.select() # Waiting for mutex locking! mutex_this, _ = gdb.lookup_symbol("this", frame.block()) mutex_value = mutex_this.value(frame) # The mutex holder is a LWPID mutex_holder = int(mutex_value["_M_mutex"]["__data"]["__owner"]) mutex_holder_id = thread_dict[mutex_holder] (_, mutex_waiter_lwpid, _) = gdb.selected_thread().ptid mutex_waiter_id = thread_dict[mutex_waiter_lwpid] if show: print("Mutex at {} held by thread 0x{:x} (LWP {}) " " waited on by thread 0x{:x} (LWP {})".format(mutex_value, mutex_holder_id, mutex_holder, mutex_waiter_id, mutex_waiter_lwpid)) if graph: graph.add_edge(Thread(mutex_waiter_id, mutex_waiter_lwpid), Lock(long(mutex_value), "Mutex")) graph.add_edge(Lock(long(mutex_value), "Mutex"), Thread(mutex_holder_id, mutex_holder))
def find_lock_manager_holders(graph, thread_dict, show): frame = find_frame(r'mongo::LockerImpl\<.*\>::') if not frame: return frame.select() (_, lwpid, _) = gdb.selected_thread().ptid locker_ptr_type = gdb.lookup_type("mongo::LockerImpl<false>").pointer() lock_head = gdb.parse_and_eval( "mongo::getGlobalLockManager()->_getBucket(resId)->findOrInsert(resId)" ) grantedList = lock_head.dereference()["grantedList"] lock_request_ptr = grantedList["_front"] while lock_request_ptr: lock_request = lock_request_ptr.dereference() locker_ptr = lock_request["locker"] locker_ptr = locker_ptr.cast(locker_ptr_type) locker = locker_ptr.dereference() lock_thread_id = int(locker["_threadId"]["_M_thread"]) lock_thread_lwpid = find_lwpid(thread_dict, lock_thread_id) if show: print("MongoDB Lock at {} ({}) held by thread id 0x{:x} (LWP {})". format(lock_head, lock_request["mode"], lock_thread_id, lock_thread_lwpid) + " waited on by thread 0x{:x} (LWP {})".format( thread_dict[lwpid], lwpid)) if graph: graph.add_edge(Thread(thread_dict[lwpid], lwpid), Lock(long(lock_head), "MongoDB lock")) graph.add_edge(Lock(long(lock_head), "MongoDB lock"), Thread(lock_thread_id, lock_thread_lwpid)) lock_request_ptr = lock_request["next"]
def find_mutex_holder(graph, thread_dict, show): """Find mutex holder.""" frame = find_frame(r'std::mutex::lock\(\)') if frame is None: return frame.select() # Waiting for mutex locking! mutex_this, _ = gdb.lookup_symbol("this", frame.block()) mutex_value = mutex_this.value(frame) # The mutex holder is a LWPID mutex_holder_lwpid = int(mutex_value["_M_mutex"]["__data"]["__owner"]) # At time thread_dict was initialized, the mutex holder may not have been found. # Use the thread LWP as a substitute for showing output or generating the graph. if mutex_holder_lwpid not in thread_dict: print("Warning: Mutex at {} held by thread with LWP {}" " not found in thread_dict. Using LWP to track thread.".format( mutex_value, mutex_holder_lwpid)) mutex_holder = Thread(mutex_holder_lwpid, mutex_holder_lwpid, '"[unknown]"') else: mutex_holder = thread_dict[mutex_holder_lwpid] (_, mutex_waiter_lwpid, _) = gdb.selected_thread().ptid mutex_waiter = thread_dict[mutex_waiter_lwpid] if show: print("Mutex at {} held by {} waited on by {}".format(mutex_value, mutex_holder, mutex_waiter)) if graph: graph.add_edge(mutex_waiter, Lock(long(mutex_value), "Mutex")) graph.add_edge(Lock(long(mutex_value), "Mutex"), mutex_holder)
def find_mutex_holder(graph, thread_dict, show): """Find mutex holder.""" frame = find_frame(r'std::mutex::lock\(\)') if frame is None: return frame.select() # Waiting for mutex locking! mutex_this, _ = gdb.lookup_symbol("this", frame.block()) mutex_value = mutex_this.value(frame) # The mutex holder is a LWPID mutex_holder_lwpid = int(mutex_value["_M_mutex"]["__data"]["__owner"]) # At time thread_dict was initialized, the mutex holder may not have been found. # Use the thread LWP as a substitute for showing output or generating the graph. if mutex_holder_lwpid not in thread_dict: print("Warning: Mutex at {} held by thread with LWP {}" " not found in thread_dict. Using LWP to track thread.".format( mutex_value, mutex_holder_lwpid)) mutex_holder = Thread(mutex_holder_lwpid, mutex_holder_lwpid, '"[unknown]"') else: mutex_holder = thread_dict[mutex_holder_lwpid] (_, mutex_waiter_lwpid, _) = gdb.selected_thread().ptid mutex_waiter = thread_dict[mutex_waiter_lwpid] if show: print("Mutex at {} held by {} waited on by {}".format( mutex_value, mutex_holder, mutex_waiter)) if graph: graph.add_edge(mutex_waiter, Lock(long(mutex_value), "Mutex")) graph.add_edge(Lock(long(mutex_value), "Mutex"), mutex_holder)
def chooseThreadFlip(): tag = "chooseThreadFlip" bufLog = "" try: inferior = gdb.selected_inferior() for inf in gdb.inferiors(): logging.debug("Inferior PID: " + str(inf.pid)) logging.debug("Inferior is valid: " + str(inf.is_valid())) logging.debug("Inferior #threads: " + str(len(inf.threads()))) th = gdb.selected_thread() bufLog += str("Backtrace BEGIN:") bufLog += "\n" bt = gdb.execute("bt", to_string=True) sourceLines = gdb.execute("list", to_string=True) bufLog += str(bt) bufLog += "\n" bufLog += str(sourceLines) bufLog += "\n" bufLog += str("Backtrace END") bufLog += "\n" threadsSymbols = list() for th in inferior.threads(): try: th.switch() thSymbols = getAllValidSymbols() if len(thSymbols) > 0: threadsSymbols.append([th, thSymbols]) except: continue thLen = len(threadsSymbols) if thLen <= 0: logging.debug(str("No Threads with symbols")) return False thPos = random.randint(0, thLen - 1) curThread = threadsSymbols[thPos][0] logging.debug("Thread name: " + str(curThread.name)) logging.debug("Thread num: " + str(curThread.num)) logging.debug("Thread ptid: " + str(curThread.ptid)) bufLogFFText = "" (r, bufLogFFText) = chooseFrameFlip(threadsSymbols[thPos][1]) while r is False: threadsSymbols.pop(thPos) thLen -= 1 if (thLen <= 0): break thPos = random.randint(0, thLen - 1) try: (r, bufLogFFText) = chooseFrameFlip(threadsSymbols[thPos][1]) except: r = False bufLog += bufLogFFText if r or conf.getboolean("DEFAULT", "debug"): logging.info(bufLog) return r except Exception as err: logging.exception("pythonException: " + str(err)) if conf.getboolean("DEFAULT", "debug"): logging.info(bufLog) return False
def update_symbols(self, current_thread_only): """Updates the mapping between symbols as seen from GDB and local library files. If current_thread_only is True, only update symbols for the current thread. """ logging.info("Updating symbols") mapped_files = _get_mapped_files() # Map all symbols from native libraries packages with the APK. for file_mappings in mapped_files: filename = file_mappings[0].filename if ( (filename.startswith("/data/data/") or filename.startswith("/data/app")) and not filename.endswith(".apk") and not filename.endswith(".dex") ): logging.info("Pre-mapping: %s" % file_mappings[0].filename) self._try_to_map(file_mappings) if current_thread_only: self._map_symbols_on_current_thread(mapped_files) else: logging.info("Updating all threads' symbols") current_thread = gdb.selected_thread() nb_threads = len(_gdb_execute("info threads").split("\n")) - 2 for i in xrange(nb_threads): try: _gdb_execute("thread %d" % (i + 1)) self._map_symbols_on_current_thread(mapped_files) except gdb.error: traceback.print_exc() current_thread.switch()
def find_mutex_holder(graph, thread_dict, show): frame = find_frame(r'std::mutex::lock\(\)') if frame is None: return frame.select() # Waiting for mutex locking! mutex_this, _ = gdb.lookup_symbol("this", frame.block()) mutex_value = mutex_this.value(frame) # The mutex holder is a LWPID mutex_holder = int(mutex_value["_M_mutex"]["__data"]["__owner"]) mutex_holder_id = thread_dict[mutex_holder] (_, mutex_waiter_lwpid, _) = gdb.selected_thread().ptid mutex_waiter_id = thread_dict[mutex_waiter_lwpid] if show: print("Mutex at {} held by thread 0x{:x} (LWP {}) " " waited on by thread 0x{:x} (LWP {})".format( mutex_value, mutex_holder_id, mutex_holder, mutex_waiter_id, mutex_waiter_lwpid)) if graph: graph.add_edge(Thread(mutex_waiter_id, mutex_waiter_lwpid), Lock(long(mutex_value), "Mutex")) graph.add_edge(Lock(long(mutex_value), "Mutex"), Thread(mutex_holder_id, mutex_holder))
def _Inject(self, position, call): """Injects evaluation of 'call' in a safe location in the inferior. Due to the way these injected function calls work, gdb must not be killed until the call has returned. If that happens, the inferior will be sent SIGTRAP upon attempting to return from the dummy frame gdb constructs for us, and will most probably crash. Args: position: array of pid, tid, framedepth specifying the requested position. call: Any expression gdb can evaluate. Usually a function call. Raises: RuntimeError: if gdb is not being run in synchronous exec mode. """ self.EnsureGdbPosition(position[0], position[1], None) self.ClearBreakpoints() self._AddThreadSpecificBreakpoint(position) gdb.parse_and_eval('%s = 1' % GdbCache.PENDINGCALLS_TO_DO) gdb.parse_and_eval('%s = 1' % GdbCache.PENDINGBUSY) try: # We're "armed", risk the blocking call to Continue self.Continue(position) # Breakpoint was hit! if not gdb.selected_thread().is_stopped(): # This should not happen. Depending on how gdb is being used, the # semantics of self.Continue change, so I'd rather leave this check in # here, in case we ever *do* end up changing to async mode. raise RuntimeError('Gdb is not acting as expected, is it being run in ' 'async mode?') finally: gdb.parse_and_eval('%s = 0' % GdbCache.PENDINGBUSY) self.Call(position, call)
def restoreCurrentState(state): curr_thread = gdb.selected_thread() for thread in gdb.selected_inferior().threads(): if thread.num in state: thread.switch() state[thread.num].switch() curr_thread.switch() state = {}
def on_new_objfile(self): if self.running or not gdb.selected_thread(): return self.running = True for function in self.registered: function()
def reactors(): orig = gdb.selected_thread() for t in gdb.selected_inferior().threads(): t.switch() reactor = gdb.parse_and_eval('local_engine') if reactor: yield reactor.dereference() orig.switch()
def prompt_hook(*a): global cur new = (gdb.selected_inferior(), gdb.selected_thread()) if cur != new: pwndbg.events.after_reload() cur = new prompt_hook_on_stop(*a)
def save_context(self, ctx): if self.context is None: self.context = {} os_thread = gdb.selected_thread().num if os_thread in self.context: return self.context[os_thread] = ctx
def stop(self): thread_id = int(gdb.selected_thread().num) assert thread_id in threads fn_result = get_result() fn_name, fn_args, fn_stacktrace = threads[thread_id] assert fn_name == self.on_enter.fn_name add_call(allocs, free_stats, call_stats, fn_name, fn_args, fn_stacktrace, fn_result) del threads[thread_id] return False
def tid(self): if pwndbg.qemu.is_qemu_usermode(): return pwndbg.qemu.pid() i = gdb.selected_thread() if i is not None: return i.ptid[1] return self.pid
def print_thread(thr, mut, owns=[]): "A helper function to nicely print a gdb.Thread." (pid, lwp, tid) = thr.ptid out = "* " if thr == gdb.selected_thread() else " " out += "Owner " if mut in owns else "Thread " out += "%2d (LWP %d) " % (thr.num, lwp) if owns: out += " owns: %s" % (" ".join(map(lambda addr: ("0x%x" % addr) if addr != mut else "this", owns))) print(out)
def __init__(self, typecache): self.next_sp = None self.next_type = None self.activation = None # An unwinder instance is specific to a thread. Record the # selected thread for later verification. self.thread = gdb.selected_thread() self.frame_map = {} self.proc_mappings = parse_proc_maps() self.typecache = typecache
def _get_current_thread_name(self): fallback_name = '"%s"' % (gdb.selected_thread().name or '') try: # This goes through the pretty printer for StringData which adds "" around the name. name = str(gdb.parse_and_eval("mongo::for_debuggers::threadName")) if name == '""': return fallback_name return name except gdb.error: return fallback_name