| /* Copyright (c) 2005-2008, Google Inc. | 
 |  * All rights reserved. | 
 |  * | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions are | 
 |  * met: | 
 |  * | 
 |  *     * Redistributions of source code must retain the above copyright | 
 |  * notice, this list of conditions and the following disclaimer. | 
 |  *     * Redistributions in binary form must reproduce the above | 
 |  * copyright notice, this list of conditions and the following disclaimer | 
 |  * in the documentation and/or other materials provided with the | 
 |  * distribution. | 
 |  *     * Neither the name of Google Inc. nor the names of its | 
 |  * contributors may be used to endorse or promote products derived from | 
 |  * this software without specific prior written permission. | 
 |  * | 
 |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 |  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 |  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
 |  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
 |  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
 |  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
 |  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
 |  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
 |  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 |  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |  * | 
 |  * --- | 
 |  * Author: Markus Gutschke, Carl Crous | 
 |  */ | 
 |  | 
 | #ifndef _ELFCORE_H | 
 | #define _ELFCORE_H | 
 | #ifdef __cplusplus | 
 | extern "C" { | 
 | #endif | 
 |  | 
 | /* We currently only support x86-32, x86-64, ARM, and MIPS on Linux. | 
 |  * Porting to other related platforms should not be difficult. | 
 |  */ | 
 | #if (defined(__i386__) || defined(__x86_64__) || defined(__ARM_ARCH_3__) || \ | 
 |      defined(__mips__)) && defined(__linux) | 
 |  | 
 | #include <stdarg.h> | 
 | #include <stdint.h> | 
 | #include <sys/types.h> | 
 | #include <config.h> | 
 |  | 
 |  | 
 | /* Define the DUMPER symbol to make sure that there is exactly one | 
 |  * core dumper built into the library. | 
 |  */ | 
 | #define DUMPER "ELF" | 
 |  | 
 | /* By the time that we get a chance to read CPU registers in the | 
 |  * calling thread, they are already in a not particularly useful | 
 |  * state. Besides, there will be multiple frames on the stack that are | 
 |  * just making the core file confusing. To fix this problem, we take a | 
 |  * snapshot of the frame pointer, stack pointer, and instruction | 
 |  * pointer at an earlier time, and then insert these values into the | 
 |  * core file. | 
 |  */ | 
 |  | 
 | #if defined(__i386__) || defined(__x86_64__) | 
 |   typedef struct i386_regs {    /* Normal (non-FPU) CPU registers            */ | 
 |   #ifdef __x86_64__ | 
 |     #define BP rbp | 
 |     #define SP rsp | 
 |     #define IP rip | 
 |     uint64_t  r15,r14,r13,r12,rbp,rbx,r11,r10; | 
 |     uint64_t  r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax; | 
 |     uint64_t  rip,cs,eflags; | 
 |     uint64_t  rsp,ss; | 
 |     uint64_t  fs_base, gs_base; | 
 |     uint64_t  ds,es,fs,gs; | 
 |   #else | 
 |     #define BP ebp | 
 |     #define SP esp | 
 |     #define IP eip | 
 |     uint32_t  ebx, ecx, edx, esi, edi, ebp, eax; | 
 |     uint16_t  ds, __ds, es, __es; | 
 |     uint16_t  fs, __fs, gs, __gs; | 
 |     uint32_t  orig_eax, eip; | 
 |     uint16_t  cs, __cs; | 
 |     uint32_t  eflags, esp; | 
 |     uint16_t  ss, __ss; | 
 |   #endif | 
 |   } i386_regs; | 
 | #elif defined(__ARM_ARCH_3__) | 
 |   typedef struct arm_regs {     /* General purpose registers                 */ | 
 |     #define BP uregs[11]        /* Frame pointer                             */ | 
 |     #define SP uregs[13]        /* Stack pointer                             */ | 
 |     #define IP uregs[15]        /* Program counter                           */ | 
 |     #define LR uregs[14]        /* Link register                             */ | 
 |     long uregs[18]; | 
 |   } arm_regs; | 
 | #elif defined(__mips__) | 
 |   typedef struct mips_regs { | 
 |     unsigned long pad[6];       /* Unused padding to match kernel structures */ | 
 |     unsigned long uregs[32];    /* General purpose registers.                */ | 
 |     unsigned long hi;           /* Used for multiplication and division.     */ | 
 |     unsigned long lo; | 
 |     unsigned long cp0_epc;      /* Program counter.                          */ | 
 |     unsigned long cp0_badvaddr; | 
 |     unsigned long cp0_status; | 
 |     unsigned long cp0_cause; | 
 |     unsigned long unused; | 
 |   } mips_regs; | 
 | #endif | 
 |  | 
 | #if defined(__i386__) && defined(__GNUC__) | 
 |   /* On x86 we provide an optimized version of the FRAME() macro, if the | 
 |    * compiler supports a GCC-style asm() directive. This results in somewhat | 
 |    * more accurate values for CPU registers. | 
 |    */ | 
 |   typedef struct Frame { | 
 |     struct i386_regs uregs; | 
 |     int              errno_; | 
 |     pid_t            tid; | 
 |   } Frame; | 
 |   #define FRAME(f) Frame f;                                           \ | 
 |                    do {                                               \ | 
 |                      f.errno_ = errno;                                \ | 
 |                      f.tid    = sys_gettid();                         \ | 
 |                      __asm__ volatile (                               \ | 
 |                        "push %%ebp\n"                                 \ | 
 |                        "push %%ebx\n"                                 \ | 
 |                        "mov  %%ebx,0(%%eax)\n"                        \ | 
 |                        "mov  %%ecx,4(%%eax)\n"                        \ | 
 |                        "mov  %%edx,8(%%eax)\n"                        \ | 
 |                        "mov  %%esi,12(%%eax)\n"                       \ | 
 |                        "mov  %%edi,16(%%eax)\n"                       \ | 
 |                        "mov  %%ebp,20(%%eax)\n"                       \ | 
 |                        "mov  %%eax,24(%%eax)\n"                       \ | 
 |                        "mov  %%ds,%%ebx\n"                            \ | 
 |                        "mov  %%ebx,28(%%eax)\n"                       \ | 
 |                        "mov  %%es,%%ebx\n"                            \ | 
 |                        "mov  %%ebx,32(%%eax)\n"                       \ | 
 |                        "mov  %%fs,%%ebx\n"                            \ | 
 |                        "mov  %%ebx,36(%%eax)\n"                       \ | 
 |                        "mov  %%gs,%%ebx\n"                            \ | 
 |                        "mov  %%ebx, 40(%%eax)\n"                      \ | 
 |                        "call 0f\n"                                    \ | 
 |                      "0:pop %%ebx\n"                                  \ | 
 |                        "add  $1f-0b,%%ebx\n"                          \ | 
 |                        "mov  %%ebx,48(%%eax)\n"                       \ | 
 |                        "mov  %%cs,%%ebx\n"                            \ | 
 |                        "mov  %%ebx,52(%%eax)\n"                       \ | 
 |                        "pushf\n"                                      \ | 
 |                        "pop  %%ebx\n"                                 \ | 
 |                        "mov  %%ebx,56(%%eax)\n"                       \ | 
 |                        "mov  %%esp,%%ebx\n"                           \ | 
 |                        "add  $8,%%ebx\n"                              \ | 
 |                        "mov  %%ebx,60(%%eax)\n"                       \ | 
 |                        "mov  %%ss,%%ebx\n"                            \ | 
 |                        "mov  %%ebx,64(%%eax)\n"                       \ | 
 |                        "pop  %%ebx\n"                                 \ | 
 |                        "pop  %%ebp\n"                                 \ | 
 |                      "1:"                                             \ | 
 |                        : : "a" (&f) : "memory");                      \ | 
 |                      } while (0) | 
 |   #define SET_FRAME(f,r)                                              \ | 
 |                      do {                                             \ | 
 |                        errno = (f).errno_;                            \ | 
 |                        (r)   = (f).uregs;                             \ | 
 |                      } while (0) | 
 | #elif defined(__x86_64__) && defined(__GNUC__) | 
 |   /* The FRAME and SET_FRAME macros for x86_64.  */ | 
 |   typedef struct Frame { | 
 |     struct i386_regs uregs; | 
 |     int              errno_; | 
 |     pid_t            tid; | 
 |   } Frame; | 
 |   #define FRAME(f) Frame f;                                           \ | 
 |                    do {                                               \ | 
 |                      f.errno_ = errno;                                \ | 
 |                      f.tid    = sys_gettid();                         \ | 
 |                      __asm__ volatile (                               \ | 
 |                        "push %%rbp\n"                                 \ | 
 |                        "push %%rbx\n"                                 \ | 
 |                        "mov  %%r15,0(%%rax)\n"                        \ | 
 |                        "mov  %%r14,8(%%rax)\n"                        \ | 
 |                        "mov  %%r13,16(%%rax)\n"                       \ | 
 |                        "mov  %%r12,24(%%rax)\n"                       \ | 
 |                        "mov  %%rbp,32(%%rax)\n"                       \ | 
 |                        "mov  %%rbx,40(%%rax)\n"                       \ | 
 |                        "mov  %%r11,48(%%rax)\n"                       \ | 
 |                        "mov  %%r10,56(%%rax)\n"                       \ | 
 |                        "mov  %%r9,64(%%rax)\n"                        \ | 
 |                        "mov  %%r8,72(%%rax)\n"                        \ | 
 |                        "mov  %%rax,80(%%rax)\n"                       \ | 
 |                        "mov  %%rcx,88(%%rax)\n"                       \ | 
 |                        "mov  %%rdx,96(%%rax)\n"                       \ | 
 |                        "mov  %%rsi,104(%%rax)\n"                      \ | 
 |                        "mov  %%rdi,112(%%rax)\n"                      \ | 
 |                        "mov  %%ds,%%rbx\n"                            \ | 
 |                        "mov  %%rbx,184(%%rax)\n"                      \ | 
 |                        "mov  %%es,%%rbx\n"                            \ | 
 |                        "mov  %%rbx,192(%%rax)\n"                      \ | 
 |                        "mov  %%fs,%%rbx\n"                            \ | 
 |                        "mov  %%rbx,200(%%rax)\n"                      \ | 
 |                        "mov  %%gs,%%rbx\n"                            \ | 
 |                        "mov  %%rbx,208(%%rax)\n"                      \ | 
 |                        "call 0f\n"                                    \ | 
 |                      "0:pop %%rbx\n"                                  \ | 
 |                        "add  $1f-0b,%%rbx\n"                          \ | 
 |                        "mov  %%rbx,128(%%rax)\n"                      \ | 
 |                        "mov  %%cs,%%rbx\n"                            \ | 
 |                        "mov  %%rbx,136(%%rax)\n"                      \ | 
 |                        "pushf\n"                                      \ | 
 |                        "pop  %%rbx\n"                                 \ | 
 |                        "mov  %%rbx,144(%%rax)\n"                      \ | 
 |                        "mov  %%rsp,%%rbx\n"                           \ | 
 |                        "add  $16,%%ebx\n"                             \ | 
 |                        "mov  %%rbx,152(%%rax)\n"                      \ | 
 |                        "mov  %%ss,%%rbx\n"                            \ | 
 |                        "mov  %%rbx,160(%%rax)\n"                      \ | 
 |                        "pop  %%rbx\n"                                 \ | 
 |                        "pop  %%rbp\n"                                 \ | 
 |                      "1:"                                             \ | 
 |                        : : "a" (&f) : "memory");                      \ | 
 |                      } while (0) | 
 |   #define SET_FRAME(f,r)                                              \ | 
 |                      do {                                             \ | 
 |                        errno = (f).errno_;                            \ | 
 |                        (f).uregs.fs_base = (r).fs_base;               \ | 
 |                        (f).uregs.gs_base = (r).gs_base;               \ | 
 |                        (r)   = (f).uregs;                             \ | 
 |                      } while (0) | 
 | #elif defined(__ARM_ARCH_3__) && defined(__GNUC__) | 
 |   /* ARM calling conventions are a little more tricky. A little assembly | 
 |    * helps in obtaining an accurate snapshot of all registers. | 
 |    */ | 
 |   typedef struct Frame { | 
 |     struct arm_regs arm; | 
 |     int             errno_; | 
 |     pid_t           tid; | 
 |   } Frame; | 
 |   #define FRAME(f) Frame f;                                           \ | 
 |                    do {                                               \ | 
 |                      long cpsr;                                       \ | 
 |                      f.errno_ = errno;                                \ | 
 |                      f.tid    = sys_gettid();                         \ | 
 |                      __asm__ volatile(                                \ | 
 |                        "stmia %0, {r0-r15}\n" /* All integer regs   */\ | 
 |                        : : "r"(&f.arm) : "memory");                   \ | 
 |                      f.arm.uregs[16] = 0;                             \ | 
 |                      __asm__ volatile(                                \ | 
 |                        "mrs %0, cpsr\n"       /* Condition code reg */\ | 
 |                        : "=r"(cpsr));                                 \ | 
 |                      f.arm.uregs[17] = cpsr;                          \ | 
 |                    } while (0) | 
 |   #define SET_FRAME(f,r)                                              \ | 
 |                      do {                                             \ | 
 |                        /* Don't override the FPU status register.   */\ | 
 |                        /* Use the value obtained from ptrace(). This*/\ | 
 |                        /* works, because our code does not perform  */\ | 
 |                        /* any FPU operations, itself.               */\ | 
 |                        long fps      = (f).arm.uregs[16];             \ | 
 |                        errno         = (f).errno_;                    \ | 
 |                        (r)           = (f).arm;                       \ | 
 |                        (r).uregs[16] = fps;                           \ | 
 |                      } while (0) | 
 | #elif defined(__mips__) && defined(__GNUC__) | 
 |   typedef struct Frame { | 
 |     struct mips_regs mips_regs; | 
 |     int              errno_; | 
 |     pid_t            tid; | 
 |   } Frame; | 
 |   #define MIPSREG(n) ({ register unsigned long r __asm__("$"#n); r; }) | 
 |   #define FRAME(f) Frame f = { 0 };                                   \ | 
 |                    do {                                               \ | 
 |                      unsigned long hi, lo;                            \ | 
 |                      register unsigned long pc __asm__("$31");        \ | 
 |                      f.mips_regs.uregs[ 0] = MIPSREG( 0);             \ | 
 |                      f.mips_regs.uregs[ 1] = MIPSREG( 1);             \ | 
 |                      f.mips_regs.uregs[ 2] = MIPSREG( 2);             \ | 
 |                      f.mips_regs.uregs[ 3] = MIPSREG( 3);             \ | 
 |                      f.mips_regs.uregs[ 4] = MIPSREG( 4);             \ | 
 |                      f.mips_regs.uregs[ 5] = MIPSREG( 5);             \ | 
 |                      f.mips_regs.uregs[ 6] = MIPSREG( 6);             \ | 
 |                      f.mips_regs.uregs[ 7] = MIPSREG( 7);             \ | 
 |                      f.mips_regs.uregs[ 8] = MIPSREG( 8);             \ | 
 |                      f.mips_regs.uregs[ 9] = MIPSREG( 9);             \ | 
 |                      f.mips_regs.uregs[10] = MIPSREG(10);             \ | 
 |                      f.mips_regs.uregs[11] = MIPSREG(11);             \ | 
 |                      f.mips_regs.uregs[12] = MIPSREG(12);             \ | 
 |                      f.mips_regs.uregs[13] = MIPSREG(13);             \ | 
 |                      f.mips_regs.uregs[14] = MIPSREG(14);             \ | 
 |                      f.mips_regs.uregs[15] = MIPSREG(15);             \ | 
 |                      f.mips_regs.uregs[16] = MIPSREG(16);             \ | 
 |                      f.mips_regs.uregs[17] = MIPSREG(17);             \ | 
 |                      f.mips_regs.uregs[18] = MIPSREG(18);             \ | 
 |                      f.mips_regs.uregs[19] = MIPSREG(19);             \ | 
 |                      f.mips_regs.uregs[20] = MIPSREG(20);             \ | 
 |                      f.mips_regs.uregs[21] = MIPSREG(21);             \ | 
 |                      f.mips_regs.uregs[22] = MIPSREG(22);             \ | 
 |                      f.mips_regs.uregs[23] = MIPSREG(23);             \ | 
 |                      f.mips_regs.uregs[24] = MIPSREG(24);             \ | 
 |                      f.mips_regs.uregs[25] = MIPSREG(25);             \ | 
 |                      f.mips_regs.uregs[26] = MIPSREG(26);             \ | 
 |                      f.mips_regs.uregs[27] = MIPSREG(27);             \ | 
 |                      f.mips_regs.uregs[28] = MIPSREG(28);             \ | 
 |                      f.mips_regs.uregs[29] = MIPSREG(29);             \ | 
 |                      f.mips_regs.uregs[30] = MIPSREG(30);             \ | 
 |                      f.mips_regs.uregs[31] = MIPSREG(31);             \ | 
 |                      __asm__ volatile ("mfhi %0" : "=r"(hi));         \ | 
 |                      __asm__ volatile ("mflo %0" : "=r"(lo));         \ | 
 |                      __asm__ volatile ("jal 1f; 1:nop" : "=r"(pc));   \ | 
 |                      f.mips_regs.hi       = hi;                       \ | 
 |                      f.mips_regs.lo       = lo;                       \ | 
 |                      f.mips_regs.cp0_epc  = pc;                       \ | 
 |                      f.errno_             = errno;                    \ | 
 |                      f.tid                = sys_gettid();             \ | 
 |                    } while (0) | 
 |   #define SET_FRAME(f,r)                                              \ | 
 |                    do {                                               \ | 
 |                      errno       = (f).errno_;                        \ | 
 |                      memcpy((r).uregs, (f).mips_regs.uregs,           \ | 
 |                             32*sizeof(unsigned long));                \ | 
 |                      (r).hi      = (f).mips_regs.hi;                  \ | 
 |                      (r).lo      = (f).mips_regs.lo;                  \ | 
 |                      (r).cp0_epc = (f).mips_regs.cp0_epc;             \ | 
 |                    } while (0) | 
 | #else | 
 |   /* If we do not have a hand-optimized assembly version of the FRAME() | 
 |    * macro, we cannot reliably unroll the stack. So, we show a few additional | 
 |    * stack frames for the coredumper. | 
 |    */ | 
 |   typedef struct Frame { | 
 |     pid_t tid; | 
 |   } Frame; | 
 |   #define FRAME(f) Frame f; do { f.tid = sys_gettid(); } while (0) | 
 |   #define SET_FRAME(f,r) do { } while (0) | 
 | #endif | 
 |  | 
 |  | 
 | /* Internal function for generating a core file. This API can change without | 
 |  * notice and is only supposed to be used internally by the core dumper. | 
 |  * | 
 |  * This function works for both single- and multi-threaded core | 
 |  * dumps. If called as | 
 |  * | 
 |  *   FRAME(frame); | 
 |  *   InternalGetCoreDump(&frame, 0, NULL, ap); | 
 |  * | 
 |  * it creates a core file that only contains information about the | 
 |  * calling thread. | 
 |  * | 
 |  * Optionally, the caller can provide information about other threads | 
 |  * by passing their process ids in "thread_pids". The process id of | 
 |  * the caller should not be included in this array. All of the threads | 
 |  * must have been attached to with ptrace(), prior to calling this | 
 |  * function. They will be detached when "InternalGetCoreDump()" returns. | 
 |  * | 
 |  * This function either returns a file handle that can be read for obtaining | 
 |  * a core dump, or "-1" in case of an error. In the latter case, "errno" | 
 |  * will be set appropriately. | 
 |  * | 
 |  * While "InternalGetCoreDump()" is not technically async signal safe, you | 
 |  * might be tempted to invoke it from a signal handler. The code goes to | 
 |  * great lengths to make a best effort that this will actually work. But in | 
 |  * any case, you must make sure that you preserve the value of "errno" | 
 |  * yourself. It is guaranteed to be clobbered otherwise. | 
 |  * | 
 |  * Also, "InternalGetCoreDump" is not strictly speaking re-entrant. Again, | 
 |  * it makes a best effort to behave reasonably when called in a multi- | 
 |  * threaded environment, but it is ultimately the caller's responsibility | 
 |  * to provide locking. | 
 |  */ | 
 | int InternalGetCoreDump(void *frame, int num_threads, pid_t *thread_pids, | 
 |                         va_list ap | 
 |                      /* const struct CoreDumpParameters *params, | 
 |                         const char *file_name, | 
 |                         const char *PATH | 
 |                       */); | 
 |  | 
 | #endif | 
 |  | 
 | #ifdef __cplusplus | 
 | } | 
 | #endif | 
 | #endif /* _ELFCORE_H */ |