We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Context disasm crashes when trying to show dereferenced call address
Enhancing a disassembled instruction fails if it is an indirect call and the address cannot be dereferenced/retrieved.

The issue can be reproduced with a binary created from assembly:
```
global _start
_start:
call qword [r11+0x30]
```

Or, full testcase (assuming `nasm` is installed):
```
printf 'global _start\n_start:\ncall qword [r11+0x30]' > test.asm && nasm -f elf64 test.asm && ld test.o -o test && gdb ./test -ex entry
```


Current result:
```
Traceback (most recent call last):
  File "/home/dc/pwndbg/pwndbg/commands/__init__.py", line 135, in __call__
    return self.function(*args, **kwargs)
  File "/home/dc/pwndbg/pwndbg/commands/__init__.py", line 226, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/home/dc/pwndbg/pwndbg/commands/context.py", line 88, in context
    result.extend(func())
  File "/home/dc/pwndbg/pwndbg/commands/context.py", line 100, in context_regs
    return [pwndbg.ui.banner("registers")] + get_regs()
  File "/home/dc/pwndbg/pwndbg/commands/context.py", line 144, in get_regs
    desc = pwndbg.chain.format(value)
  File "/home/dc/pwndbg/pwndbg/chain.py", line 122, in format
    enhanced = pwndbg.enhance.enhance(chain[-2] + offset, code=code)
  File "/home/dc/pwndbg/pwndbg/enhance.py", line 102, in enhance
    instr = pwndbg.disasm.one(value)
  File "/home/dc/pwndbg/pwndbg/disasm/__init__.py", line 115, in one
    for insn in get(address, 1):
  File "/home/dc/pwndbg/pwndbg/disasm/__init__.py", line 135, in get
    i = get_one_instruction(address)
  File "/home/dc/pwndbg/pwndbg/memoize.py", line 48, in __call__
    value = self.func(*args, **kwargs)
  File "/home/dc/pwndbg/pwndbg/disasm/__init__.py", line 107, in get_one_instruction
    pwndbg.disasm.arch.DisassemblyAssistant.enhance(ins)
  File "/home/dc/pwndbg/pwndbg/disasm/arch.py", line 55, in enhance
    enhancer.enhance_next(instruction)
  File "/home/dc/pwndbg/pwndbg/disasm/arch.py", line 111, in enhance_next
    instruction.target = self.next(instruction, call=True)
  File "/home/dc/pwndbg/pwndbg/disasm/x86.py", line 112, in next
    return super(DisassemblyAssistant, self).next(instruction, call)
  File "/home/dc/pwndbg/pwndbg/disasm/arch.py", line 150, in next
    addr = int(pwndbg.memory.poi(pwndbg.typeinfo.ppvoid, addr))
  File "/home/dc/pwndbg/pwndbg/inthook.py", line 40, in __new__
    value = value.cast(pwndbg.typeinfo.ulong)
gdb.MemoryError: Cannot access memory at address 0x30
```

Expected result - display disasm:
```
call   qword ptr [r11 + 0x30]  # <INVALID>
```

