Repository: pwndbg/pwndbg

Issue:
xinfo Exception
Hello!

I have the following problem:

```
pwndbg> p printf
$3 = {int (const char *, ...)} 0x7ffff7e33e10 <__printf>
pwndbg> xinfo 0x7ffff7e33e10
Extended information for virtual address 0x7ffff7e33e10:

  Containing mapping:
    0x7ffff7df4000     0x7ffff7f6c000 r-xp   178000 25000  /usr/lib/x86_64-linux-gnu/libc-2.31.so

  Offset information:
         Mapped Area 0x7ffff7e33e10 = 0x7ffff7df4000 + 0x3fe10
         File (Base) 0x7ffff7e33e10 = 0x7ffff7dcf000 + 0x64e10
'xinfo': Shows offsets of the specified address to useful other locations
Exception occurred: xinfo: argument of type 'int' is not iterable (<class 'TypeError'>)
For more info invoke `set exception-verbose on` and rerun the command
or debug it by yourself with `set exception-debugger on`
```
more details:
```
pwndbg> set exception-verbose on
Set whether to print a full stacktracefor exceptions raised in Pwndbg commands to True
pwndbg> xinfo 0x7ffff7e33e10
Extended information for virtual address 0x7ffff7e33e10:

  Containing mapping:
    0x7ffff7df4000     0x7ffff7f6c000 r-xp   178000 25000  /usr/lib/x86_64-linux-gnu/libc-2.31.so

  Offset information:
         Mapped Area 0x7ffff7e33e10 = 0x7ffff7df4000 + 0x3fe10
         File (Base) 0x7ffff7e33e10 = 0x7ffff7dcf000 + 0x64e10
'xinfo': Shows offsets of the specified address to useful other locations
Traceback (most recent call last):
  File "/opt/pwndbg/pwndbg/commands/__init__.py", line 136, in __call__
    return self.function(*args, **kwargs)
  File "/opt/pwndbg/pwndbg/commands/__init__.py", line 227, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/opt/pwndbg/pwndbg/commands/xinfo.py", line 126, in xinfo
    xinfo_mmap_file(page, addr)
  File "/opt/pwndbg/pwndbg/commands/xinfo.py", line 72, in xinfo_mmap_file
    containing_loads = [seg for seg in pwndbg.elf.get_containing_segments(file_name, first.vaddr, addr)
  File "/opt/pwndbg/pwndbg/elf.py", line 153, in get_containing_segments
    if 'LOAD' not in seg['p_type'] and seg['p_filesz'] == 0:
TypeError: argument of type 'int' is not iterable
```
versions are:

```
pwndbg> version
Gdb:      9.1
Python:   3.8.2 (default, Apr 27 2020, 15:53:34)  [GCC 9.3.0]
Pwndbg:   1.1.0 build: 609284c
Capstone: 4.0.1024
Unicorn:  1.0.2
```
my system:

```
$ uname -a
Linux ubuntu2004.localdomain 5.4.0-29-generic #33-Ubuntu SMP Wed Apr 29 14:32:27 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/issue
Ubuntu 20.04 LTS \n \l
```
more information from `bugreport --run-browser`:

```
Gdb session history:
start
p printf
xinfo 0x7ffff7e33e10
set exception-verbose on
xinfo 0x7ffff7e33e10

Platform: Linux-5.4.0-29-generic-x86_64-with-glibc2.29
Gdb:      9.1
Python:   3.8.2 (default, Apr 27 2020, 15:53:34)  [GCC 9.3.0]
Pwndbg:   1.1.0 build: 609284c
Capstone: 4.0.1024
Unicorn:  1.0.2
This GDB was configured as follows:
   configure --host=x86_64-linux-gnu --target=x86_64-linux-gnu
             --with-auto-load-dir=$debugdir:$datadir/auto-load
             --with-auto-load-safe-path=$debugdir:$datadir/auto-load
             --with-expat
             --with-gdb-datadir=/usr/share/gdb (relocatable)
             --with-jit-reader-dir=/usr/lib/gdb (relocatable)
             --without-libunwind-ia64
             --with-lzma
             --with-babeltrace
             --without-intel-pt
             --with-mpfr
             --without-xxhash
             --with-python=/usr (relocatable)
             --without-guile
             --disable-source-highlight
             --with-separate-debug-dir=/usr/lib/debug (relocatable)
             --with-system-gdbinit=/etc/gdb/gdbinit
```
I also attached the file I used: [relocoverwrite.zip](https://github.com/pwndbg/pwndbg/files/4740908/relocoverwrite.zip)

Best
Martin




Discussion:
@martinclauss Hey, I can't reproduce it even with your binary, at least on GDB 8.1. I will try on 9.x, though it seems like it is a bug within pwndbg :F.
Hi! It seems that it is depending on the address whether it crashes or not. `xinfo <address of main>` works without any problems...
It also seems that it effects Ubuntu 19.10 (gdb 8.3) as well..:

## Ubuntu 18.04 WORKS

```
pwndbg: loaded 177 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)

Temporary breakpoint 1 at 0x1090

Temporary breakpoint 1, 0x0000555555555090 in main ()
Extended information for virtual address 0x7ffff7a48e80:

  Containing mapping:
    0x7ffff79e4000     0x7ffff7bcb000 r-xp   1e7000 0      /lib/x86_64-linux-gnu/libc-2.27.so

  Offset information:
         Mapped Area 0x7ffff7a48e80 = 0x7ffff79e4000 + 0x64e80
         File (Base) 0x7ffff7a48e80 = 0x7ffff79e4000 + 0x64e80
      File (Segment) 0x7ffff7a48e80 = 0x7ffff79e4000 + 0x64e80
         File (Disk) 0x7ffff7a48e80 = /lib/x86_64-linux-gnu/libc-2.27.so + 0x64e80

 Containing ELF sections:
               .text 0x7ffff7a48e80 = 0x7ffff7a052d0 + 0x43bb0
Gdb:      8.1.0.20180409-git
Python:   3.6.9 (default, Apr 18 2020, 01:56:04)  [GCC 8.4.0]
Pwndbg:   1.1.0 build: 606eae0
Capstone: 4.0.1024
Unicorn:  1.0.1
```

## Ubuntu 19.10 EXCEPTION

```
pwndbg: loaded 178 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Temporary breakpoint 1 at 0x1090

Temporary breakpoint 1, 0x0000555555555090 in main ()
Extended information for virtual address 0x7ffff7e38d70:

  Containing mapping:
    0x7ffff7df9000     0x7ffff7f71000 r-xp   178000 25000  /usr/lib/x86_64-linux-gnu/libc-2.30.so

  Offset information:
         Mapped Area 0x7ffff7e38d70 = 0x7ffff7df9000 + 0x3fd70
         File (Base) 0x7ffff7e38d70 = 0x7ffff7dd4000 + 0x64d70
'xinfo': Shows offsets of the specified address to useful other locations
Traceback (most recent call last):
  File "/opt/pwndbg/pwndbg/commands/__init__.py", line 136, in __call__
    return self.function(*args, **kwargs)
  File "/opt/pwndbg/pwndbg/commands/__init__.py", line 227, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/opt/pwndbg/pwndbg/commands/xinfo.py", line 126, in xinfo
    xinfo_mmap_file(page, addr)
  File "/opt/pwndbg/pwndbg/commands/xinfo.py", line 72, in xinfo_mmap_file
    containing_loads = [seg for seg in pwndbg.elf.get_containing_segments(file_name, first.vaddr, addr)
  File "/opt/pwndbg/pwndbg/elf.py", line 153, in get_containing_segments
    if 'LOAD' not in seg['p_type'] and seg['p_filesz'] == 0:
TypeError: argument of type 'int' is not iterable

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
Gdb:      8.3
Python:   3.7.5 (default, Apr 19 2020, 20:18:17)  [GCC 9.2.1 20191008]
Pwndbg:   1.1.0 build: 606eae0
Capstone: 4.0.1024
Unicorn:  1.0.1
```

## Ubuntu 20.04 EXCEPTION

```
pwndbg: loaded 178 commands. Type pwndbg [filter] for a list.
pwndbg: created $rebase, $ida gdb functions (can be used with print/break)
Temporary breakpoint 1 at 0x1090

Temporary breakpoint 1, 0x0000555555555090 in main ()
Extended information for virtual address 0x7ffff7e36e10:

  Containing mapping:
    0x7ffff7df7000     0x7ffff7f6f000 r-xp   178000 25000  /usr/lib/x86_64-linux-gnu/libc-2.31.so

  Offset information:
         Mapped Area 0x7ffff7e36e10 = 0x7ffff7df7000 + 0x3fe10
         File (Base) 0x7ffff7e36e10 = 0x7ffff7dd2000 + 0x64e10
'xinfo': Shows offsets of the specified address to useful other locations
Traceback (most recent call last):
  File "/opt/pwndbg/pwndbg/commands/__init__.py", line 136, in __call__
    return self.function(*args, **kwargs)
  File "/opt/pwndbg/pwndbg/commands/__init__.py", line 227, in _OnlyWhenRunning
    return function(*a, **kw)
  File "/opt/pwndbg/pwndbg/commands/xinfo.py", line 126, in xinfo
    xinfo_mmap_file(page, addr)
  File "/opt/pwndbg/pwndbg/commands/xinfo.py", line 72, in xinfo_mmap_file
    containing_loads = [seg for seg in pwndbg.elf.get_containing_segments(file_name, first.vaddr, addr)
  File "/opt/pwndbg/pwndbg/elf.py", line 153, in get_containing_segments
    if 'LOAD' not in seg['p_type'] and seg['p_filesz'] == 0:
TypeError: argument of type 'int' is not iterable

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
Gdb:      9.1
Python:   3.8.2 (default, Apr 27 2020, 15:53:34)  [GCC 9.3.0]
Pwndbg:   1.1.0 build: 606eae0
Capstone: 4.0.1024
Unicorn:  1.0.1
```
I wrote a little shell script and Dockerfile that makes the testing a bit easier:

`run_containers.sh`:

```shell
#!/usr/bin/env bash

for image in 'ubuntu:18.04' 'ubuntu:19.10' 'ubuntu:20.04' 
do
	temp_docker_file=$(tempfile)
	sed -e "s/@image/$image/" Dockerfile > $temp_docker_file
	sudo docker build -t "pwndbg_test_${image}" - < $temp_docker_file 
	sudo docker run --rm -v$(pwd)/relocoverwrite:/test/binary:Z --cap-add=SYS_PTRACE "pwndbg_test_${image}"
	rm -f $temp_docker_file
	echo "check the output and press Enter to continue"
	read foo
done
```

`Dockerfile`:

```docker
FROM @image

RUN apt-get update && \
    DEBIAN_FRONTEND=noninteractive apt-get upgrade -y && \
    DEBIAN_FRONTEND=noninteractive apt-get install -y git

RUN cd /opt && \
    git clone https://github.com/pwndbg/pwndbg && \
    cd pwndbg && \
    DEBIAN_FRONTEND=noninteractive ./setup.sh

CMD printf_address=$(gdb -ex "start" -ex "p printf" -batch /test/binary | grep printf | grep -Po "0x[a-f0-9]+"); gdb -ex "set exception-verbose on" -ex "start" -ex "xinfo ${printf_address}" -ex "version" -batch /test/binary
```
Here is a zipped version of all the files: [pwndbg_xinfo_test.zip](https://github.com/pwndbg/pwndbg/files/4741585/pwndbg_xinfo_test.zip)
@martinclauss Thanks a lot for reproducible case! I will check this out.
Weird, it seems this might be a bug in `elftools`. This is on Ubuntu 20.04:
```
(Pdb) [i.header['p_type'] for i in ELFFile(open('/usr/lib/x86_64-linux-gnu/libc-2.31.so', 'rb')).iter_segments()]
['PT_PHDR', 'PT_INTERP', 'PT_LOAD', 'PT_LOAD', 'PT_LOAD', 'PT_LOAD', 'PT_DYNAMIC', 'PT_NOTE', 'PT_NOTE', 'PT_TLS', 1685382483, 'PT_GNU_EH_FRAME', 'PT_GNU_STACK', 'PT_GNU_RELRO']
```

For some reasosn, one of the `p_type` has a value of `1685382483`.

On Ubuntu 18.04:
```
root@56fe55a4ae84:/test# python3
Python 3.6.9 (default, Apr 18 2020, 01:56:04)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from elftools.elf.elffile import ELFFile
>>> [i.header['p_type'] for i in ELFFile(open('/lib/x86_64-linux-gnu/libc-2.27.so', 'rb')).iter_segments()]
['PT_PHDR', 'PT_INTERP', 'PT_LOAD', 'PT_LOAD', 'PT_DYNAMIC', 'PT_NOTE', 'PT_TLS', 'PT_GNU_EH_FRAME', 'PT_GNU_STACK', 'PT_GNU_RELRO']```
```
root@e4eca15a3839:/test# readelf --segments /usr/lib/x86_64-linux-gnu/libc-2.31.so

Elf file type is DYN (Shared object file)
Entry point 0x271f0
There are 14 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000000040 0x0000000000000040
                 0x0000000000000310 0x0000000000000310  R      0x8
  INTERP         0x00000000001c16a0 0x00000000001c16a0 0x00000000001c16a0
                 0x000000000000001c 0x000000000000001c  R      0x10
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000024940 0x0000000000024940  R      0x1000
  LOAD           0x0000000000025000 0x0000000000025000 0x0000000000025000
                 0x0000000000177434 0x0000000000177434  R E    0x1000
  LOAD           0x000000000019d000 0x000000000019d000 0x000000000019d000
                 0x0000000000049d45 0x0000000000049d45  R      0x1000
  LOAD           0x00000000001e7600 0x00000000001e8600 0x00000000001e8600
                 0x0000000000005010 0x0000000000008ed8  RW     0x1000
  DYNAMIC        0x00000000001e9b80 0x00000000001eab80 0x00000000001eab80
                 0x00000000000001e0 0x00000000000001e0  RW     0x8
  NOTE           0x0000000000000350 0x0000000000000350 0x0000000000000350
                 0x0000000000000020 0x0000000000000020  R      0x8
  NOTE           0x0000000000000370 0x0000000000000370 0x0000000000000370
                 0x0000000000000044 0x0000000000000044  R      0x4
  TLS            0x00000000001e7600 0x00000000001e8600 0x00000000001e8600
                 0x0000000000000010 0x0000000000000090  R      0x8
  GNU_PROPERTY   0x0000000000000350 0x0000000000000350 0x0000000000000350
                 0x0000000000000020 0x0000000000000020  R      0x8
  GNU_EH_FRAME   0x00000000001c16bc 0x00000000001c16bc 0x00000000001c16bc
                 0x0000000000005ec4 0x0000000000005ec4  R      0x4
  GNU_STACK      0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x0000000000000000 0x0000000000000000  RW     0x10
  GNU_RELRO      0x00000000001e7600 0x00000000001e8600 0x00000000001e8600
                 0x0000000000002a00 0x0000000000002a00  R      0x1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .note.gnu.property .note.gnu.build-id .note.ABI-tag .hash .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_d .gnu.version_r .rela.dyn .rela.plt
   03     .plt .plt.got .plt.sec .text __libc_freeres_fn
   04     .rodata .stapsdt.base .interp .eh_frame_hdr .eh_frame .gcc_except_table
   05     .tdata .init_array .data.rel.ro .dynamic .got .got.plt .data __libc_subfreeres __libc_IO_vtables __libc_atexit .bss __libc_freeres_ptrs
   06     .dynamic
   07     .note.gnu.property
   08     .note.gnu.build-id .note.ABI-tag
   09     .tdata .tbss
   10     .note.gnu.property
   11     .eh_frame_hdr
   12
   13     .tdata .init_array .data.rel.ro .dynamic .got
root@e4eca15a3839:/test#
```
According to the paste above and to the order in here:
> `['PT_PHDR', 'PT_INTERP', 'PT_LOAD', 'PT_LOAD', 'PT_LOAD', 'PT_LOAD', 'PT_DYNAMIC', 'PT_NOTE', 'PT_NOTE', 'PT_TLS', 1685382483, 'PT_GNU_EH_FRAME', 'PT_GNU_STACK', 'PT_GNU_RELRO']`

It seems the pyelftools library doesn't know about the `GNU_PROPERTY` segment which has a value of 1685382483.  
Yeah, this is a missing value on the pyelftools side, but also, we should probably not fail when elftools misses one of the segment values.

I sent a patch to pyelftools here: https://github.com/eliben/pyelftools/pull/319.

Resolving patch:
diff --git a/pwndbg/elf.py b/pwndbg/elf.py
--- a/pwndbg/elf.py
+++ b/pwndbg/elf.py
@@ -149,8 +149,9 @@ def get_containing_segments(elf_filepath, elf_loadaddr, vaddr):
     elf = get_elf_info_rebased(elf_filepath, elf_loadaddr)
     segments = []
     for seg in elf.segments:
-        # disregard non-LOAD segments that are not file-backed (typically STACK)
-        if 'LOAD' not in seg['p_type'] and seg['p_filesz'] == 0:
+        # disregard segments which were unable to be named by pyelftools (see #777)
+        # and non-LOAD segments that are not file-backed (typically STACK)
+        if isinstance(seg['p_type'], int) or ('LOAD' not in seg['p_type'] and seg['p_filesz'] == 0):
             continue
         # disregard segments not containing vaddr
         if vaddr < seg['p_vaddr'] or vaddr >= seg['x_vaddr_mem_end']:


Test patch: