Unwind method using CFI in core dump sections?

Ben Cohen ben_c@tiscali.co.uk
Thu May 30 12:29:00 GMT 2013


I have found that it is possible to identify the DWARF Call Frame 
Information (CFI) if it is available in a core dump, as described 
below.  It would be useful to add a new unwind method in gdb to do this 
so that it is possible to analyse core dumps for which the shared 
libraries are not available.  (I don't know anything about gdb 
internals though.)


If you have a core dump from a system with 
different glibc and other library versions then gdb is likely to show 
corrupted stack traces unless you have a copy of those libraries, which 
contain CFI to tell the debugger how to unwind the stack, and set solib-
search-path.  Unfortunately it's not always easy or possible to obtain 
a copy of the libraries, for example if they are on customer systems to 
which we don't have access.

Actually the CFI is present in the library 
in the process's memory image, because C++ uses it to unwind when 
processing exceptions.  Unfortunately these segments aren't typically 
put into a core file, but they could be.  

On Linux since 2.6.28, 
"echo 127 > /proc/PID/coredump_filter" will tell the kernel to dump 
other memory mapping types including the library segments, but it does 
not by default.  (My employer, Kognitio, has a custom core file 
generator that also dumps these segments.  Of course, doing this makes 
core files larger.)

Given such a core file, gdb could infer the CFI 
and use that to unwind when there is no library available.  Of course, 
just as when using stripped libraries the frames won't have symbols, 
but the frame addresses and registers are correct.  This would 
presumably be a bit like using __jit_debug_descriptor for JIT/runtime-
generated code but a bit more difficult.

To show that this is actually 
possible, below is a program I wrote for 32-bit x86 Linux.  I 
frequently use it to generate stub libraries containing CFI that gdb 
can then use to obtain correct stack traces for a core file without 
having the appropriate libraries.  It is somewhat fragile, partly 
because it tries to guess the library names, which gdb presumably 
wouldn't have to.

It works for glibc and other libraries (but not for 
really old library versions without CFI) including the example C 
program and asm library below.

Thanks,
Ben.



Example session using 
wxcoretool:

[ubuntu tmp]$ gcc -o wxcoretool wxcoretool.c -Wall
[ubuntu 
tmp]$ gcc -Wl,-soname,library.so -shared -fPIC -o library.so library.S

[ubuntu tmp]$ gcc -ggdb -o frametest frametest.c library.so
[ubuntu 
tmp]$ echo 127 > /proc/self/coredump_filter
[ubuntu tmp]$ ulimit -c 
unlimited
[ubuntu tmp]$ LD_LIBRARY_PATH=. ./frametest
Trace/breakpoint 
trap (core dumped)
[ubuntu tmp]$ gdb frametest core --ex backtrace --ex 
quit
GNU gdb (GDB) 7.5-ubuntu
Copyright (C) 2012 Free Software 
Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.

There is NO WARRANTY, to the extent permitted by law.  Type "show 
copying"
and "show warranty" for details.
This GDB was configured as 
"i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from 
/tmp/tmp/frametest...done.
[New LWP 2856]
Core was generated by `.
/frametest'.
Program terminated with signal 5, Trace/breakpoint trap.

#0  0xb77d04fd in library_function () from ./library.so
#0  0xb77d04fd 
in library_function () from ./library.so
#1  0x08048564 in f2 (x=2, 
y=98 'b') at frametest.c:11
#2  0x0804858e in f1 (x=1, y=97 'a') at 
frametest.c:16
#3  0x080485ad in main () at frametest.c:21
[ubuntu 
tmp]$ rm library.so
[ubuntu tmp]$ gdb frametest core --ex backtrace --
ex quit
GNU gdb (GDB) 7.5-ubuntu
Copyright (C) 2012 Free Software 
Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.

There is NO WARRANTY, to the extent permitted by law.  Type "show 
copying"
and "show warranty" for details.
This GDB was configured as 
"i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from 
/tmp/tmp/frametest...done.
[New LWP 2856]

warning: Could not load 
shared library symbols for ./library.so.
Do you need "set solib-search-
path" or "set sysroot"?
Core was generated by `./frametest'.
Program 
terminated with signal 5, Trace/breakpoint trap.
#0  0xb77d04fd in 
?? ()
#0  0xb77d04fd in ?? ()
[ubuntu tmp]$ ./wxcoretool -f. core

Creating stub library libc.so.6
Creating stub library library.so

Creating stub library library.so
Failed to open file
Creating stub 
library libunknown_14
[ubuntu tmp]$ gdb --ex 'set solib-search-path 
lib' \
>     --ex 'set sysroot .' \
>     --ex 'file frametest' \
>     
--ex 'core core' \
>     --ex backtrace \
>     --ex quit
GNU gdb (GDB) 
7.5-ubuntu
Copyright (C) 2012 Free Software Foundation, Inc.
License 
GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.

There is NO WARRANTY, to the extent permitted by law.  Type "show 
copying"
and "show warranty" for details.
This GDB was configured as 
"i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.Reading symbols from 
/tmp/tmp/frametest...done.
[New LWP 2856]
Core was generated by `.
/frametest'.
Program terminated with signal 5, Trace/breakpoint trap.

#0  0xb77d04fd in ?? ()
#0  0xb77d04fd in ?? ()
#1  0x08048564 in f2 
(x=2, y=98 'b') at frametest.c:11
#2  0x0804858e in f1 (x=1, y=97 'a') 
at frametest.c:16
#3  0x080485ad in main () at frametest.c:21




##########################################################################

# library: example library with Call Frame Information
# 
# Compile 
using:
#     gcc -Wl,-soname,library.so -shared -fPIC -o library.so 
library.S 
#
        .text
.globl library_function
        .type   
library_function, @function
library_function:
        .cfi_startproc

        push    %ebp
        .cfi_def_cfa_offset 8
        .cfi_offset %
ebp, -8
        mov     $0x0, %ebp
        sub     $0x80000000,%esp

        .cfi_adjust_cfa_offset  0x80000000
        int     $0x03

        add     $0x80000000,%esp
        .cfi_adjust_cfa_offset  -0
x80000000
        pop     %ebp
        ret
        .cfi_endproc
        
.size   library_function, .-library_function
        .section        .
note.GNU-stack,"",@progbits




/**************************************************************************

 * frametest: example program
 *
 * Compile using:
 *     gcc -ggdb -o 
frametest frametest.c library.so
 */
void library_function(int x, char 
y);

int f2(int x, char y)
{
  library_function(x + 1, y + 1);
}

int f1
(int x, char y)
{
  f2(x + 1, y + 1);
}

int main()
{
  f1(1, 'a');
}





/**************************************************************************

 * wxcoretool: Generate stub libraries with CFI for 32-bit i386 Linux 
corefiles
 *
 * Copyright (C) 2010-2013 Ben Cohen / Kognitio Ltd.
 *
 * 
This program is free software; you can redistribute it and/or modify
 * 
it under the terms of the GNU General Public License as published by
 * 
the Free Software Foundation; either version 3 of the License, or
 * 
(at your option) any later version.
 * 
 * This program is distributed 
in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; 
without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR 
A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more 
details.
 *
 * Compile using:
 *     gcc -o wxcoretool wxcoretool.c -
Wall
 * Run using:
 *     wxcoretool -f <target-dir> <core-file>
 *     
gdb --ex 'set solib-search-path <target-dir>/lib' \
 *         --ex 
'set sysroot <target-dir>' \
 *         --ex 'file <exec-file>' \
 
*         --ex 'core <core-file>'
 */

#define _GNU_SOURCE
#include 
<sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include 
<stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>
#include <ctype.h>
#include <errno.h>

#include 
<elf.h>


int debug = 0;

void check(bool cond, char *msg)
{
    if (!
cond)
    {
        fprintf(stderr, "%s", msg);
        exit(1);
    
}    
}

void *xmalloc(int size)
{
    void *ret = malloc(size);

    
check(ret != NULL, "malloc() failed");
    return ret;
}


void readat
(int fd, void *buf, size_t count, size_t offset)
{
    size_t ret;
    
size_t bytes_read = 0;

    ret = lseek(fd, offset, SEEK_SET);
    check
(offset == ret, "lseek() failed\n");

    while (bytes_read < count)

    {
        ret = read(fd, buf + bytes_read, count - bytes_read);

        check(ret > 0, "read() failed\n");
        bytes_read += ret;

    }
}

bool memreadat(char *segment, int segsz, void *buf, size_t 
count, size_t offset)
{
    if (count + offset > segsz)
        return 
false;
    memcpy(buf, segment + offset, count);
    return true;
}



/* We create a stub library.  This is more complicated than the minimal 
ELF
 * library, but GDB is a little fussy. */
void CreateStubLibrary
(char *libname, int eh_frame_offset, 
                       char 
*eh_frame, int eh_frame_len,
                       int LoadOffset)
{

    int libfd;
    int nSecs = 3;
    Elf32_Ehdr ElfHeader;
    
Elf32_Phdr ProgHeader;
    Elf32_Shdr SecHeader[nSecs];
    int EHSize 
= sizeof(Elf32_Ehdr);
    int PHSize = sizeof(Elf32_Phdr);
    int 
SHSize = sizeof(Elf32_Shdr);
    char *eh_frame_str = ".eh_frame";
    
char *shstrtab_str = ".shstrtab";
    int eh_frame_strlen = strlen
(eh_frame_str) + 1;
    int shstrtab_strlen = strlen(shstrtab_str) + 1;

    int shstrtab_offset = eh_frame_offset + eh_frame_len;
    int 
shstrtab_len = eh_frame_strlen + shstrtab_strlen;
    int EH_offset = 
shstrtab_offset + shstrtab_len;
    int rc;

    printf("Creating stub 
library %s\n", libname);
    libfd = open(libname, O_WRONLY|O_CREAT, 
0555);
    if (libfd < 0)
    {
        printf("Failed to open 
file\n");
        return;
    }

    /* Write the ELF header */
    
memset(&ElfHeader, 0, EHSize);

    ElfHeader.e_ident[0] = ELFMAG0;
    
ElfHeader.e_ident[1] = ELFMAG1;
    ElfHeader.e_ident[2] = ELFMAG2;
    
ElfHeader.e_ident[3] = ELFMAG3;
    ElfHeader.e_ident[4] = ELFCLASS32;

    ElfHeader.e_ident[5] = ELFDATA2LSB;
    ElfHeader.e_ident[6] = 
EV_CURRENT;
    ElfHeader.e_type = ET_DYN;
    ElfHeader.e_machine = 
EM_386;
    ElfHeader.e_version = EV_CURRENT;
    ElfHeader.e_entry = 
0;
    ElfHeader.e_phoff = EHSize;
    ElfHeader.e_shoff = EH_offset;

    ElfHeader.e_flags = 0;
    ElfHeader.e_ehsize = EHSize;
    
ElfHeader.e_phentsize = PHSize;
    ElfHeader.e_phnum = 1;
    
ElfHeader.e_shentsize = SHSize;
    ElfHeader.e_shnum = nSecs;
    
ElfHeader.e_shstrndx = 2;

    rc = write(libfd, &ElfHeader, EHSize);

    if (rc != EHSize)
    {
        printf("Failed to write to 
file\n");
        close(libfd);
        return;
    }

    /* Write the 
program header */
    memset(&ProgHeader, 0, PHSize);

    ProgHeader.
p_type = PT_LOAD;
    ProgHeader.p_offset = 0;
    ProgHeader.p_vaddr = 
LoadOffset;
    ProgHeader.p_paddr = LoadOffset;
    ProgHeader.
p_filesz = EH_offset;
    ProgHeader.p_memsz = ProgHeader.p_filesz;
    
ProgHeader.p_flags = PF_X | PF_R;
    ProgHeader.p_align = 0x1000;

    
rc = write(libfd, &ProgHeader, PHSize * 1);
    if (rc != PHSize * 1)

    {
        printf("Failed to write to file\n");
        close
(libfd);
        return;
    }

    /* Write the .eh_frame section at 
its original location */
    check(eh_frame_offset > EHSize + PHSize * 
1, "eh_frame_offset too small\n");
    rc = lseek(libfd, 
eh_frame_offset, SEEK_SET);
    if (rc != eh_frame_offset)
    {

        printf("Failed to seek\n");
        close(libfd);
        
return;
    }
    rc = write(libfd, eh_frame, eh_frame_len);
    if (rc 
!= eh_frame_len)
    {
        printf("Failed to write to file\n");

        close(libfd);
        return;
    }

    /* Write the section 
string table, .shstrtab */
    rc = write(libfd, shstrtab_str, 
shstrtab_strlen);
    if (rc != shstrtab_strlen)
    {
        printf
("Failed to write to file\n");
        close(libfd);
        return;

    }
    rc = write(libfd, eh_frame_str, eh_frame_strlen);
    if (rc !
= eh_frame_strlen)
    {
        printf("Failed to write to file\n");

        close(libfd);
        return;
    }

    /* Write the section 
headers */
    memset(&SecHeader, 0, SHSize * nSecs);

    SecHeader[0].
sh_name = shstrtab_strlen - 1;
    SecHeader[0].sh_type = 
SHT_NULL;          /* First one: empty */

    SecHeader[1].sh_name = 
shstrtab_strlen;   /* Third one: .eh_frame */
    SecHeader[1].sh_type 
= SHT_PROGBITS;
    SecHeader[1].sh_flags = SHF_ALLOC;
    SecHeader[1].
sh_addr = eh_frame_offset + LoadOffset;
    SecHeader[1].sh_offset = 
eh_frame_offset;
    SecHeader[1].sh_size = eh_frame_len;
    SecHeader
[1].sh_link = 0;
    SecHeader[1].sh_info = 0;
    SecHeader[1].
sh_addralign = 4;
    SecHeader[1].sh_entsize = 0;

    SecHeader[2].
sh_name = 0;                 /* Second one: .shstrtab */
    SecHeader
[2].sh_type = SHT_STRTAB;
    SecHeader[2].sh_flags = 0;
    SecHeader
[2].sh_addr = 0;
    SecHeader[2].sh_offset = shstrtab_offset;
    
SecHeader[2].sh_size = shstrtab_len;
    SecHeader[2].sh_link = 0;
    
SecHeader[2].sh_info = 0;
    SecHeader[2].sh_addralign = 1;
    
SecHeader[2].sh_entsize = 0;

    rc = write(libfd, &SecHeader, SHSize 
* nSecs);
    if (rc != SHSize * nSecs)
    {
        printf("Failed to 
write to file\n");
        close(libfd);
        return;
    }

    
close(libfd);
}

bool ProcessEhFrameHdr(char *segment, int size, char 
*eh_frame_hdr, int ehsize,
                       char *libname, int 
LoadOffset)
{
    signed int eh_frame_ptr;
    int fde_count;
    char 
*eh_frame;
    int eh_frame_len;
    char *eh_frame_end;
    int 
fdes_counted;

    if (debug)
    {
        printf("Object eh_frame_hdr:
\n");
        printf("    version:            %d\n", eh_frame_hdr[0]);

        printf("    eh_frame_ptr_enc:   %d\n", eh_frame_hdr[1]);

        printf("    fde_count_enc:      %d\n", eh_frame_hdr[2]);

        printf("    table_enc:          %d\n", eh_frame_hdr[3]);
    }

    if (eh_frame_hdr[0] != 1)
    {
        if (debug)
            
printf("Bad eh_frame_hdr version\n");
        return 0;
    }

    /* 
XXX I can't be bothered to implement them all unless necessary */
    
check((eh_frame_hdr[1] & 0xF0) == 0x10, "eh_frame_ptr not relative to 
pc\n");
    check((eh_frame_hdr[1] & 0x0F) == 0x0b, "eh_frame_ptr not 
signed int\n");
    check(eh_frame_hdr[2] == 0x03, "fde_count_enc not 
unsigned int\n");
    eh_frame_ptr = ((int *)eh_frame_hdr)[1];
    
fde_count = ((int *)eh_frame_hdr)[2];
    if (fde_count == 0)
    {

        if (debug)
            printf("No fde search table\n");
        
return 0;
    }
    
    eh_frame = eh_frame_hdr + eh_frame_ptr + 4;

    if (debug)
    {
        printf("    eh_frame_ptr:       %d\n", 
eh_frame_ptr);
        printf("    eh_frame:           %d\n", eh_frame 
- segment);
        printf("    fde_count:          %d\n", fde_count);

    }
    check(eh_frame <= segment + size, "eh_frame not in 
segment\n");
    
    /* Frame length is that of all the FDEs plus a 
zero int at the end */
    fdes_counted = 0;
    eh_frame_end = 
eh_frame; 
    while (((int *)eh_frame_end)[0] != 0 && fdes_counted < 
fde_count)
    {
        if (((int *)eh_frame_end)[1] != 0)
        {

            fdes_counted ++;
            if (debug)
            {

                printf("    FDE:                %d at %d\n",

                       ((int *)eh_frame_end)[0],
                       
eh_frame_end - segment);
            }
        }
        else
        {

            if (debug)
            {
                printf("    
CIE:                %d at %d\n",
                       ((int *)
eh_frame_end)[0],
                       eh_frame_end - segment);

            }
        }
        eh_frame_end += ((int *)eh_frame_end)
[0] + 4;
        check(eh_frame_end <= segment + size, "eh_frame not in 
segment\n");
    }
    eh_frame_end += 4;
    check(eh_frame_end <= 
segment + size, "eh_frame not in segment\n");
 
    eh_frame_len = 
eh_frame_end - eh_frame;

    if (debug)
    {
        printf("    
eh_frame_end:       %d\n", eh_frame_end - segment);
        printf("    
eh_frame_len:       %d\n", eh_frame_len);
        printf("    
fdes_counted:       %d\n", fdes_counted);
    }

    if (strncmp
(libname, "ld-linux.so", 11) != 0)
    {
        CreateStubLibrary
(libname, eh_frame - segment, eh_frame, eh_frame_len,

                          LoadOffset);
    }
    else
    {
        if 
(debug)
        {
            printf("Not creating stub library for %
s\n", libname);
        }
    }
        
    return 1;
}

void 
ProcessObject(char *segment, int size, char *libname)
{
    Elf32_Ehdr 
ElfHeader;
    int PHOffset, PHCount;
    Elf32_Phdr ProgHeader;
    
bool ret;
    int i;
    int LoadOffset = 0;
    int EhFrameOffset = 0;

    int EhFrameSize = 0;

    ret = memreadat(segment, size, (void *)
&ElfHeader, sizeof(ElfHeader), 0);
    if (!ret)
        return;
    if 
(debug)
    {
        printf("Object ELF Header:\n");
        printf
("    e_ident:        %.16s\n", ElfHeader.e_ident);
        printf("    
e_type:         %d\n", ElfHeader.e_type);
        printf("    
e_machine:      %d\n", ElfHeader.e_machine);
        printf("    
e_version:      %d\n", ElfHeader.e_version);
        printf("    
e_entry:        %d\n", ElfHeader.e_entry);
        printf("    
e_phoff:        %d\n", ElfHeader.e_phoff);
        printf("    
e_shoff:        %d\n", ElfHeader.e_shoff);
        printf("    
e_flags:        %d\n", ElfHeader.e_flags);
        printf("    
e_ehsize:       %d\n", ElfHeader.e_ehsize);
        printf("    
e_phentsize:    %d\n", ElfHeader.e_phentsize);
        printf("    
e_phnum:        %d\n", ElfHeader.e_phnum);
        printf("    
e_shentsize:    %d\n", ElfHeader.e_shentsize);
        printf("    
e_shnum:        %d\n", ElfHeader.e_shnum);
        printf("    
e_shstrndx:     %d\n", ElfHeader.e_shstrndx);
    }
    if (memcmp
(ELFMAG, ElfHeader.e_ident, SELFMAG) != 0)
    {
        if (debug)

            printf("Bad ELF header magic number\n");
        return;

    }
    if (ElfHeader.e_type != ET_DYN)
    {
        if (debug)

            printf("Not a shared object\n");
        return;
    }
    
check(ElfHeader.e_machine == EM_386, "Bad ELF architecture\n");
    
check(ElfHeader.e_version == EV_CURRENT, "Bad ELF version\n");
    check
(ElfHeader.e_phoff >= ElfHeader.e_ehsize,
          "Bad program header 
offset\n");
    check(ElfHeader.e_phentsize == sizeof(ProgHeader),

          "Bad program header size\n");
    PHOffset = ElfHeader.
e_phoff;
    PHCount = ElfHeader.e_phnum;

    for (i = 0; i < PHCount; 
i ++)
    {
        /* Get the i-th program header; we are interested 
in the eh_frame_hdr
         * section */
        ret = memreadat
(segment,
                        size,
                        
&ProgHeader,
                        sizeof(ProgHeader),

                        PHOffset + i * sizeof(ProgHeader));
        if 
(!ret)
            return;
        if (debug)
        {
            
printf("Object Program Header:\n");
            printf("    
p_type:         %d\n", ProgHeader.p_type);
            printf("    
p_offset:       %d\n", ProgHeader.p_offset);
            printf("    
p_vaddr:        %d\n", ProgHeader.p_vaddr);
            printf("    
p_paddr:        %d\n", ProgHeader.p_paddr);
            printf("    
p_filesz:       %d\n", ProgHeader.p_filesz);
            printf("    
p_memsz:        %d\n", ProgHeader.p_memsz);
            printf("    
p_flags:        %d\n", ProgHeader.p_flags);
            printf("    
p_align:        %d\n", ProgHeader.p_align);
        }

        if 
(ProgHeader.p_type == PT_LOAD && ProgHeader.p_offset == 0)
        {

            LoadOffset = ProgHeader.p_vaddr;
            if (debug)

            {
                printf("Found load offset 0x%x\n", 
LoadOffset);
            }
        }

        if (ProgHeader.p_type == 
PT_GNU_EH_FRAME)
        {
            check(EhFrameSize == 0, 

                  "Multiple PT_GNU_EH_FRAME program sections\n");


            EhFrameOffset = ProgHeader.p_offset;
            
EhFrameSize   = ProgHeader.p_filesz;
        }
    }

    if 
(EhFrameSize > 0)
    {
        char *ehsegment = xmalloc(EhFrameSize);

        ret = memreadat(segment, size, ehsegment,

                        EhFrameSize,
                        
EhFrameOffset);
        if (ret)
            ProcessEhFrameHdr
(segment, 
                              size,

                              segment + EhFrameOffset, 

                              EhFrameSize,

                              libname,
                              
LoadOffset);
        free(ehsegment);
    }
}

char *GuessLibName(char 
*segment, int size)
{
    char *first_GLIBC;
    char *this_string;
    
char *prev_string;
    int  retries;

    first_GLIBC = (char *)memmem
(segment, size, "\0GLIBC_", 7);
    if (first_GLIBC == NULL)
        
return NULL;
    this_string = first_GLIBC;

    for (retries = 0; 
retries < 15; retries ++)
    {
        for (prev_string = this_string 
- 1;
             prev_string > segment && *prev_string != '\0';

             prev_string --)
        {
            if (!isgraph
(*prev_string))
                return NULL;
            /* arbitrary 
max len */
            if (this_string - prev_string > 128)

                return NULL;        
        }

        if (memcmp
(prev_string + 1, "lib", 3) == 0 ||
            memcmp(prev_string + 1, 
"ld-linux.so", 11) == 0)
        {
            char *ret = xmalloc
(this_string - prev_string);
            memcpy(ret, prev_string + 1, 
this_string - prev_string);
            return ret;
        }

        
this_string = prev_string;
    }

    return NULL;
}

void extract_cfi
(char *corefile)
{
    int corefd;
    Elf32_Ehdr ElfHeader;
    int 
PHOffset, PHCount;
    Elf32_Phdr ProgHeader;
    int i;

    /* Open 
the corefile for reading */
    corefd = open(corefile, O_RDONLY);
    
check(corefd > 0, "open() failed\n");

    /* Get the corefile ELF 
header */
    readat(corefd, (void *)&ElfHeader, sizeof(ElfHeader), 0);

    if (debug)
    {
        printf("Corefile ELF Header:\n");
        
printf("    e_ident:        %.16s\n", ElfHeader.e_ident);
        printf
("    e_type:         %d\n", ElfHeader.e_type);
        printf("    
e_machine:      %d\n", ElfHeader.e_machine);
        printf("    
e_version:      %d\n", ElfHeader.e_version);
        printf("    
e_entry:        %d\n", ElfHeader.e_entry);
        printf("    
e_phoff:        %d\n", ElfHeader.e_phoff);
        printf("    
e_shoff:        %d\n", ElfHeader.e_shoff);
        printf("    
e_flags:        %d\n", ElfHeader.e_flags);
        printf("    
e_ehsize:       %d\n", ElfHeader.e_ehsize);
        printf("    
e_phentsize:    %d\n", ElfHeader.e_phentsize);
        printf("    
e_phnum:        %d\n", ElfHeader.e_phnum);
        printf("    
e_shentsize:    %d\n", ElfHeader.e_shentsize);
        printf("    
e_shnum:        %d\n", ElfHeader.e_shnum);
        printf("    
e_shstrndx:     %d\n", ElfHeader.e_shstrndx);
    }
    check(memcmp
(ELFMAG, ElfHeader.e_ident, SELFMAG) == 0,
          "Bad ELF header 
magic number\n");
    check(ElfHeader.e_type == ET_CORE, "Bad ELF 
object file type\n");
    check(ElfHeader.e_machine == EM_386, "Bad ELF 
architecture\n");
    check(ElfHeader.e_version == EV_CURRENT, "Bad ELF 
version\n");
    check(ElfHeader.e_phoff >= ElfHeader.e_ehsize,

          "Bad program header offset\n");
    check(ElfHeader.
e_phentsize == sizeof(ProgHeader),
          "Bad program header 
size\n");
    PHOffset = ElfHeader.e_phoff;
    PHCount = ElfHeader.
e_phnum;

    for (i = 0; i < PHCount; i ++)
    {
        /* Get the i-
th program header; we are interested in loadXX sections */
        
readat(corefd,
               &ProgHeader,
               sizeof
(ProgHeader),
               PHOffset + i * sizeof(ProgHeader));

        if (debug)
        {
            printf("Corefile Program 
Header:\n");
            printf("    p_type:         %d\n", ProgHeader.
p_type);
            printf("    p_offset:       %d\n", ProgHeader.
p_offset);
            printf("    p_vaddr:        %d\n", ProgHeader.
p_vaddr);
            printf("    p_paddr:        %d\n", ProgHeader.
p_paddr);
            printf("    p_filesz:       %d\n", ProgHeader.
p_filesz);
            printf("    p_memsz:        %d\n", ProgHeader.
p_memsz);
            printf("    p_flags:        %d\n", ProgHeader.
p_flags);
            printf("    p_align:        %d\n", ProgHeader.
p_align);
        }
        if (ProgHeader.p_type == PT_LOAD)
        {

            char *segment = xmalloc(ProgHeader.p_filesz);

            
/* Read the section.  If it starts with an ELF header then it's

             * (almost certainly) the start of an object */
            
readat(corefd, segment, ProgHeader.p_filesz, ProgHeader.p_offset);

            if (memcmp(ELFMAG, segment, SELFMAG) == 0)
            {

                char *libname = GuessLibName(segment, ProgHeader.
p_filesz);
                if (libname == NULL)
                {

                    libname = xmalloc(40);
                    snprintf
(libname, 40, "libunknown_%d", i);
                }
                if 
(debug)
                {
                    printf("Guessed library 
name %s\n", libname);
                }
                ProcessObject
(segment, ProgHeader.p_filesz, libname);
                free(libname);

            }
            free(segment);
        }
    }

    close
(corefd);
}


int main(int argc, char **argv)
{
    char *corefile;
    
int c;
    char *cfi_dir = NULL;
    int show_help = 0;

    while((c = 
getopt(argc, argv, "h?vdf:")) > 0)
    {
        switch (c)
        {

        case 'd':
            debug = 1;
            break;

        
case 'f':
            cfi_dir = optarg;
            break;

        
case '?':
        case 'h':
            show_help = 1;
            
break;

        default:
            fprintf(stderr, "invalid argument %
c.\n", c);
            exit(1);
            break;
        }
    }

    
if (show_help)
    {
        printf("Usage: wxcoretool [options] 
corefile\n\nwhere options are:\n\n"
               "-f <dir>	: Create 
CFI stub libraries in sysroot <dir>.\n"
               "-d		: Output 
debugging information.\n"
               "-h or -?	: Show help.\n"

              );
        exit(0);
    }

    check(argc - optind == 1, 
"invalid number of arguments.\n");

    corefile = realpath(argv
[optind], NULL);
    check(corefile != NULL, "unable to obtain path of 
core file.\n");

    if (cfi_dir)
    {
        int res;
        char 
*cfi_lib_dir = xmalloc(strlen(cfi_dir) + 5);
        struct stat 
stat_buf;

        sprintf(cfi_lib_dir, "%s/lib", cfi_dir);

        
res = stat(cfi_lib_dir, &stat_buf);
        if (res != 0 && errno == 
ENOENT)
        {
            res = mkdir(cfi_lib_dir, 0755);

            check(res == 0, "unable to make directory.\n");
        }

        else
        {
            check(res == 0, "unable to stat.
\n");
        }

        res = chdir(cfi_lib_dir);
        check(res == 
0, "unable to change to specified directory.\n");
        free
(cfi_lib_dir);

        extract_cfi(corefile);
    }
    exit(0);
}



More information about the Gdb mailing list