or `INVALID DEREF` or sth like this.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `pwndbg/disasm/arch.py`
Content:
```
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 from __future__ import absolute_import
4 from __future__ import division
5 from __future__ import print_function
6 from __future__ import unicode_literals
7 
8 import collections
9 
10 import capstone
11 from capstone import *
12 
13 import pwndbg.memoize
14 import pwndbg.symbol
15 
16 CS_OP_IMM
17 
18 debug = False
19 
20 groups = {v:k for k,v in globals().items() if k.startswith('CS_GRP_')}
21 ops    = {v:k for k,v in globals().items() if k.startswith('CS_OP_')}
22 access = {v:k for k,v in globals().items() if k.startswith('CS_AC_')}
23 
24 for value1, name1 in dict(access).items():
25     for value2, name2 in dict(access).items():
26         access.setdefault(value1 | value2, '%s | %s' % (name1, name2))
27 
28 
29 class DisassemblyAssistant(object):
30     # Registry of all instances, {architecture: instance}
31     assistants = {}
32 
33     def __init__(self, architecture):
34         if architecture is not None:
35             self.assistants[architecture] = self
36 
37         self.op_handlers = {
38             CS_OP_IMM: self.immediate,
39             CS_OP_REG: self.register,
40             CS_OP_MEM: self.memory
41         }
42 
43         self.op_names = {
44             CS_OP_IMM: self.immediate_sz,
45             CS_OP_REG: self.register_sz,
46             CS_OP_MEM: self.memory_sz
47         }
48 
49     @staticmethod
50     def enhance(instruction):
51         enhancer = DisassemblyAssistant.assistants.get(pwndbg.arch.current, generic_assistant)
52         enhancer.enhance_operands(instruction)
53         enhancer.enhance_symbol(instruction)
54         enhancer.enhance_conditional(instruction)
55         enhancer.enhance_next(instruction)
56 
57         if debug:
58             print(enhancer.dump(instruction))
59 
60     def enhance_conditional(self, instruction):
61         """
62         Adds a ``condition`` field to the instruction.
63 
64         If the instruction is always executed unconditionally, the value
65         of the field is ``None``.
66 
67         If the instruction is executed conditionally, and we can be absolutely
68         sure that it will be executed, the value of the field is ``True``.
69         Generally, this implies that it is the next instruction to be executed.
70 
71         In all other cases, it is set to ``False``.
72         """
73         c = self.condition(instruction)
74 
75         if c:
76             c = True
77         elif c is not None:
78             c = False
79 
80         instruction.condition = c
81 
82     def condition(self, instruction):
83         return False
84 
85     def enhance_next(self, instruction):
86         """
87         Adds a ``next`` field to the instruction.
88 
89         By default, it is set to the address of the next linear
90         instruction.
91 
92         If the instruction is a non-"call" branch and either:
93 
94         - Is unconditional
95         - Is conditional, but is known to be taken
96 
97         And the target can be resolved, it is set to the address
98         of the jump target.
99         """
100         next_addr = None
101 
102         if instruction.condition in (True, None):
103             next_addr = self.next(instruction)
104 
105         instruction.target = None
106         instruction.target_const = None
107         instruction.next = None
108 
109         if next_addr is None:
110             next_addr = instruction.address + instruction.size
111             instruction.target = self.next(instruction, call=True)
112 
113 
114         instruction.next = next_addr & pwndbg.arch.ptrmask
115 
116         if instruction.target is None:
117             instruction.target = instruction.next
118 
119         if instruction.operands and instruction.operands[0].int:
120             instruction.target_const = True
121 
122 
123     def next(self, instruction, call=False):
124         """
125         Architecture-specific hook point for enhance_next.
126         """
127         if CS_GRP_CALL in instruction.groups:
128             if not call:
129                 return None
130 
131         elif CS_GRP_JUMP not in instruction.groups:
132             return None
133 
134         # At this point, all operands have been resolved.
135         # Assume only single-operand jumps.
136         if len(instruction.operands) != 1:
137             return None
138 
139         # Memory operands must be dereferenced
140         op   = instruction.operands[0]
141         addr = op.int
142         if addr:
143             addr &= pwndbg.arch.ptrmask
144         if op.type == CS_OP_MEM:
145             if addr is None:
146                 addr = self.memory(instruction, op)
147 
148             # self.memory may return none, so we need to check it here again
149             if addr is not None:
150                 addr = int(pwndbg.memory.poi(pwndbg.typeinfo.ppvoid, addr))
151         if op.type == CS_OP_REG:
152             addr = self.register(instruction, op)
153 
154         # Evidently this can happen?
155         if addr is None:
156             return None
157 
158         return int(addr)
159 
160     def enhance_symbol(self, instruction):
161         """
162         Adds a ``symbol`` and ``symbol_addr`` fields to the instruction.
163 
164         If, after parsing all of the operands, there is exactly one
165         value which resolved to a named symbol, it will be set to
166         that value.
167 
168         In all other cases, the value is ``None``.
169         """
170         instruction.symbol = None
171         operands = [o for o in instruction.operands if o.symbol]
172 
173         if len(operands) != 1:
174             return
175 
176         o = operands[0]
177 
178         instruction.symbol = o.symbol
179         instruction.symbol_addr = o.int
180 
181     def enhance_operands(self, instruction):
182         """
183         Enhances all of the operands in the instruction, by adding the following
184         fields:
185 
186         operand.str:
187             String of this operand, as it should appear in the
188             disassembly.
189 
190         operand.int:
191             Integer value of the operand, if it can be resolved.
192 
193         operand.symbol:
194             Resolved symbol name for this operand.
195         """
196         current = (instruction.address == pwndbg.regs.pc)
197 
198         for i, op in enumerate(instruction.operands):
199             op.int    = None
200             op.symbol = None
201 
202             op.int = self.op_handlers.get(op.type, lambda *a: None)(instruction, op)
203             if op.int:
204                 op.int &= pwndbg.arch.ptrmask
205             op.str = self.op_names.get(op.type, lambda *a: None)(instruction, op)
206 
207             if op.int:
208                 op.symbol = pwndbg.symbol.get(op.int)
209 
210 
211     def immediate(self, instruction, operand):
212         return operand.value.imm
213 
214     def immediate_sz(self, instruction, operand):
215         value = operand.int
216 
217         if abs(value) < 0x10:
218             return "%i" % value
219 
220         return "%#x" % value
221 
222     def register(self, instruction, operand):
223         if instruction.address != pwndbg.regs.pc:
224             return None
225 
226         # # Don't care about registers which are only overwritten
227         # if operand.access & CS_AC_WRITE and not operand.access & CS_AC_READ:
228         #     return None
229 
230         reg  = operand.value.reg
231         name = instruction.reg_name(reg)
232 
233         return pwndbg.regs[name]
234 
235     def register_sz(self, instruction, operand):
236         reg  = operand.value.reg
237         return instruction.reg_name(reg).lower()
238 
239     def memory(self, instruction, operand):
240         return None
241 
242     def memory_sz(self, instruction, operand):
243         return None # raise NotImplementedError
244 
245     def dump(self, instruction):
246         ins = instruction
247         rv  = []
248         rv.append('%s %s' % (ins.mnemonic, ins.op_str))
249 
250         for i, group in enumerate(ins.groups):
251             rv.append('   groups[%i]   = %s' % (i, groups.get(group, group)))
252 
253         rv.append('           next = %#x' % (ins.next))
254         rv.append('      condition = %r' % (ins.condition))
255 
256         for i, op in enumerate(ins.operands):
257             rv.append('   operands[%i] = %s' % (i, ops.get(op.type, op.type)))
258             rv.append('       access   = %s' % (access.get(op.access, op.access)))
259 
260             if op.int is not None:
261                 rv.append('            int = %#x' % (op.int))
262             if op.symbol is not None:
263                 rv.append('            sym = %s' % (op.symbol))
264             if op.str is not None:
265                 rv.append('            str = %s' % (op.str))
266 
267         return '\n'.join(rv)
268 
269 generic_assistant = DisassemblyAssistant(None)
270
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/pwndbg/disasm/arch.py b/pwndbg/disasm/arch.py
--- a/pwndbg/disasm/arch.py
+++ b/pwndbg/disasm/arch.py
@@ -8,6 +8,7 @@
 import collections
 
 import capstone
+import gdb
 from capstone import *
 
 import pwndbg.memoize
@@ -147,7 +148,12 @@
 
             # self.memory may return none, so we need to check it here again
             if addr is not None:
-                addr = int(pwndbg.memory.poi(pwndbg.typeinfo.ppvoid, addr))
+                try:
+                    # fails with gdb.MemoryError if the dereferenced address
+                    # doesn't belong to any of process memory maps
+                    addr = int(pwndbg.memory.poi(pwndbg.typeinfo.ppvoid, addr))
+                except gdb.MemoryError:
+                    return None
         if op.type == CS_OP_REG:
             addr = self.register(instruction, op)
 
@@ -243,6 +249,9 @@
         return None # raise NotImplementedError
 
     def dump(self, instruction):
+        """
+        Debug-only method.
+        """
         ins = instruction
         rv  = []
         rv.append('%s %s' % (ins.mnemonic, ins.op_str))

{"golden_diff": "diff --git a/pwndbg/disasm/arch.py b/pwndbg/disasm/arch.py\n--- a/pwndbg/disasm/arch.py\n+++ b/pwndbg/disasm/arch.py\n@@ -8,6 +8,7 @@\n import collections\n \n import capstone\n+import gdb\n from capstone import *\n \n import pwndbg.memoize\n@@ -147,7 +148,12 @@\n \n             # self.memory may return none, so we need to check it here again\n             if addr is not None:\n-                addr = int(pwndbg.memory.poi(pwndbg.typeinfo.ppvoid, addr))\n+                try:\n+                    # fails with gdb.MemoryError if the dereferenced address\n+                    # doesn't belong to any of process memory maps\n+                    addr = int(pwndbg.memory.poi(pwndbg.typeinfo.ppvoid, addr))\n+                except gdb.MemoryError:\n+                    return None\n         if op.type == CS_OP_REG:\n             addr = self.register(instruction, op)\n \n@@ -243,6 +249,9 @@\n         return None # raise NotImplementedError\n \n     def dump(self, instruction):\n+        \"\"\"\n+        Debug-only method.\n+        \"\"\"\n         ins = instruction\n         rv  = []\n         rv.append('%s %s' % (ins.mnemonic, ins.op_str))\n", "issue": "Context disasm crashes when trying to show dereferenced call address\nEnhancing a disassembled instruction fails if it is an indirect call and the address cannot be dereferenced/retrieved.\r\n\r\nThe issue can be reproduced with a binary created from assembly:\r\n```\r\nglobal _start\r\n_start:\r\ncall qword [r11+0x30]\r\n```\r\n\r\nOr, full testcase (assuming `nasm` is installed):\r\n```\r\nprintf 'global _start\\n_start:\\ncall qword [r11+0x30]' > test.asm && nasm -f elf64 test.asm && ld test.o -o test && gdb ./test -ex entry\r\n```\r\n\r\n\r\nCurrent result:\r\n```\r\nTraceback (most recent call last):\r\n  File \"/home/dc/pwndbg/pwndbg/commands/__init__.py\", line 135, in __call__\r\n    return self.function(*args, **kwargs)\r\n  File \"/home/dc/pwndbg/pwndbg/commands/__init__.py\", line 226, in _OnlyWhenRunning\r\n    return function(*a, **kw)\r\n  File \"/home/dc/pwndbg/pwndbg/commands/context.py\", line 88, in context\r\n    result.extend(func())\r\n  File \"/home/dc/pwndbg/pwndbg/commands/context.py\", line 100, in context_regs\r\n    return [pwndbg.ui.banner(\"registers\")] + get_regs()\r\n  File \"/home/dc/pwndbg/pwndbg/commands/context.py\", line 144, in get_regs\r\n    desc = pwndbg.chain.format(value)\r\n  File \"/home/dc/pwndbg/pwndbg/chain.py\", line 122, in format\r\n    enhanced = pwndbg.enhance.enhance(chain[-2] + offset, code=code)\r\n  File \"/home/dc/pwndbg/pwndbg/enhance.py\", line 102, in enhance\r\n    instr = pwndbg.disasm.one(value)\r\n  File \"/home/dc/pwndbg/pwndbg/disasm/__init__.py\", line 115, in one\r\n    for insn in get(address, 1):\r\n  File \"/home/dc/pwndbg/pwndbg/disasm/__init__.py\", line 135, in get\r\n    i = get_one_instruction(address)\r\n  File \"/home/dc/pwndbg/pwndbg/memoize.py\", line 48, in __call__\r\n    value = self.func(*args, **kwargs)\r\n  File \"/home/dc/pwndbg/pwndbg/disasm/__init__.py\", line 107, in get_one_instruction\r\n    pwndbg.disasm.arch.DisassemblyAssistant.enhance(ins)\r\n  File \"/home/dc/pwndbg/pwndbg/disasm/arch.py\", line 55, in enhance\r\n    enhancer.enhance_next(instruction)\r\n  File \"/home/dc/pwndbg/pwndbg/disasm/arch.py\", line 111, in enhance_next\r\n    instruction.target = self.next(instruction, call=True)\r\n  File \"/home/dc/pwndbg/pwndbg/disasm/x86.py\", line 112, in next\r\n    return super(DisassemblyAssistant, self).next(instruction, call)\r\n  File \"/home/dc/pwndbg/pwndbg/disasm/arch.py\", line 150, in next\r\n    addr = int(pwndbg.memory.poi(pwndbg.typeinfo.ppvoid, addr))\r\n  File \"/home/dc/pwndbg/pwndbg/inthook.py\", line 40, in __new__\r\n    value = value.cast(pwndbg.typeinfo.ulong)\r\ngdb.MemoryError: Cannot access memory at address 0x30\r\n```\r\n\r\nExpected result - display disasm:\r\n```\r\ncall   qword ptr [r11 + 0x30]  # <INVALID>\r\n```\r\n\r\nor `INVALID DEREF` or sth like this.\n", "before_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\n\nimport collections\n\nimport capstone\nfrom capstone import *\n\nimport pwndbg.memoize\nimport pwndbg.symbol\n\nCS_OP_IMM\n\ndebug = False\n\ngroups = {v:k for k,v in globals().items() if k.startswith('CS_GRP_')}\nops    = {v:k for k,v in globals().items() if k.startswith('CS_OP_')}\naccess = {v:k for k,v in globals().items() if k.startswith('CS_AC_')}\n\nfor value1, name1 in dict(access).items():\n    for value2, name2 in dict(access).items():\n        access.setdefault(value1 | value2, '%s | %s' % (name1, name2))\n\n\nclass DisassemblyAssistant(object):\n    # Registry of all instances, {architecture: instance}\n    assistants = {}\n\n    def __init__(self, architecture):\n        if architecture is not None:\n            self.assistants[architecture] = self\n\n        self.op_handlers = {\n            CS_OP_IMM: self.immediate,\n            CS_OP_REG: self.register,\n            CS_OP_MEM: self.memory\n        }\n\n        self.op_names = {\n            CS_OP_IMM: self.immediate_sz,\n            CS_OP_REG: self.register_sz,\n            CS_OP_MEM: self.memory_sz\n        }\n\n    @staticmethod\n    def enhance(instruction):\n        enhancer = DisassemblyAssistant.assistants.get(pwndbg.arch.current, generic_assistant)\n        enhancer.enhance_operands(instruction)\n        enhancer.enhance_symbol(instruction)\n        enhancer.enhance_conditional(instruction)\n        enhancer.enhance_next(instruction)\n\n        if debug:\n            print(enhancer.dump(instruction))\n\n    def enhance_conditional(self, instruction):\n        \"\"\"\n        Adds a ``condition`` field to the instruction.\n\n        If the instruction is always executed unconditionally, the value\n        of the field is ``None``.\n\n        If the instruction is executed conditionally, and we can be absolutely\n        sure that it will be executed, the value of the field is ``True``.\n        Generally, this implies that it is the next instruction to be executed.\n\n        In all other cases, it is set to ``False``.\n        \"\"\"\n        c = self.condition(instruction)\n\n        if c:\n            c = True\n        elif c is not None:\n            c = False\n\n        instruction.condition = c\n\n    def condition(self, instruction):\n        return False\n\n    def enhance_next(self, instruction):\n        \"\"\"\n        Adds a ``next`` field to the instruction.\n\n        By default, it is set to the address of the next linear\n        instruction.\n\n        If the instruction is a non-\"call\" branch and either:\n\n        - Is unconditional\n        - Is conditional, but is known to be taken\n\n        And the target can be resolved, it is set to the address\n        of the jump target.\n        \"\"\"\n        next_addr = None\n\n        if instruction.condition in (True, None):\n            next_addr = self.next(instruction)\n\n        instruction.target = None\n        instruction.target_const = None\n        instruction.next = None\n\n        if next_addr is None:\n            next_addr = instruction.address + instruction.size\n            instruction.target = self.next(instruction, call=True)\n\n\n        instruction.next = next_addr & pwndbg.arch.ptrmask\n\n        if instruction.target is None:\n            instruction.target = instruction.next\n\n        if instruction.operands and instruction.operands[0].int:\n            instruction.target_const = True\n\n\n    def next(self, instruction, call=False):\n        \"\"\"\n        Architecture-specific hook point for enhance_next.\n        \"\"\"\n        if CS_GRP_CALL in instruction.groups:\n            if not call:\n                return None\n\n        elif CS_GRP_JUMP not in instruction.groups:\n            return None\n\n        # At this point, all operands have been resolved.\n        # Assume only single-operand jumps.\n        if len(instruction.operands) != 1:\n            return None\n\n        # Memory operands must be dereferenced\n        op   = instruction.operands[0]\n        addr = op.int\n        if addr:\n            addr &= pwndbg.arch.ptrmask\n        if op.type == CS_OP_MEM:\n            if addr is None:\n                addr = self.memory(instruction, op)\n\n            # self.memory may return none, so we need to check it here again\n            if addr is not None:\n                addr = int(pwndbg.memory.poi(pwndbg.typeinfo.ppvoid, addr))\n        if op.type == CS_OP_REG:\n            addr = self.register(instruction, op)\n\n        # Evidently this can happen?\n        if addr is None:\n            return None\n\n        return int(addr)\n\n    def enhance_symbol(self, instruction):\n        \"\"\"\n        Adds a ``symbol`` and ``symbol_addr`` fields to the instruction.\n\n        If, after parsing all of the operands, there is exactly one\n        value which resolved to a named symbol, it will be set to\n        that value.\n\n        In all other cases, the value is ``None``.\n        \"\"\"\n        instruction.symbol = None\n        operands = [o for o in instruction.operands if o.symbol]\n\n        if len(operands) != 1:\n            return\n\n        o = operands[0]\n\n        instruction.symbol = o.symbol\n        instruction.symbol_addr = o.int\n\n    def enhance_operands(self, instruction):\n        \"\"\"\n        Enhances all of the operands in the instruction, by adding the following\n        fields:\n\n        operand.str:\n            String of this operand, as it should appear in the\n            disassembly.\n\n        operand.int:\n            Integer value of the operand, if it can be resolved.\n\n        operand.symbol:\n            Resolved symbol name for this operand.\n        \"\"\"\n        current = (instruction.address == pwndbg.regs.pc)\n\n        for i, op in enumerate(instruction.operands):\n            op.int    = None\n            op.symbol = None\n\n            op.int = self.op_handlers.get(op.type, lambda *a: None)(instruction, op)\n            if op.int:\n                op.int &= pwndbg.arch.ptrmask\n            op.str = self.op_names.get(op.type, lambda *a: None)(instruction, op)\n\n            if op.int:\n                op.symbol = pwndbg.symbol.get(op.int)\n\n\n    def immediate(self, instruction, operand):\n        return operand.value.imm\n\n    def immediate_sz(self, instruction, operand):\n        value = operand.int\n\n        if abs(value) < 0x10:\n            return \"%i\" % value\n\n        return \"%#x\" % value\n\n    def register(self, instruction, operand):\n        if instruction.address != pwndbg.regs.pc:\n            return None\n\n        # # Don't care about registers which are only overwritten\n        # if operand.access & CS_AC_WRITE and not operand.access & CS_AC_READ:\n        #     return None\n\n        reg  = operand.value.reg\n        name = instruction.reg_name(reg)\n\n        return pwndbg.regs[name]\n\n    def register_sz(self, instruction, operand):\n        reg  = operand.value.reg\n        return instruction.reg_name(reg).lower()\n\n    def memory(self, instruction, operand):\n        return None\n\n    def memory_sz(self, instruction, operand):\n        return None # raise NotImplementedError\n\n    def dump(self, instruction):\n        ins = instruction\n        rv  = []\n        rv.append('%s %s' % (ins.mnemonic, ins.op_str))\n\n        for i, group in enumerate(ins.groups):\n            rv.append('   groups[%i]   = %s' % (i, groups.get(group, group)))\n\n        rv.append('           next = %#x' % (ins.next))\n        rv.append('      condition = %r' % (ins.condition))\n\n        for i, op in enumerate(ins.operands):\n            rv.append('   operands[%i] = %s' % (i, ops.get(op.type, op.type)))\n            rv.append('       access   = %s' % (access.get(op.access, op.access)))\n\n            if op.int is not None:\n                rv.append('            int = %#x' % (op.int))\n            if op.symbol is not None:\n                rv.append('            sym = %s' % (op.symbol))\n            if op.str is not None:\n                rv.append('            str = %s' % (op.str))\n\n        return '\\n'.join(rv)\n\ngeneric_assistant = DisassemblyAssistant(None)\n", "path": "pwndbg/disasm/arch.py"}], "after_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nfrom __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\nfrom __future__ import unicode_literals\n\nimport collections\n\nimport capstone\nimport gdb\nfrom capstone import *\n\nimport pwndbg.memoize\nimport pwndbg.symbol\n\nCS_OP_IMM\n\ndebug = False\n\ngroups = {v:k for k,v in globals().items() if k.startswith('CS_GRP_')}\nops    = {v:k for k,v in globals().items() if k.startswith('CS_OP_')}\naccess = {v:k for k,v in globals().items() if k.startswith('CS_AC_')}\n\nfor value1, name1 in dict(access).items():\n    for value2, name2 in dict(access).items():\n        access.setdefault(value1 | value2, '%s | %s' % (name1, name2))\n\n\nclass DisassemblyAssistant(object):\n    # Registry of all instances, {architecture: instance}\n    assistants = {}\n\n    def __init__(self, architecture):\n        if architecture is not None:\n            self.assistants[architecture] = self\n\n        self.op_handlers = {\n            CS_OP_IMM: self.immediate,\n            CS_OP_REG: self.register,\n            CS_OP_MEM: self.memory\n        }\n\n        self.op_names = {\n            CS_OP_IMM: self.immediate_sz,\n            CS_OP_REG: self.register_sz,\n            CS_OP_MEM: self.memory_sz\n        }\n\n    @staticmethod\n    def enhance(instruction):\n        enhancer = DisassemblyAssistant.assistants.get(pwndbg.arch.current, generic_assistant)\n        enhancer.enhance_operands(instruction)\n        enhancer.enhance_symbol(instruction)\n        enhancer.enhance_conditional(instruction)\n        enhancer.enhance_next(instruction)\n\n        if debug:\n            print(enhancer.dump(instruction))\n\n    def enhance_conditional(self, instruction):\n        \"\"\"\n        Adds a ``condition`` field to the instruction.\n\n        If the instruction is always executed unconditionally, the value\n        of the field is ``None``.\n\n        If the instruction is executed conditionally, and we can be absolutely\n        sure that it will be executed, the value of the field is ``True``.\n        Generally, this implies that it is the next instruction to be executed.\n\n        In all other cases, it is set to ``False``.\n        \"\"\"\n        c = self.condition(instruction)\n\n        if c:\n            c = True\n        elif c is not None:\n            c = False\n\n        instruction.condition = c\n\n    def condition(self, instruction):\n        return False\n\n    def enhance_next(self, instruction):\n        \"\"\"\n        Adds a ``next`` field to the instruction.\n\n        By default, it is set to the address of the next linear\n        instruction.\n\n        If the instruction is a non-\"call\" branch and either:\n\n        - Is unconditional\n        - Is conditional, but is known to be taken\n\n        And the target can be resolved, it is set to the address\n        of the jump target.\n        \"\"\"\n        next_addr = None\n\n        if instruction.condition in (True, None):\n            next_addr = self.next(instruction)\n\n        instruction.target = None\n        instruction.target_const = None\n        instruction.next = None\n\n        if next_addr is None:\n            next_addr = instruction.address + instruction.size\n            instruction.target = self.next(instruction, call=True)\n\n\n        instruction.next = next_addr & pwndbg.arch.ptrmask\n\n        if instruction.target is None:\n            instruction.target = instruction.next\n\n        if instruction.operands and instruction.operands[0].int:\n            instruction.target_const = True\n\n\n    def next(self, instruction, call=False):\n        \"\"\"\n        Architecture-specific hook point for enhance_next.\n        \"\"\"\n        if CS_GRP_CALL in instruction.groups:\n            if not call:\n                return None\n\n        elif CS_GRP_JUMP not in instruction.groups:\n            return None\n\n        # At this point, all operands have been resolved.\n        # Assume only single-operand jumps.\n        if len(instruction.operands) != 1:\n            return None\n\n        # Memory operands must be dereferenced\n        op   = instruction.operands[0]\n        addr = op.int\n        if addr:\n            addr &= pwndbg.arch.ptrmask\n        if op.type == CS_OP_MEM:\n            if addr is None:\n                addr = self.memory(instruction, op)\n\n            # self.memory may return none, so we need to check it here again\n            if addr is not None:\n                try:\n                    # fails with gdb.MemoryError if the dereferenced address\n                    # doesn't belong to any of process memory maps\n                    addr = int(pwndbg.memory.poi(pwndbg.typeinfo.ppvoid, addr))\n                except gdb.MemoryError:\n                    return None\n        if op.type == CS_OP_REG:\n            addr = self.register(instruction, op)\n\n        # Evidently this can happen?\n        if addr is None:\n            return None\n\n        return int(addr)\n\n    def enhance_symbol(self, instruction):\n        \"\"\"\n        Adds a ``symbol`` and ``symbol_addr`` fields to the instruction.\n\n        If, after parsing all of the operands, there is exactly one\n        value which resolved to a named symbol, it will be set to\n        that value.\n\n        In all other cases, the value is ``None``.\n        \"\"\"\n        instruction.symbol = None\n        operands = [o for o in instruction.operands if o.symbol]\n\n        if len(operands) != 1:\n            return\n\n        o = operands[0]\n\n        instruction.symbol = o.symbol\n        instruction.symbol_addr = o.int\n\n    def enhance_operands(self, instruction):\n        \"\"\"\n        Enhances all of the operands in the instruction, by adding the following\n        fields:\n\n        operand.str:\n            String of this operand, as it should appear in the\n            disassembly.\n\n        operand.int:\n            Integer value of the operand, if it can be resolved.\n\n        operand.symbol:\n            Resolved symbol name for this operand.\n        \"\"\"\n        current = (instruction.address == pwndbg.regs.pc)\n\n        for i, op in enumerate(instruction.operands):\n            op.int    = None\n            op.symbol = None\n\n            op.int = self.op_handlers.get(op.type, lambda *a: None)(instruction, op)\n            if op.int:\n                op.int &= pwndbg.arch.ptrmask\n            op.str = self.op_names.get(op.type, lambda *a: None)(instruction, op)\n\n            if op.int:\n                op.symbol = pwndbg.symbol.get(op.int)\n\n\n    def immediate(self, instruction, operand):\n        return operand.value.imm\n\n    def immediate_sz(self, instruction, operand):\n        value = operand.int\n\n        if abs(value) < 0x10:\n            return \"%i\" % value\n\n        return \"%#x\" % value\n\n    def register(self, instruction, operand):\n        if instruction.address != pwndbg.regs.pc:\n            return None\n\n        # # Don't care about registers which are only overwritten\n        # if operand.access & CS_AC_WRITE and not operand.access & CS_AC_READ:\n        #     return None\n\n        reg  = operand.value.reg\n        name = instruction.reg_name(reg)\n\n        return pwndbg.regs[name]\n\n    def register_sz(self, instruction, operand):\n        reg  = operand.value.reg\n        return instruction.reg_name(reg).lower()\n\n    def memory(self, instruction, operand):\n        return None\n\n    def memory_sz(self, instruction, operand):\n        return None # raise NotImplementedError\n\n    def dump(self, instruction):\n        \"\"\"\n        Debug-only method.\n        \"\"\"\n        ins = instruction\n        rv  = []\n        rv.append('%s %s' % (ins.mnemonic, ins.op_str))\n\n        for i, group in enumerate(ins.groups):\n            rv.append('   groups[%i]   = %s' % (i, groups.get(group, group)))\n\n        rv.append('           next = %#x' % (ins.next))\n        rv.append('      condition = %r' % (ins.condition))\n\n        for i, op in enumerate(ins.operands):\n            rv.append('   operands[%i] = %s' % (i, ops.get(op.type, op.type)))\n            rv.append('       access   = %s' % (access.get(op.access, op.access)))\n\n            if op.int is not None:\n                rv.append('            int = %#x' % (op.int))\n            if op.symbol is not None:\n                rv.append('            sym = %s' % (op.symbol))\n            if op.str is not None:\n                rv.append('            str = %s' % (op.str))\n\n        return '\\n'.join(rv)\n\ngeneric_assistant = DisassemblyAssistant(None)\n", "path": "pwndbg/disasm/arch.py"}]}