Repository: pwndbg/pwndbg

Issue:
Cannot get correct context when debug an ARM64 binary
## env
pwndbg latest
ubuntu 16.04
ARM64 gdbserver latest (8.3)
aarch64-linux-gnu-gdb (gcc-linaro-7.4.1-2019.02-x86_64_aarch64-linux-gnu)

## problem
When I use aarch64-linux-gnu-gdb and gdbserver to debug a ARM64 binary remotely, I cannot get the context of the remote binary, here is the error log. Is there anybody knows why?
```
0x0000005578b133a4 in memcmp@plt ()
'context': Print out the current register, instruction, and stack context.
Traceback (most recent call last):
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/__init__.py", line 136, in __call__
    return self.function(*args, **kwargs)
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/__init__.py", line 227, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/context.py", line 112, in context
    result.extend(func())
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/context.py", line 127, in context_regs
    return [pwndbg.ui.banner("registers")] + get_regs()
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/context.py", line 176, in get_regs
    desc = pwndbg.chain.format(value)
  File "/root/Pwn/Tools/pwndbg/pwndbg/chain.py", line 122, in format
    enhanced = pwndbg.enhance.enhance(chain[-2] + offset, code=code)
  File "/root/Pwn/Tools/pwndbg/pwndbg/enhance.py", line 102, in enhance
    instr = pwndbg.disasm.one(value)
  File "/root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py", line 118, in one
    for insn in get(address, 1):
  File "/root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py", line 138, in get
    i = get_one_instruction(address)
  File "/root/Pwn/Tools/pwndbg/pwndbg/memoize.py", line 48, in __call__
    value = self.func(*args, **kwargs)
  File "/root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py", line 106, in get_one_instruction
    md   = get_disassembler(address)
  File "/root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py", line 88, in get_disassembler
    extra = CS_MODE_THUMB if (pwndbg.regs.cpsr & (1<<5)) else CS_MODE_ARM
TypeError: unsupported operand type(s) for &: 'NoneType' and 'int'
```


Discussion:
It seems that `pwndbg.regs.cpsr` is `None`.

Can you show output of `info regs all` in GDB when debugging that target?


