Search code examples
linuxdebugginggdblldbcoredump

Debug core file with LLDB without executable, but with debug symbols file


I have a core dump file that needs to be debugged. But the only file that I have for crashed program is a debug symbols file

Exec and debug file were generated with:

$ gcc -g -O0 -o <exec> main.c
$ objcopy --only-keep-debug <exec> <exec>.dbg
$ strip --strip-debug --strip-unneeded <exec>

When I'm running lldb with my core file as a target and trying to add symbols file, lldb gives me an error:

$ lldb -c <core-file>
(lldb) target symbols add <exec>.dbg
error: symbol file '<exec>.dbg' does not match any existing module

Then, I tried to add module with my .dbg file and only then add it as symfile. No errors this time, but still no symbols was added -- bt gives me only 1 frame in 1 thread, and I can't see any code in gui mode

$ lldb -c <core-file>
(lldb) target modules add <exec>.dbg
(lldb) target symbols add <exec>.dbg

My questions are:

Firstly, I've barely found any information about what is lldb "module"

Secondly, I don't understand why lldb needs any information besides my core and debug files. Core file has snapshot of the memory, and debug file has all the symbols that can help parse core file contents to "human-readable" form.

Lastly, is it even possible to debug core file with symbols, but without executable? If it isn't in lldb, maybe there is a way in gdb or other debbuger? Or, maybe I generated debug file incorrectly?


Solution

  • maybe there is a way in gdb or other debbuger?

    This worked for me:

    gdb -q a.dbg core
    Reading symbols from a.dbg...
    
    warning: core file may not match specified executable file.
    
    Core was generated by `./a.out'.
    Program terminated with signal SIGABRT, Aborted.
    #0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
    50        return ret;
    
    (gdb) bt
    #0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
    #1  0x00007fcad7676797 in __GI_abort () at abort.c:79
    #2  0x0000000000203af9 in foo () at main.c:5
    #3  0x00007ffe54685830 in ?? ()
    #4  0x0000000000203b14 in main () at main.c:10
    

    Update: Here are the exact steps I took:

    // t.c
    #include <stdlib.h>
    
    int foo() {
      abort();
    }
    
    int main()
    {
      return foo();
    }
    
    // t.sh
    #!/bin/bash
    ulimit -c unlimited
    gcc -g t.c &&
    objcopy --only-keep-debug a.out a.dbg &&
    strip --strip-debug --strip-unneeded a.out
    
    ./a.out
    rm -f a.out
    
    gdb -q a.dbg core
    

    Note: even though there is a somewhat reasonable stack, it is not correct: frame#3 does not really exist.

    In general, note that you are doing it wrong -- the debugger does need access to the code, not just debug symbols to unwind the stack (though I am not sure of the exact details of why that is).

    You should either preserve the original (unstripped) a.out, or preserve both the stripped a.out and a.dbg.