gdbx86-64binaryfileselfcore-file

How can I edit $rip and $rsp in a core file to help a debugger generate a more user friendly expereince?


I am currently attempting to debug a crash of a c++ application that corrupted the stack. After some investigation I am very sure I know valid $rsp and $rip address that correspond to a very useful frame on the stack that should be uncorrupted.

It would be incredibly useful to be able to use all of gdb's built-in features for dealing with dynamically addressed calls when it has a valid stack. Unfortunately gdb cannot set these register values directly when debugging a core file, and I have found a feature request literally a decade old asking for this functionality.

Is there some way to edit the core file directly to set these values? Or does lldb potentially allow you to override these register values when debugging a core file?


Solution

  • Is there some way to edit the core file directly to set these values?

    Sure -- the values are stored in the core somewhere; the trick is finding out where exactly.

    The register values are stored in the PRSTATUS notes (the first such note is usually the one corresponding to the crashing thread).

    You can examine the notes from your existing core with elfutils eu-readelf -Wn core. The output will look similar to:

    Note segment of 5200 bytes at offset 0x580:
      Owner          Data size  Type
      CORE                 336  PRSTATUS
        info.si_signo: 3, info.si_code: 0, info.si_errno: 0, cursig: 3
        sigpend: <>
        sighold: <>
        pid: 4174783, ppid: 140563, pgrp: 4174783, sid: 140563
        utime: 0.000000, stime: 0.000000, cutime: 0.000000, cstime: 0.000000
        orig_rax: 230, fpvalid: 1
        r15:         140725686367064  r14:                       1
        r13:         140725686367064  r12:         140725686366544
        rbp:      0x00007ffd408bf190  rbx:                      60
        r11:                     514  r10:         140725686366608
        r9:                        0  r8:                        0
        rax:                    -516  rcx:         139740173005747
        rdx:         140725686366544  rsi:                       0
        rdi:                       0  rip:      0x00007f17cb5f73b3
        rflags:   0x0000000000000202  rsp:      0x00007ffd408bf138
        fs.base:   0x00007f17cb525740  gs.base:   0x0000000000000000
        cs: 0x0033  ss: 0x002b  ds: 0x0000  es: 0x0000  fs: 0x0000  gs: 0x0000
    

    Here you can see that the Note is at offset 0x580, and the rsp register is somewhere within it.

    From here, you can use offsetof(struct elf_prstatus, pr_reg) (112 on x86_64), and offsetof(struct user_regs_struct, rsp) (152).

    If my arithmetic is correct, the value of rsp should be at 0x580 + 20 + 112 + 152. Let's check this:

    xxd -e -s $((0x580+20+112+152)) -g8 core | head -1
    0000069c: 00007ffd408bf138 000000000000002b  8..@....+.......
    

    So overwriting the 8-byte value at offset 0x69c into this core should produce desired result.

    P.S. Where did the extra 20 come from? The Elf64_Nhdr has a few data items before the note data starts: n_namesz, n_descsz, n_type (each 4 bytes), followed by note name (CORE\0 here), rounded up to 4-byte boundary (so 8 bytes total).