Yes. Here is the output:
```
pwndbg> info registers
x0             0x7ff8421348        549625926472
x1             0x80                128
x2             0x0                 0
x3             0x0                 0
x4             0x0                 0
x5             0x7fb77677d0        548538841040
x6             0x7fb7767ec0        548538842816
x7             0x0                 0
x8             0x62                98
x9             0xffffff80ffffffd0  -545460846640
x10            0x0                 0
x11            0x20                32
x12            0x0                 0
x13            0x0                 0
x14            0x1                 1
x15            0x0                 0
x16            0x7fb7c060f0        548543684848
x17            0x7fb7e57920        548546115872
x18            0x0                 0
x19            0x7ff8421348        549625926472
x20            0x7ff8421320        549625926432
x21            0x0                 0
x22            0x7ff8421330        549625926448
x23            0x7ff8421230        549625926192
x24            0x0                 0
x25            0x7ff8421350        549625926480
x26            0x7fb7e57860        548546115680
x27            0x0                 0
x28            0x0                 0
x29            0x7ff84211a0        549625926048
x30            0x7fb7e57a18        548546116120
sp             0x7ff84211a0        0x7ff84211a0
pc             0x7fb7e57a34        0x7fb7e57a34 <pthread_cond_wait+276>
cpsr           0x80000000          [ EL=0 N ]
fpsr           0x0                 0
fpcr           0x0                 0
```
(I edited your post and removed `info registers all` from it as it turned out the relevant info is in `info regs` so it wasn't needed)

Hmm... it seems there is `cpsr` register.  So it's somehow `pwndbg.regs.__getattr__` that is failing.

I also don't like this:
```
pwndbg> pi
>>> import pwndbg
>>> pwndbg.regs.rax
28
>>> pwndbg.regs.raaa
>>> pwndbg.regs.raaaxasd
>>>
```
I think the last two should fail in this case (I did this on amd64 target).
@thinkycx Can you show: `pi print(pwndbg.regs.last)`? This might require doing `pi import pwndbg` first.
You can also try to add some debug print to https://github.com/pwndbg/pwndbg/blob/dev/pwndbg/regs.py#L300-L301

Like 
![image](https://user-images.githubusercontent.com/10009354/61128056-47a9fc80-a4b1-11e9-838c-2e7a544035fa.png)

Here is the original print:

Some info maybe helpful:
```bash
pwndbg> x/3i $pc
=> 0x7f91465a34 <pthread_cond_wait+276>:	svc	#0x0
   0x7f91465a38 <pthread_cond_wait+280>:	cmn	x0, #0x1, lsl #12
   0x7f91465a3c <pthread_cond_wait+284>:	mov	x1, x0
pwndbg> telescope
'telescope': Recursively dereferences pointers starting at the specified address
    ($sp by default)
Traceback (most recent call last):
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/__init__.py", line 136, in __call__
    return self.function(*args, **kwargs)
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/__init__.py", line 227, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/telescope.py", line 121, in telescope
    pwndbg.chain.format(addr)))
  File "/root/Pwn/Tools/pwndbg/pwndbg/chain.py", line 122, in format
    enhanced = pwndbg.enhance.enhance(chain[-2] + offset, code=code)
  File "/root/Pwn/Tools/pwndbg/pwndbg/enhance.py", line 102, in enhance
    instr = pwndbg.disasm.one(value)
  File "/root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py", line 118, in one
    for insn in get(address, 1):
  File "/root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py", line 138, in get
    i = get_one_instruction(address)
  File "/root/Pwn/Tools/pwndbg/pwndbg/memoize.py", line 48, in __call__
    value = self.func(*args, **kwargs)
  File "/root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py", line 106, in get_one_instruction
    md   = get_disassembler(address)
  File "/root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py", line 88, in get_disassembler
    extra = CS_MODE_THUMB if (pwndbg.regs.cpsr & (1<<5)) else CS_MODE_ARM
TypeError: unsupported operand type(s) for &: 'NoneType' and 'int'

If that is an issue, you can report it on https://github.com/pwndbg/pwndbg/issues
(Please don't forget to search if it hasn't been reported before)
To generate the report and open a browser, you may run `bugreport --run-browser`
PS: Pull requests are welcome
> /root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py(88)get_disassembler()
-> extra = CS_MODE_THUMB if (pwndbg.regs.cpsr & (1<<5)) else CS_MODE_ARM
(Pdb) exit
```
Output1:
```
pwndbg> pi import pwndbg
pwndbg> pi print(pwndbg.regs.last)
{u'cpsr': None, u'pc': 547898153524L, u'x29': 549440384656L, u'x28': 0L, u'x25': 549440385088L, u'x24': 0L, u'x27': 0L, u'x26': 547898153056L, u'x21': 0L, u'x20': 549440385040L, u'x23': 549440384800L, u'x22': 549440385056L, u'x8': 98L, u'x9': 18446743528248704976L, u'x2': 0L, u'x3': 0L, u'x0': 549440385080L, u'x1': 128L, u'x6': 547890880192L, u'x7': 0L, u'x4': 0L, u'x5': 547890878416L, u'sp': 549440384656L, u'x18': 0L, u'x19': 549440385080L, u'x10': 0L, u'x11': 32L, u'x12': 0L, u'x13': 0L, u'x14': 1L, u'x15': 0L, u'x16': 547895722224L, u'x17': 547898153248L}
```

I tried again and the output2:
```bash
pwndbg> info registers
x0             0x7fcca106c8        548893951688
x1             0x80                128
x2             0x0                 0
x3             0x0                 0
x4             0x0                 0
x5             0x7fb41f47d0        548482795472
x6             0x7fb41f4ec0        548482797248
x7             0x0                 0
x8             0x62                98
x9             0xffffff80ffffffd0  -545460846640
x10            0x0                 0
x11            0x20                32
x12            0x0                 0
x13            0x0                 0
x14            0x1                 1
x15            0x0                 0
x16            0x7fb46930f0        548487639280
x17            0x7fb48e4920        548490070304
x18            0x0                 0
x19            0x7fcca106c8        548893951688
x20            0x7fcca106a0        548893951648
x21            0x0                 0
x22            0x7fcca106b0        548893951664
x23            0x7fcca105b0        548893951408
x24            0x0                 0
x25            0x7fcca106d0        548893951696
x26            0x7fb48e4860        548490070112
x27            0x0                 0
x28            0x0                 0
x29            0x7fcca10520        548893951264
x30            0x7fb48e4a18        548490070552
sp             0x7fcca10520        0x7fcca10520
pc             0x7fb48e4a34        0x7fb48e4a34 <pthread_cond_wait+276>
cpsr           0x80000000          [ EL=0 N ]
fpsr           0x0                 0
fpcr           0x0                 0
pwndbg> pi
>>> pi import pwndbg
  File "<stdin>", line 1
    pi import pwndbg
            ^
SyntaxError: invalid syntax
>>> import pwndbg
>>> print(pwndbg.regs.last)
{u'cpsr': None, u'pc': 548490070580L, u'x29': 548893951264L, u'x28': 0L, u'x25': 548893951696L, u'x24': 0L, u'x27': 0L, u'x26': 548490070112L, u'x21': 0L, u'x20': 548893951648L, u'x23': 548893951408L, u'x22': 548893951664L, u'x8': 98L, u'x9': 18446743528248704976L, u'x2': 0L, u'x3': 0L, u'x0': 548893951688L, u'x1': 128L, u'x6': 548482797248L, u'x7': 0L, u'x4': 0L, u'x5': 548482795472L, u'sp': 548893951264L, u'x18': 0L, u'x19': 548893951688L, u'x10': 0L, u'x11': 32L, u'x12': 0L, u'x13': 0L, u'x14': 1L, u'x15': 0L, u'x16': 548487639280L, u'x17': 548490070304L}
>>> pwndbg.regs.x1
128L
>>> pwndbg.regs.cpsr
<class 'gdb.error'>
Invalid cast.
```

So it seems like the `value = value.cast(pwndbg.typeinfo.ptrdiff)` failed? Can you make prints in between to confirm it? Or remove the `try: ... catch: ...` and invoke `set exception-debugger on` and try to debug what is failing.

Can you also show output of `show language` and `pi print(pwndbg.typeinfo.ptrdiff)`?


After I remove the try catch and invoke the set exception-debuffer on , the output is :
```
pwndbg> set exception-verbose on
Set whether to print a full stacktracefor exceptions raised in Pwndbg commands to True
Traceback (most recent call last):
  File "/root/Pwn/Tools/pwndbg/pwndbg/events.py", line 169, in caller
    func()
  File "/root/Pwn/Tools/pwndbg/pwndbg/regs.py", line 448, in update_last
    M.last = {k:M[k] for k in M.common}
  File "/root/Pwn/Tools/pwndbg/pwndbg/regs.py", line 448, in <dictcomp>
    M.last = {k:M[k] for k in M.common}
  File "/root/Pwn/Tools/pwndbg/pwndbg/memoize.py", line 48, in __call__
    value = self.func(*args, **kwargs)
  File "/root/Pwn/Tools/pwndbg/pwndbg/regs.py", line 320, in __getitem__
    item = getattr(self, item.lower())
  File "/root/Pwn/Tools/pwndbg/pwndbg/memoize.py", line 48, in __call__
    value = self.func(*args, **kwargs)
  File "/root/Pwn/Tools/pwndbg/pwndbg/regs.py", line 296, in __getattr__
    value = value.cast(pwndbg.typeinfo.ptrdiff)
error: Invalid cast.

If that is an issue, you can report it on https://github.com/pwndbg/pwndbg/issues
(Please don't forget to search if it hasn't been reported before)
To generate the report and open a browser, you may run `bugreport --run-browser`
PS: Pull requests are welcome
Traceback (most recent call last):
  File "/root/Pwn/Tools/pwndbg/pwndbg/prompt.py", line 37, in prompt_hook
    pwndbg.events.after_reload(start=False)
  File "/root/Pwn/Tools/pwndbg/pwndbg/events.py", line 220, in after_reload
    f()
  File "/root/Pwn/Tools/pwndbg/pwndbg/events.py", line 173, in caller
    raise e
gdb.error: Invalid cast.
```


Also I add some print, after that I try to remote connect to it.
```python
value = get_register(attr)
296                 print(value)
297                 print(pwndbg.typeinfo.ptrdiff)
298                 value = value.cast(pwndbg.typeinfo.ptrdiff)
```

Output:
```
Reading /lib/ld-linux-aarch64.so.1 from remote target...
0x0000007faf0ada34 in pthread_cond_wait () from target:/gpl/lib/libpthread.so.0
549544428024
unsigned long long
128
unsigned long long
0
unsigned long long
0
unsigned long long
0
unsigned long long
548390295504
unsigned long long
548390297280
unsigned long long
0
unsigned long long
98
unsigned long long
-545460846640
unsigned long long
0
unsigned long long
32
unsigned long long
0
unsigned long long
0
unsigned long long
1
unsigned long long
0
unsigned long long
548395139312
unsigned long long
548397570336
unsigned long long
0
unsigned long long
549544428024
unsigned long long
549544427984
unsigned long long
0
unsigned long long
549544428000
unsigned long long
549544427744
unsigned long long
0
unsigned long long
549544428032
unsigned long long
548397570144
unsigned long long
0
unsigned long long
0
unsigned long long
549544427600
unsigned long long
0x7ff3668050
unsigned long long
0x7faf0ada34 <pthread_cond_wait+276>
unsigned long long
[ EL=0 N ]
unsigned long long
Exception occured: Error: Invalid cast. (<class 'gdb.error'>)
For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
Python Exception <class 'gdb.error'> Invalid cast.:
[ EL=0 N ]
unsigned long long
Exception occured: Error: Invalid cast. (<class 'gdb.error'>)
For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
Python Exception <class 'gdb.error'> Invalid cast.:
549544428024
unsigned long long
128
unsigned long long
0
unsigned long long
0
unsigned long long
0
unsigned long long
548390295504
unsigned long long
548390297280
unsigned long long
0
unsigned long long
98
unsigned long long
-545460846640
unsigned long long
0
unsigned long long
32
unsigned long long
0
unsigned long long
0
unsigned long long
1
unsigned long long
0
unsigned long long
548395139312
unsigned long long
548397570336
unsigned long long
0
unsigned long long
549544428024
unsigned long long
549544427984
unsigned long long
0
unsigned long long
549544428000
unsigned long long
549544427744
unsigned long long
0
unsigned long long
549544428032
unsigned long long
548397570144
unsigned long long
0
unsigned long long
0
unsigned long long
549544427600
unsigned long long
0x7ff3668050
unsigned long long
0x7faf0ada34 <pthread_cond_wait+276>
unsigned long long
[ EL=0 N ]
unsigned long long
Exception occured: Error: Invalid cast. (<class 'gdb.error'>)
For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
Python Exception <class 'gdb.error'> Invalid cast.:


pwndbg> show language
The current source language is "auto; currently c".
549544428024
unsigned long long
128
unsigned long long
0
unsigned long long
0
unsigned long long
0
unsigned long long
548390295504
unsigned long long
548390297280
unsigned long long
0
unsigned long long
98
unsigned long long
-545460846640
unsigned long long
0
unsigned long long
32
unsigned long long
0
unsigned long long
0
unsigned long long
1
unsigned long long
0
unsigned long long
548395139312
unsigned long long
548397570336
unsigned long long
0
unsigned long long
549544428024
unsigned long long
549544427984
unsigned long long
0
unsigned long long
549544428000
unsigned long long
549544427744
unsigned long long
0
unsigned long long
549544428032
unsigned long long
548397570144
unsigned long long
0
unsigned long long
0
unsigned long long
549544427600
unsigned long long
0x7ff3668050
unsigned long long
0x7faf0ada34 <pthread_cond_wait+276>
unsigned long long
[ EL=0 N ]
unsigned long long
Exception occured: Error: Invalid cast. (<class 'gdb.error'>)
For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
Python Exception <class 'gdb.error'> Invalid cast.:
pwndbg>
```

```
pwndbg> pi print(pwndbg.typeinfo.ptrdiff)
unsigned long long
549544428024
unsigned long long
128
unsigned long long
0
unsigned long long
0
unsigned long long
0
unsigned long long
548390295504
unsigned long long
548390297280
unsigned long long
0
unsigned long long
98
unsigned long long
-545460846640
unsigned long long
0
unsigned long long
32
unsigned long long
0
unsigned long long
0
unsigned long long
1
unsigned long long
0
unsigned long long
548395139312
unsigned long long
548397570336
unsigned long long
0
unsigned long long
549544428024
unsigned long long
549544427984
unsigned long long
0
unsigned long long
549544428000
unsigned long long
549544427744
unsigned long long
0
unsigned long long
549544428032
unsigned long long
548397570144
unsigned long long
0
unsigned long long
0
unsigned long long
549544427600
unsigned long long
0x7ff3668050
unsigned long long
0x7faf0ada34 <pthread_cond_wait+276>
unsigned long long
[ EL=0 N ]
unsigned long long
Traceback (most recent call last):
  File "/root/Pwn/Tools/pwndbg/pwndbg/events.py", line 169, in caller
    func()
  File "/root/Pwn/Tools/pwndbg/pwndbg/regs.py", line 450, in update_last
    M.last = {k:M[k] for k in M.common}
  File "/root/Pwn/Tools/pwndbg/pwndbg/regs.py", line 450, in <dictcomp>
    M.last = {k:M[k] for k in M.common}
  File "/root/Pwn/Tools/pwndbg/pwndbg/memoize.py", line 48, in __call__
    value = self.func(*args, **kwargs)
  File "/root/Pwn/Tools/pwndbg/pwndbg/regs.py", line 322, in __getitem__
    item = getattr(self, item.lower())
  File "/root/Pwn/Tools/pwndbg/pwndbg/memoize.py", line 48, in __call__
    value = self.func(*args, **kwargs)
  File "/root/Pwn/Tools/pwndbg/pwndbg/regs.py", line 298, in __getattr__
    value = value.cast(pwndbg.typeinfo.ptrdiff)
error: Invalid cast.

> /root/Pwn/Tools/pwndbg/pwndbg/regs.py(298)__getattr__()
-> value = value.cast(pwndbg.typeinfo.ptrdiff)
(Pdb)
```



Does this occur on all aarch64 binaries? I've seen it work in the past on at least some. If this is happening on a specific binary, is that binary public?
> Does this occur on all aarch64 binaries? I've seen it work in the past on at least some. If this is happening on a specific binary, is that binary public?

Yes. It will occur on many aarch64 binaries. And sorry that the binary is not public. I will test some other binaries later.
@thinkycx  Any update on providing a repro case?
Thanks for your waiting. 
Sorry that I'm so busy nowadays. 
I will try on some other binaries later. 
Hello I have tested some other binaries such as /bin/bash.
Sadly, it is the same and the binary is not public.

```
pwndbg> set exception-verbose on
Set whether to print a full stacktracefor exceptions raised in Pwndbg commands to True
pwndbg> ni
0x0000007fb7fd3004 in ?? () from target:/lib/ld-linux-aarch64.so.1
'context': Print out the current register, instruction, and stack context.
Traceback (most recent call last):
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/__init__.py", line 136, in __call__
    return self.function(*args, **kwargs)
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/__init__.py", line 227, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/context.py", line 112, in context
    result.extend(func())
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/context.py", line 127, in context_regs
    return [pwndbg.ui.banner("registers")] + get_regs()
  File "/root/Pwn/Tools/pwndbg/pwndbg/commands/context.py", line 176, in get_regs
    desc = pwndbg.chain.format(value)
  File "/root/Pwn/Tools/pwndbg/pwndbg/chain.py", line 122, in format
    enhanced = pwndbg.enhance.enhance(chain[-2] + offset, code=code)
  File "/root/Pwn/Tools/pwndbg/pwndbg/enhance.py", line 102, in enhance
    instr = pwndbg.disasm.one(value)
  File "/root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py", line 115, in one
    for insn in get(address, 1):
  File "/root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py", line 135, in get
    i = get_one_instruction(address)
  File "/root/Pwn/Tools/pwndbg/pwndbg/memoize.py", line 48, in __call__
    value = self.func(*args, **kwargs)
  File "/root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py", line 103, in get_one_instruction
    md   = get_disassembler(address)
  File "/root/Pwn/Tools/pwndbg/pwndbg/disasm/__init__.py", line 85, in get_disassembler
    extra = CS_MODE_THUMB if (pwndbg.regs.cpsr & (1<<5)) else CS_MODE_ARM
TypeError: unsupported operand type(s) for &: 'NoneType' and 'int'
```

I don't need to debug the binaries on the target system( a system on the car) so I am going to close the issue.
If anyone comes into the problem, you can reopen it at any time.

Resolving patch:
diff --git a/pwndbg/regs.py b/pwndbg/regs.py
--- a/pwndbg/regs.py
+++ b/pwndbg/regs.py
@@ -286,7 +286,7 @@ def __getattr__(self, attr):
         attr = attr.lstrip('$')
         try:
             # Seriously, gdb? Only accepts uint32.
-            if 'eflags' in attr:
+            if 'eflags' in attr or 'cpsr' in attr:
                 value = gdb77_get_register(attr)
                 value = value.cast(pwndbg.typeinfo.uint32)
             else:


Test patch: