mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-12-04 21:42:39 +00:00
402 lines
21 KiB
C++
402 lines
21 KiB
C++
|
// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
|
||
|
/* 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, MIPS, PPC on Linux.
|
||
|
* Porting to other related platforms should not be difficult.
|
||
|
*/
|
||
|
#if (defined(__i386__) || defined(__x86_64__) || defined(__arm__) || \
|
||
|
defined(__mips__) || defined(__PPC__)) && 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__)
|
||
|
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;
|
||
|
#elif defined (__PPC__)
|
||
|
typedef struct ppc_regs {
|
||
|
#define SP uregs[1] /* Stack pointer */
|
||
|
#define IP rip /* Program counter */
|
||
|
#define LR lr /* Link register */
|
||
|
unsigned long uregs[32]; /* General Purpose Registers - r0-r31. */
|
||
|
double fpr[32]; /* Floating-Point Registers - f0-f31. */
|
||
|
unsigned long rip; /* Program counter. */
|
||
|
unsigned long msr;
|
||
|
unsigned long ccr;
|
||
|
unsigned long lr;
|
||
|
unsigned long ctr;
|
||
|
unsigned long xeq;
|
||
|
unsigned long mq;
|
||
|
} ppc_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__) && 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 */
|