def context_expressions(target=sys.stdout, with_banner=True, width=None): if not expressions: return [] banner = [pwndbg.ui.banner("expressions", target=target, width=width)] output = [] if width is None: _height, width = pwndbg.ui.get_window_size(target=target) for exp, cmd in sorted(expressions): try: # value = gdb.parse_and_eval(exp) value = str(cmd(exp)) except gdb.error as err: value = str(err) value = value.split("\n") lines = [] for line in value: if width and len(line) + len(exp) + 3 > width: n = width - (len(exp) + 3) - 1 # 1 Padding... lines.extend(line[i:i + n] for i in range(0, len(line), n)) else: lines.append(line) fmt = C.highlight(exp) lines[0] = "{} = {}".format(fmt, lines[0]) lines[1:] = [" " * (len(exp) + 3) + line for line in lines[1:]] output.extend(lines) return banner + output if with_banner else output
def instruction(ins): asm = '%-06s %s' % (ins.mnemonic, ins.op_str) if pwndbg.config.syntax_highlight: asm = syntax_highlight(asm) is_branch = set(ins.groups) & capstone_branch_groups # Highlight the current line if enabled if pwndbg.config.highlight_pc and ins.address == pwndbg.regs.pc: asm = C.highlight(asm) # tl;dr is a branch? if ins.target not in (None, ins.address + ins.size): sym = pwndbg.symbol.get(ins.target) or None target = M.get(ins.target) const = ins.target_const hextarget = hex(ins.target) hexlen = len(hextarget) # If it's a constant expression, color it directly in the asm. if const: asm = '%s <%s>' % (ljust_colored(asm, 36), target) asm = asm.replace(hex(ins.target), sym or target) # It's not a constant expression, but we've calculated the target # address by emulation or other means (for example showing ret instruction target) elif sym: asm = '%s <%s; %s>' % (ljust_colored(asm, 36), target, sym) # We were able to calculate the target, but there is no symbol # name for it. else: asm += '<%s>' % (target) # not a branch elif ins.symbol: if is_branch and not ins.target: asm = '%s <%s>' % (asm, ins.symbol) # XXX: not sure when this ever happens asm += '<-- file a pwndbg bug for this' else: inlined_sym = asm.replace(hex(ins.symbol_addr), ins.symbol) # display symbol as mem text if no inline replacement was made mem_text = ins.symbol if inlined_sym == asm else None asm = '%s <%s>' % (ljust_colored(inlined_sym, 36), M.get(ins.symbol_addr, mem_text)) # Style the instruction mnemonic if it's a branch instruction. if is_branch: asm = asm.replace(ins.mnemonic, branch(ins.mnemonic), 1) # If we know the conditional is taken, mark it as taken. if ins.condition is None: asm = ' ' + asm elif ins.condition: asm = on('✔ ') + asm else: asm = ' ' + asm return asm
def instruction(ins): asm = '%-06s %s' % (ins.mnemonic, ins.op_str) # TODO: detect 'arm', 'x86,64' is only for Intel x86/64 _highlighted, asm = pwndbg.color.syntax_highlight(asm, language='ARM') is_branch = set(ins.groups) & capstone_branch_groups # Highlight the current line if enabled if pwndbg.config.highlight_pc and ins.address == pwndbg.regs.pc: asm = C.highlight(asm) # tl;dr is a branch? if ins.target not in (None, ins.address + ins.size): sym = pwndbg.symbol.get(ins.target) or None target = M.get(ins.target) const = ins.target_const hextarget = hex(ins.target) hexlen = len(hextarget) # If it's a constant expression, color it directly in the asm. if const: asm = asm.replace(hex(ins.target), sym or target) if sym: asm = '%s <%s>' % (ljust_colored(asm, 36), target) # It's not a constant expression, but we've calculated the target # address by emulation. elif sym: asm = '%s <%s; %s>' % (ljust_colored(asm, 36), target, sym) # We were able to calculate the target, but there is no symbol # name for it. else: asm += '<%s>' % (target) # not a branch elif ins.symbol: if is_branch and not ins.target: asm = '%s <%s>' % (asm, ins.symbol) # XXX: not sure when this ever happens asm += '<-- file a pwndbg bug for this' else: asm = asm.replace(hex(ins.symbol_addr), ins.symbol) asm = '%s <%s>' % (ljust_colored(asm, 36), M.get(ins.symbol_addr)) # Style the instruction mnemonic if it's a branch instruction. if is_branch: asm = asm.replace(ins.mnemonic, branch(ins.mnemonic), 1) # If we know the conditional is taken, mark it as green. if ins.condition is None: asm = ' ' + asm elif ins.condition: asm = green('✔ ') + asm else: asm = ' ' + asm return asm
def get_filename_and_formatted_source(): """ Returns formatted, lines limited and highlighted source as list or if it isn't there - an empty list """ sal = gdb.selected_frame().find_sal() # gdb.Symtab_and_line # Check if source code is available if sal.symtab is None: return "", [] # Get the full source code closest_line = sal.line filename = sal.symtab.fullname() try: source = get_highlight_source(filename) except IOError: return "", [] if not source: return "", [] n = int(source_code_lines) # Compute the line range start = max(closest_line - 1 - n // 2, 0) end = min(closest_line - 1 + n // 2 + 1, len(source)) num_width = len(str(end)) # split the code source = source[start:end] # Compute the prefix_sign length prefix_sign = pwndbg.config.code_prefix prefix_width = len(prefix_sign) # Format the output formatted_source = [] for line_number, code in enumerate(source, start=start + 1): fmt = " {prefix_sign:{prefix_width}} {line_number:>{num_width}} {code}" if pwndbg.config.highlight_source and line_number == closest_line: fmt = C.highlight(fmt) line = fmt.format( prefix_sign=C.prefix(prefix_sign) if line_number == closest_line else "", prefix_width=prefix_width, line_number=line_number, num_width=num_width, code=code, ) formatted_source.append(line) return filename, formatted_source
def context_code(): try: symtab = gdb.selected_frame().find_sal().symtab linetable = symtab.linetable() closest_pc = -1 closest_line = -1 for line in linetable: if line.pc <= pwndbg.regs.pc and line.pc > closest_pc: closest_line = line.line closest_pc = line.pc if closest_line < 0: return [] source = gdb.execute('list %i' % closest_line, from_tty=False, to_string=True) # If it starts on line 1, it's not really using the # correct source code. if not source or closest_line <= 1: return [] # highlight the current code line source_lines = source.splitlines() if pwndbg.config.highlight_source: for i in range(len(source_lines)): if source_lines[i].startswith('%s\t' % closest_line): source_lines[i] = C.highlight(source_lines[i]) break banner = [pwndbg.ui.banner("source")] banner.extend(source_lines) return banner except: pass if not pwndbg.ida.available(): return [] try: name = pwndbg.ida.GetFunctionName(pwndbg.regs.pc) addr = pwndbg.ida.LocByName(name) lines = pwndbg.ida.decompile(addr) return lines.splitlines() except: pass return []
def context_source(): try: symtab = gdb.selected_frame().find_sal().symtab linetable = symtab.linetable() closest_pc = -1 closest_line = -1 for line in linetable: if line.pc <= pwndbg.regs.pc and line.pc > closest_pc: closest_line = line.line closest_pc = line.pc if closest_line < 0: return [] source = gdb.execute('list %i' % closest_line, from_tty=False, to_string=True) # If it starts on line 1, it's not really using the # correct source code. if not source or closest_line <= 1: return [] # highlight the current code line source_lines = source.splitlines() if pwndbg.config.highlight_source: for i in range(len(source_lines)): if source_lines[i].startswith('%s\t' % closest_line): source_lines[i] = C.highlight(source_lines[i]) break banner = [pwndbg.ui.banner("code")] banner.extend(source_lines) return banner except: pass if not pwndbg.ida.available(): return [] try: name = pwndbg.ida.GetFunctionName(pwndbg.regs.pc) addr = pwndbg.ida.LocByName(name) lines = pwndbg.ida.decompile(addr) return lines.splitlines() except: pass return []
def nearpc(pc=None, lines=None, to_string=False, emulate=False): """ Disassemble near a specified address. """ # Repeating nearpc (pressing enter) makes it show next addresses # (writing nearpc explicitly again will reset its state) if nearpc.repeat: pc = nearpc.next_pc result = [] # Fix the case where we only have one argument, and # it's a small value. if lines is None and (pc is None or int(pc) < 0x100): lines = pc pc = None if pc is None: pc = pwndbg.regs.pc if lines is None: lines = nearpc_lines // 2 pc = int(pc) lines = int(lines) # Check whether we can even read this address if not pwndbg.memory.peek(pc): result.append(message.error('Invalid address %#x' % pc)) # # Load source data if it's available # pc_to_linenos = collections.defaultdict(lambda: []) # lineno_to_src = {} # frame = gdb.selected_frame() # if frame: # sal = frame.find_sal() # if sal: # symtab = sal.symtab # objfile = symtab.objfile # sourcefilename = symtab.filename # with open(sourcefilename, 'r') as sourcefile: # lineno_to_src = {i:l for i,l in enumerate(sourcefile.readlines())} # for line in symtab.linetable(): # pc_to_linenos[line.pc].append(line.line) instructions = pwndbg.disasm.near(pc, lines, emulate=emulate, show_prev_insns=not nearpc.repeat) if pwndbg.memory.peek(pc) and not instructions: result.append(message.error('Invalid instructions at %#x' % pc)) # In case $pc is in a new map we don't know about, # this will trigger an exploratory search. pwndbg.vmmap.find(pc) # Gather all addresses and symbols for each instruction symbols = [pwndbg.symbol.get(i.address) for i in instructions] addresses = ['%#x' % i.address for i in instructions] nearpc.next_pc = instructions[-1].address + instructions[ -1].size if instructions else 0 # Format the symbol name for each instruction symbols = ['<%s> ' % sym if sym else '' for sym in symbols] # Pad out all of the symbols and addresses if pwndbg.config.left_pad_disasm and not nearpc.repeat: symbols = ljust_padding(symbols) addresses = ljust_padding(addresses) prev = None first_pc = True # Print out each instruction for address_str, symbol, instr in zip(addresses, symbols, instructions): asm = D.instruction(instr) prefix_sign = pwndbg.config.nearpc_prefix # Show prefix only on the specified address and don't show it while in repeat-mode # or when showing current instruction for the second time show_prefix = instr.address == pc and not nearpc.repeat and first_pc prefix = ' %s' % (prefix_sign if show_prefix else ' ' * len(prefix_sign)) prefix = N.prefix(prefix) pre = pwndbg.ida.Anterior(instr.address) if pre: result.append(N.ida_anterior(pre)) # Colorize address and symbol if not highlighted # symbol is fetched from gdb and it can be e.g. '<main+8>' if instr.address != pc or not pwndbg.config.highlight_pc or nearpc.repeat: address_str = N.address(address_str) symbol = N.symbol(symbol) elif pwndbg.config.highlight_pc and first_pc: prefix = C.highlight(prefix) address_str = C.highlight(address_str) symbol = C.highlight(symbol) first_pc = False line = ' '.join((prefix, address_str, symbol, asm)) # If there was a branch before this instruction which was not # contiguous, put in some ellipses. if prev and prev.address + prev.size != instr.address: result.append(N.branch_marker('%s' % nearpc_branch_marker)) # Otherwise if it's a branch and it *is* contiguous, just put # and empty line. elif prev and any(g in prev.groups for g in (CS_GRP_CALL, CS_GRP_JUMP, CS_GRP_RET)): if len('%s' % nearpc_branch_marker_contiguous) > 0: result.append('%s' % nearpc_branch_marker_contiguous) # For syscall instructions, put the name on the side if instr.address == pc: syscall_name = pwndbg.arguments.get_syscall_name(instr) if syscall_name: line += ' <%s>' % N.syscall_name(syscall_name) # For Comment Function try: line += " " * 10 + C.comment( pwndbg.commands.comments.file_lists[pwndbg.proc.exe][hex( instr.address)]) except: pass result.append(line) # For call instructions, attempt to resolve the target and # determine the number of arguments. if show_args: result.extend([ '%8s%s' % ('', arg) for arg in pwndbg.arguments.format_args(instruction=instr) ]) prev = instr if not to_string: print('\n'.join(result)) return result
def nearpc(pc=None, lines=None, to_string=False, emulate=False): """ Disassemble near a specified address. """ # Fix the case where we only have one argument, and # it's a small value. if lines is None and (pc is None or int(pc) < 0x100): lines = pc pc = None if pc is None: pc = pwndbg.regs.pc if lines is None: lines = 5 pc = int(pc) lines = int(lines) # # Load source data if it's available # pc_to_linenos = collections.defaultdict(lambda: []) # lineno_to_src = {} # frame = gdb.selected_frame() # if frame: # sal = frame.find_sal() # if sal: # symtab = sal.symtab # objfile = symtab.objfile # sourcefilename = symtab.filename # with open(sourcefilename, 'r') as sourcefile: # lineno_to_src = {i:l for i,l in enumerate(sourcefile.readlines())} # for line in symtab.linetable(): # pc_to_linenos[line.pc].append(line.line) result = [] instructions = pwndbg.disasm.near(pc, lines, emulate=emulate) # In case $pc is in a new map we don't know about, # this will trigger an exploratory search. pwndbg.vmmap.find(pc) # Gather all addresses and symbols for each instruction symbols = [pwndbg.symbol.get(i.address) for i in instructions] addresses = ['%#x' % i.address for i in instructions] # Format the symbol name for each instruction symbols = ['<%s> ' % sym if sym else '' for sym in symbols] # Pad out all of the symbols and addresses if pwndbg.config.left_pad_disasm: symbols = ljust_padding(symbols) addresses = ljust_padding(addresses) prev = None # Print out each instruction for address_str, s, i in zip(addresses, symbols, instructions): asm = D.instruction(i) prefix = ' %s' % (pwndbg.config.nearpc_prefix if i.address == pc else ' ' * len(pwndbg.config.nearpc_prefix.value)) prefix = N.prefix(prefix) if pwndbg.config.highlight_pc: prefix = C.highlight(prefix) pre = pwndbg.ida.Anterior(i.address) if pre: result.append(N.ida_anterior(pre)) # Colorize address and symbol if not highlighted if i.address != pc or not pwndbg.config.highlight_pc: address_str = N.address(address_str) s = N.symbol(s) elif pwndbg.config.highlight_pc: address_str = C.highlight(address_str) s = C.highlight(s) line = ' '.join((prefix, address_str, s, asm)) # If there was a branch before this instruction which was not # contiguous, put in some ellipses. if prev and prev.address + prev.size != i.address: result.append(N.branch_marker('%s' % nearpc_branch_marker)) # Otherwise if it's a branch and it *is* contiguous, just put # and empty line. elif prev and any(g in prev.groups for g in (CS_GRP_CALL, CS_GRP_JUMP, CS_GRP_RET)): if len('%s' % nearpc_branch_marker_contiguous) > 0: result.append('%s' % nearpc_branch_marker_contiguous) # For syscall instructions, put the name on the side if i.address == pc: syscall_name = pwndbg.arguments.get_syscall_name(i) if syscall_name: line += ' <%s>' % N.syscall_name(syscall_name) result.append(line) # For call instructions, attempt to resolve the target and # determine the number of arguments. for arg, value in pwndbg.arguments.get(i): code = False if arg.type == 'char' else True pretty = pwndbg.chain.format(value, code=code) result.append('%8s%-10s %s' % ('', N.argument(arg.name) + ':', pretty)) prev = i if not to_string: print('\n'.join(result)) return result
def context_code(): try: # Compute the closest pc and line number symtab = gdb.selected_frame().find_sal().symtab linetable = symtab.linetable() closest_pc = -1 closest_line = -1 for line in linetable: if closest_pc < line.pc <= pwndbg.regs.pc: closest_line = line.line closest_pc = line.pc if closest_line < 0: return [] # Get the full source code filename = symtab.fullname() source = get_highlight_source(filename) # If it starts on line 1, it's not really using the # correct source code. if not source or closest_line <= 1: return [] n = int(source_code_lines) # Compute the line range start = max(closest_line - 1 - n // 2, 0) end = min(closest_line - 1 + n // 2 + 1, len(source)) num_width = len(str(end)) # split the code source = source[start:end] # Compute the prefix_sign length prefix_sign = pwndbg.config.code_prefix prefix_width = len(prefix_sign) # Format the output formatted_source = [] for line_number, code in enumerate(source, start=start + 1): fmt = ' {prefix_sign:{prefix_width}} {line_number:>{num_width}} {code}' if pwndbg.config.highlight_source and line_number == closest_line: fmt = C.highlight(fmt) line = fmt.format(prefix_sign=C.prefix(prefix_sign) if line_number == closest_line else '', prefix_width=prefix_width, line_number=line_number, num_width=num_width, code=code) formatted_source.append(line) banner = [pwndbg.ui.banner("Source (code)")] banner.extend(formatted_source) return banner except: pass if not pwndbg.ida.available(): return [] name = pwndbg.ida.GetFunctionName(pwndbg.regs.pc) addr = pwndbg.ida.LocByName(name) # May be None when decompilation failed or user loaded wrong binary in IDA code = pwndbg.ida.decompile(addr) if code: return [pwndbg.ui.banner("Hexrays pseudocode")] + code.splitlines() else: return []
def instruction(ins): asm = '%-06s %s' % (ins.mnemonic, ins.op_str) if pwndbg.config.syntax_highlight: asm = syntax_highlight(asm) is_branch = set(ins.groups) & capstone_branch_groups # Highlight the current line if enabled if pwndbg.config.highlight_pc and ins.address == pwndbg.regs.pc: asm = C.highlight(asm) # tl;dr is a branch? if ins.target not in (None, ins.address + ins.size): sym = pwndbg.symbol.get(ins.target) or None target = M.get(ins.target) const = ins.target_const # Use format string instead of hex() to avoid suffix 'l' or 'L' hextarget = '0x%x' % ins.target hexlen = len(hextarget) # If it's a constant expression, color it directly in the asm. if const: # TODO: Also colorize the address starts with '$' and '#' asm = asm.replace(hextarget, sym or target) if sym: asm = '%s <%s>' % (ljust_colored(asm, 36), target) # It's not a constant expression, but we've calculated the target # address by emulation. elif sym: asm = '%s <%s; %s>' % (ljust_colored(asm, 36), target, sym) # We were able to calculate the target, but there is no symbol # name for it. else: asm += '<%s>' % (target) # not a branch elif ins.symbol: if is_branch and not ins.target: asm = '%s <%s>' % (asm, ins.symbol) # XXX: not sure when this ever happens asm += '<-- file a pwndbg bug for this' else: asm = asm.replace(hex(ins.symbol_addr), ins.symbol) asm = '%s <%s>' % (ljust_colored(asm, 36), M.get(ins.symbol_addr)) # Style the instruction mnemonic if it's a branch instruction. if is_branch: asm = asm.replace(ins.mnemonic, branch(ins.mnemonic), 1) # If we know the conditional is taken, mark it as taken. if ins.condition is None: asm = ' ' + asm elif ins.condition: asm = on('✔ ') + asm else: asm = ' ' + asm return asm
def nearpc(pc=None, lines=None, to_string=False, emulate=False): """ Disassemble near a specified address. """ # Repeating nearpc (pressing enter) makes it show next addresses # (writing nearpc explicitly again will reset its state) if nearpc.repeat: pc = nearpc.next_pc result = [] # Fix the case where we only have one argument, and # it's a small value. if lines is None and (pc is None or int(pc) < 0x100): lines = pc pc = None if pc is None: pc = pwndbg.regs.pc if lines is None: lines = nearpc_lines // 2 pc = int(pc) lines = int(lines) # Check whether we can even read this address if not pwndbg.memory.peek(pc): result.append(message.error('Invalid address %#x' % pc)) # # Load source data if it's available # pc_to_linenos = collections.defaultdict(lambda: []) # lineno_to_src = {} # frame = gdb.selected_frame() # if frame: # sal = frame.find_sal() # if sal: # symtab = sal.symtab # objfile = symtab.objfile # sourcefilename = symtab.filename # with open(sourcefilename, 'r') as sourcefile: # lineno_to_src = {i:l for i,l in enumerate(sourcefile.readlines())} # for line in symtab.linetable(): # pc_to_linenos[line.pc].append(line.line) instructions = pwndbg.disasm.near(pc, lines, emulate=emulate, show_prev_insns=not nearpc.repeat) if pwndbg.memory.peek(pc) and not instructions: result.append(message.error('Invalid instructions at %#x' % pc)) # In case $pc is in a new map we don't know about, # this will trigger an exploratory search. pwndbg.vmmap.find(pc) # Gather all addresses and symbols for each instruction symbols = [pwndbg.symbol.get(i.address) for i in instructions] addresses = ['%#x' % i.address for i in instructions] nearpc.next_pc = instructions[-1].address + instructions[-1].size if instructions else 0 # Format the symbol name for each instruction symbols = ['<%s> ' % sym if sym else '' for sym in symbols] # Pad out all of the symbols and addresses if pwndbg.config.left_pad_disasm and not nearpc.repeat: symbols = ljust_padding(symbols) addresses = ljust_padding(addresses) prev = None # Print out each instruction for address_str, symbol, instr in zip(addresses, symbols, instructions): asm = D.instruction(instr) prefix_sign = pwndbg.config.nearpc_prefix # Show prefix only on the specified address and don't show it while in repeat-mode show_prefix = instr.address == pc and not nearpc.repeat prefix = ' %s' % (prefix_sign if show_prefix else ' ' * len(prefix_sign)) prefix = N.prefix(prefix) pre = pwndbg.ida.Anterior(instr.address) if pre: result.append(N.ida_anterior(pre)) # Colorize address and symbol if not highlighted # symbol is fetched from gdb and it can be e.g. '<main+8>' if instr.address != pc or not pwndbg.config.highlight_pc or nearpc.repeat: address_str = N.address(address_str) symbol = N.symbol(symbol) elif pwndbg.config.highlight_pc: prefix = C.highlight(prefix) address_str = C.highlight(address_str) symbol = C.highlight(symbol) line = ' '.join((prefix, address_str, symbol, asm)) # If there was a branch before this instruction which was not # contiguous, put in some ellipses. if prev and prev.address + prev.size != instr.address: result.append(N.branch_marker('%s' % nearpc_branch_marker)) # Otherwise if it's a branch and it *is* contiguous, just put # and empty line. elif prev and any(g in prev.groups for g in (CS_GRP_CALL, CS_GRP_JUMP, CS_GRP_RET)): if len('%s' % nearpc_branch_marker_contiguous) > 0: result.append('%s' % nearpc_branch_marker_contiguous) # For syscall instructions, put the name on the side if instr.address == pc: syscall_name = pwndbg.arguments.get_syscall_name(instr) if syscall_name: line += ' <%s>' % N.syscall_name(syscall_name) result.append(line) # For call instructions, attempt to resolve the target and # determine the number of arguments. if show_args: result.extend(['%8s%s' % ('', arg) for arg in pwndbg.arguments.format_args(instruction=instr)]) prev = instr if not to_string: print('\n'.join(result)) return result
def context_code(): try: # Compute the closest pc and line number symtab = gdb.selected_frame().find_sal().symtab linetable = symtab.linetable() closest_pc = -1 closest_line = -1 for line in linetable: if closest_pc < line.pc <= pwndbg.regs.pc: closest_line = line.line closest_pc = line.pc if closest_line < 0: return [] # Get the full source code filename = symtab.fullname() source = get_highlight_source(filename) # If it starts on line 1, it's not really using the # correct source code. if not source or closest_line <= 1: return [] n = int(source_code_lines) # Compute the line range start = max(closest_line - 1 - n//2, 0) end = min(closest_line - 1 + n//2 + 1, len(source)) num_width = len(str(end)) # split the code source = source[start:end] # Compute the prefix_sign length prefix_sign = pwndbg.config.code_prefix prefix_width = len(prefix_sign) # Format the output formatted_source = [] for line_number, code in enumerate(source, start=start + 1): fmt = ' {prefix_sign:{prefix_width}} {line_number:>{num_width}} {code}' if pwndbg.config.highlight_source and line_number == closest_line: fmt = C.highlight(fmt) line = fmt.format( prefix_sign=C.prefix(prefix_sign) if line_number == closest_line else '', prefix_width=prefix_width, line_number=line_number, num_width=num_width, code=code ) formatted_source.append(line) banner = [pwndbg.ui.banner("Source (code)"), 'In file: %s' % filename] banner.extend(formatted_source) return banner except: pass if not pwndbg.ida.available(): return [] name = pwndbg.ida.GetFunctionName(pwndbg.regs.pc) addr = pwndbg.ida.LocByName(name) # May be None when decompilation failed or user loaded wrong binary in IDA code = pwndbg.ida.decompile(addr) if code: return [pwndbg.ui.banner("Hexrays pseudocode")] + code.splitlines() else: return []
def context_code(): try: # Compute the closest pc and line number symtab = gdb.selected_frame().find_sal().symtab linetable = symtab.linetable() closest_pc = -1 closest_line = -1 for line in linetable: if closest_pc < line.pc <= pwndbg.regs.pc: closest_line = line.line closest_pc = line.pc if closest_line < 0: return [] # Get the full source code filename = symtab.fullname() source = get_highlight_source(filename) # If it starts on line 1, it's not really using the # correct source code. if not source or closest_line <= 1: return [] n = int(source_code_lines) # Compute the line range start = max(closest_line - 1 - n//2, 0) end = min(closest_line - 1 + n//2 + 1, len(source)) num_width = len(str(end)) # split the code source = source[start:end] # Compute the prefix_sign length # TODO: remove this if the config setter can make sure everything is unicode. # This is needed because the config value may be utf8 byte string. # It is better to convert to unicode at setter of config and then we will not need this. prefix_sign = pwndbg.config.code_prefix value = prefix_sign.value if isinstance(value, bytes): value = codecs.decode(value, 'utf-8') prefix_width = len(value) # Convert config class to str to make format() work prefix_sign = str(prefix_sign) # Format the output formatted_source = [] for line_number, code in enumerate(source, start=start + 1): fmt = ' {prefix_sign:{prefix_width}} {line_number:>{num_width}} {code}' if pwndbg.config.highlight_source and line_number == closest_line: fmt = C.highlight(fmt) line = fmt.format( prefix_sign=C.prefix(prefix_sign) if line_number == closest_line else '', prefix_width=prefix_width, line_number=line_number, num_width=num_width, code=code ) formatted_source.append(line) banner = [pwndbg.ui.banner("Source (code)")] banner.extend(formatted_source) return banner except: pass if not pwndbg.ida.available(): return [] name = pwndbg.ida.GetFunctionName(pwndbg.regs.pc) addr = pwndbg.ida.LocByName(name) # May be None when decompilation failed or user loaded wrong binary in IDA code = pwndbg.ida.decompile(addr) if code: return [pwndbg.ui.banner("Hexrays pseudocode")] + code.splitlines() else: return []