diff options
Diffstat (limited to 'contrib/libs/breakpad/src/common/linux')
35 files changed, 5918 insertions, 0 deletions
diff --git a/contrib/libs/breakpad/src/common/linux/breakpad_getcontext.S b/contrib/libs/breakpad/src/common/linux/breakpad_getcontext.S new file mode 100644 index 0000000000..2ebcf31910 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/breakpad_getcontext.S @@ -0,0 +1,552 @@ +// Copyright (c) 2012, 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. + +// A minimalistic implementation of getcontext() to be used by +// Google Breakpad when getcontext() is not available in libc. + +#include "common/linux/ucontext_constants.h" + +/* int getcontext (ucontext_t* ucp) */ + +#if defined(__arm__) + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .type breakpad_getcontext, #function + .align 0 + .fnstart +breakpad_getcontext: + + /* First, save r4-r11 */ + add r1, r0, #(MCONTEXT_GREGS_OFFSET + 4*4) + stm r1, {r4-r11} + + /* r12 is a scratch register, don't save it */ + + /* Save sp and lr explicitly. */ + /* - sp can't be stored with stmia in Thumb-2 */ + /* - STM instructions that store sp and pc are deprecated in ARM */ + str sp, [r0, #(MCONTEXT_GREGS_OFFSET + 13*4)] + str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)] + + /* Save the caller's address in 'pc' */ + str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 15*4)] + + /* Save ucontext_t* pointer across next call */ + mov r4, r0 + + /* Call sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */ + mov r0, #0 /* SIG_BLOCK */ + mov r1, #0 /* NULL */ + add r2, r4, #UCONTEXT_SIGMASK_OFFSET + bl sigprocmask(PLT) + + /* Intentionally do not save the FPU state here. This is because on + * Linux/ARM, one should instead use ptrace(PTRACE_GETFPREGS) or + * ptrace(PTRACE_GETVFPREGS) to get it. + * + * Note that a real implementation of getcontext() would need to save + * this here to allow setcontext()/swapcontext() to work correctly. + */ + + /* Restore the values of r4 and lr */ + mov r0, r4 + ldr lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)] + ldr r4, [r0, #(MCONTEXT_GREGS_OFFSET + 4*4)] + + /* Return 0 */ + mov r0, #0 + bx lr + + .fnend + .size breakpad_getcontext, . - breakpad_getcontext + +#elif defined(__aarch64__) + +#if defined(__ARM_FEATURE_PAC_DEFAULT) && __ARM_FEATURE_PAC_DEFAULT + // ENABLE_PAUTH must be defined to 1 since this value will be used in + // bitwise-shift later! + #define ENABLE_PAUTH 1 + + #if ((__ARM_FEATURE_PAC_DEFAULT&((1<<0)|(1<<1)))==0) + #error Pointer authentication defines no valid key! + #endif +#else + #define ENABLE_PAUTH 0 +#endif + +#if defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT==1) + // ENABLE_BTI must be defined to 1 since this value will be used in + // bitwise-shift later! + #define ENABLE_BTI 1 +#else + #define ENABLE_BTI 0 +#endif + + +// Although Pointer Authentication and Branch Target Instructions are technically +// seperate features they work together, i.e. the paciasp and pacibsp instructions +// serve as BTI landing pads. +// Therefore PA-instructions are enabled when PA _or_ BTI is enabled! +#if ENABLE_PAUTH || ENABLE_BTI + // See section "Pointer Authentication" of + // https://developer.arm.com/documentation/101028/0012/5--Feature-test-macros + // for details how to interpret __ARM_FEATURE_PAC_DEFAULT + #if (__ARM_FEATURE_PAC_DEFAULT & (1<<0)) + #define PAUTH_SIGN_SP paciasp + #define PAUTH_AUTH_SP autiasp + #else + #define PAUTH_SIGN_SP pacibsp + #define PAUTH_AUTH_SP autibsp + #endif +#else + #define PAUTH_SIGN_SP + #define PAUTH_AUTH_SP +#endif + +#define _NSIG 64 +#define __NR_rt_sigprocmask 135 + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .type breakpad_getcontext, #function + .align 4 + .cfi_startproc +breakpad_getcontext: + + PAUTH_SIGN_SP + + /* The saved context will return to the getcontext() call point + with a return value of 0 */ + str xzr, [x0, MCONTEXT_GREGS_OFFSET + 0 * REGISTER_SIZE] + + stp x18, x19, [x0, MCONTEXT_GREGS_OFFSET + 18 * REGISTER_SIZE] + stp x20, x21, [x0, MCONTEXT_GREGS_OFFSET + 20 * REGISTER_SIZE] + stp x22, x23, [x0, MCONTEXT_GREGS_OFFSET + 22 * REGISTER_SIZE] + stp x24, x25, [x0, MCONTEXT_GREGS_OFFSET + 24 * REGISTER_SIZE] + stp x26, x27, [x0, MCONTEXT_GREGS_OFFSET + 26 * REGISTER_SIZE] + stp x28, x29, [x0, MCONTEXT_GREGS_OFFSET + 28 * REGISTER_SIZE] + str x30, [x0, MCONTEXT_GREGS_OFFSET + 30 * REGISTER_SIZE] + + /* Place LR into the saved PC, this will ensure that when + switching to this saved context with setcontext() control + will pass back to the caller of getcontext(), we have + already arranged to return the appropriate return value in x0 + above. */ + str x30, [x0, MCONTEXT_PC_OFFSET] + + /* Save the current SP */ + mov x2, sp + str x2, [x0, MCONTEXT_SP_OFFSET] + + /* Initialize the pstate. */ + str xzr, [x0, MCONTEXT_PSTATE_OFFSET] + + /* Figure out where to place the first context extension + block. */ + add x2, x0, #MCONTEXT_EXTENSION_OFFSET + + /* Write the context extension fpsimd header. */ + mov w3, #(FPSIMD_MAGIC & 0xffff) + movk w3, #(FPSIMD_MAGIC >> 16), lsl #16 + str w3, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET] + mov w3, #FPSIMD_CONTEXT_SIZE + str w3, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET] + + /* Fill in the FP SIMD context. */ + add x3, x2, #(FPSIMD_CONTEXT_VREGS_OFFSET + 8 * SIMD_REGISTER_SIZE) + stp d8, d9, [x3], #(2 * SIMD_REGISTER_SIZE) + stp d10, d11, [x3], #(2 * SIMD_REGISTER_SIZE) + stp d12, d13, [x3], #(2 * SIMD_REGISTER_SIZE) + stp d14, d15, [x3], #(2 * SIMD_REGISTER_SIZE) + + add x3, x2, FPSIMD_CONTEXT_FPSR_OFFSET + + mrs x4, fpsr + str w4, [x3] + + mrs x4, fpcr + str w4, [x3, FPSIMD_CONTEXT_FPCR_OFFSET - FPSIMD_CONTEXT_FPSR_OFFSET] + + /* Write the termination context extension header. */ + add x2, x2, #FPSIMD_CONTEXT_SIZE + + str xzr, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET] + str xzr, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET] + + /* Grab the signal mask */ + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + add x2, x0, #UCONTEXT_SIGMASK_OFFSET + mov x0, #0 /* SIG_BLOCK */ + mov x1, #0 /* NULL */ + mov x3, #(_NSIG / 8) + mov x8, #__NR_rt_sigprocmask + svc 0 + + /* Return x0 for success */ + mov x0, 0 + + PAUTH_AUTH_SP + + ret + + .cfi_endproc + .size breakpad_getcontext, . - breakpad_getcontext + +#elif defined(__i386__) + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .align 4 + .type breakpad_getcontext, @function + +breakpad_getcontext: + + movl 4(%esp), %eax /* eax = uc */ + + /* Save register values */ + movl %ecx, MCONTEXT_ECX_OFFSET(%eax) + movl %edx, MCONTEXT_EDX_OFFSET(%eax) + movl %ebx, MCONTEXT_EBX_OFFSET(%eax) + movl %edi, MCONTEXT_EDI_OFFSET(%eax) + movl %esi, MCONTEXT_ESI_OFFSET(%eax) + movl %ebp, MCONTEXT_EBP_OFFSET(%eax) + + movl (%esp), %edx /* return address */ + lea 4(%esp), %ecx /* exclude return address from stack */ + mov %edx, MCONTEXT_EIP_OFFSET(%eax) + mov %ecx, MCONTEXT_ESP_OFFSET(%eax) + + xorl %ecx, %ecx + movw %fs, %cx + mov %ecx, MCONTEXT_FS_OFFSET(%eax) + + movl $0, MCONTEXT_EAX_OFFSET(%eax) + + /* Save floating point state to fpregstate, then update + * the fpregs pointer to point to it */ + leal UCONTEXT_FPREGS_MEM_OFFSET(%eax), %ecx + fnstenv (%ecx) + fldenv (%ecx) + mov %ecx, UCONTEXT_FPREGS_OFFSET(%eax) + + /* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */ + leal UCONTEXT_SIGMASK_OFFSET(%eax), %edx + xorl %ecx, %ecx + push %edx /* &uc->uc_sigmask */ + push %ecx /* NULL */ + push %ecx /* SIGBLOCK == 0 on i386 */ + call sigprocmask@PLT + addl $12, %esp + + movl $0, %eax + ret + + .size breakpad_getcontext, . - breakpad_getcontext + +#elif defined(__mips__) + +// This implementation is inspired by implementation of getcontext in glibc. +#include <asm-mips/asm.h> +#include <asm-mips/regdef.h> +#if _MIPS_SIM == _ABIO32 +#include <asm-mips/fpregdef.h> +#endif + +// from asm-mips/asm.h +#if _MIPS_SIM == _ABIO32 +#define ALSZ 7 +#define ALMASK ~7 +#define SZREG 4 +#else // _MIPS_SIM != _ABIO32 +#define ALSZ 15 +#define ALMASK ~15 +#define SZREG 8 +#endif + +#include <asm/unistd.h> // for __NR_rt_sigprocmask + +#define _NSIG8 128 / 8 +#define SIG_BLOCK 1 + + + .text +LOCALS_NUM = 1 // save gp on stack +FRAME_SIZE = ((LOCALS_NUM * SZREG) + ALSZ) & ALMASK + +GP_FRAME_OFFSET = FRAME_SIZE - (1 * SZREG) +MCONTEXT_REG_SIZE = 8 + +#if _MIPS_SIM == _ABIO32 + +NESTED (breakpad_getcontext, FRAME_SIZE, ra) + .mask 0x00000000, 0 + .fmask 0x00000000, 0 + + .set noreorder + .cpload t9 + .set reorder + + move a2, sp +#define _SP a2 + + addiu sp, -FRAME_SIZE + .cprestore GP_FRAME_OFFSET + + sw s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw fp, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sw ra, MCONTEXT_PC_OFFSET(a0) + +#ifdef __mips_hard_float + s.d fs0, (20 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs1, (22 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs2, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs3, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs4, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d fs5, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + + cfc1 v1, fcr31 + sw v1, MCONTEXT_FPC_CSR(a0) +#endif // __mips_hard_float + + /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + li a3, _NSIG8 + addu a2, a0, UCONTEXT_SIGMASK_OFFSET + move a1, zero + li a0, SIG_BLOCK + li v0, __NR_rt_sigprocmask + syscall + + addiu sp, FRAME_SIZE + jr ra + +END (breakpad_getcontext) +#else + +#ifndef NESTED +/* + * NESTED - declare nested routine entry point + */ +#define NESTED(symbol, framesize, rpc) \ + .globl symbol; \ + .align 2; \ + .type symbol,@function; \ + .ent symbol,0; \ +symbol: .frame sp, framesize, rpc; +#endif + +/* + * END - mark end of function + */ +#ifndef END +# define END(function) \ + .end function; \ + .size function,.-function +#endif + +/* int getcontext (ucontext_t* ucp) */ + +NESTED (breakpad_getcontext, FRAME_SIZE, ra) + .mask 0x10000000, 0 + .fmask 0x00000000, 0 + + move a2, sp +#define _SP a2 + move a3, gp +#define _GP a3 + + daddiu sp, -FRAME_SIZE + .cpsetup $25, GP_FRAME_OFFSET, breakpad_getcontext + + /* Store a magic flag. */ + li v1, 1 + sd v1, (0 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) /* zero */ + + sd s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd _GP, (28 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd s8, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) + sd ra, MCONTEXT_PC_OFFSET(a0) + +#ifdef __mips_hard_float + s.d $f24, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f25, (25 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f26, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f27, (27 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f28, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f29, (29 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f30, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + s.d $f31, (31 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0) + + cfc1 v1, $31 + sw v1, MCONTEXT_FPC_CSR(a0) +#endif /* __mips_hard_float */ + +/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */ + li a3, _NSIG8 + daddu a2, a0, UCONTEXT_SIGMASK_OFFSET + move a1, zero + li a0, SIG_BLOCK + + li v0, __NR_rt_sigprocmask + syscall + + .cpreturn + daddiu sp, FRAME_SIZE + move v0, zero + jr ra + +END (breakpad_getcontext) +#endif // _MIPS_SIM == _ABIO32 + +#elif defined(__x86_64__) +/* The x64 implementation of breakpad_getcontext was derived in part + from the implementation of libunwind which requires the following + notice. */ +/* libunwind - a platform-independent unwind library + Copyright (C) 2008 Google, Inc + Contributed by Paul Pluzhnikov <ppluzhnikov@google.com> + Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org> + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + + .text + .global breakpad_getcontext + .hidden breakpad_getcontext + .align 4 + .type breakpad_getcontext, @function + +breakpad_getcontext: + .cfi_startproc + + /* Callee saved: RBX, RBP, R12-R15 */ + movq %r12, MCONTEXT_GREGS_R12(%rdi) + movq %r13, MCONTEXT_GREGS_R13(%rdi) + movq %r14, MCONTEXT_GREGS_R14(%rdi) + movq %r15, MCONTEXT_GREGS_R15(%rdi) + movq %rbp, MCONTEXT_GREGS_RBP(%rdi) + movq %rbx, MCONTEXT_GREGS_RBX(%rdi) + + /* Save argument registers (not strictly needed, but setcontext + restores them, so don't restore garbage). */ + movq %r8, MCONTEXT_GREGS_R8(%rdi) + movq %r9, MCONTEXT_GREGS_R9(%rdi) + movq %rdi, MCONTEXT_GREGS_RDI(%rdi) + movq %rsi, MCONTEXT_GREGS_RSI(%rdi) + movq %rdx, MCONTEXT_GREGS_RDX(%rdi) + movq %rax, MCONTEXT_GREGS_RAX(%rdi) + movq %rcx, MCONTEXT_GREGS_RCX(%rdi) + + /* Save fp state (not needed, except for setcontext not + restoring garbage). */ + leaq MCONTEXT_FPREGS_MEM(%rdi),%r8 + movq %r8, MCONTEXT_FPREGS_PTR(%rdi) + fnstenv (%r8) + stmxcsr FPREGS_OFFSET_MXCSR(%r8) + + leaq 8(%rsp), %rax /* exclude this call. */ + movq %rax, MCONTEXT_GREGS_RSP(%rdi) + + movq 0(%rsp), %rax + movq %rax, MCONTEXT_GREGS_RIP(%rdi) + + /* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */ + leaq UCONTEXT_SIGMASK_OFFSET(%rdi), %rdx // arg3 + xorq %rsi, %rsi // arg2 NULL + xorq %rdi, %rdi // arg1 SIGBLOCK == 0 + call sigprocmask@PLT + + /* Always return 0 for success, even if sigprocmask failed. */ + xorl %eax, %eax + ret + .cfi_endproc + .size breakpad_getcontext, . - breakpad_getcontext + +#else +#error "This file has not been ported for your CPU!" +#endif + +#if defined(__aarch64__) +// ENABLE_PAUTH and ENABLE_BTI would be enabled at the definition +// of AArch64 specific breakpad_getcontext function +#if ENABLE_PAUTH || ENABLE_BTI +// for further information on the .note.gnu.property section see +// https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst#program-property +.pushsection .note.gnu.property, "a"; + .balign 8 + .long 4 + .long 0x10 + .long 0x5 + .asciz "GNU" + .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ + .long 4 + .long ((ENABLE_PAUTH)<<1) | ((ENABLE_BTI)<<0) /* PAuth and BTI */ + .long 0 +.popsection +#endif +#endif diff --git a/contrib/libs/breakpad/src/common/linux/breakpad_getcontext.h b/contrib/libs/breakpad/src/common/linux/breakpad_getcontext.h new file mode 100644 index 0000000000..1418cde621 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/breakpad_getcontext.h @@ -0,0 +1,56 @@ +// Copyright (c) 2012, 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. + +#ifndef GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H +#define GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifndef HAVE_GETCONTEXT + +#include <signal.h> + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +// Provided by src/common/linux/breakpad_getcontext.S +int breakpad_getcontext(ucontext_t* ucp); + +#define getcontext(x) breakpad_getcontext(x) + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +#endif // HAVE_GETCONTEXT + +#endif // GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H diff --git a/contrib/libs/breakpad/src/common/linux/crc32.cc b/contrib/libs/breakpad/src/common/linux/crc32.cc new file mode 100644 index 0000000000..8df636ce4d --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/crc32.cc @@ -0,0 +1,70 @@ +// Copyright 2014 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. + +#include "common/linux/crc32.h" + +namespace google_breakpad { + +// This implementation is based on the sample implementation in RFC 1952. + +// CRC32 polynomial, in reversed form. +// See RFC 1952, or http://en.wikipedia.org/wiki/Cyclic_redundancy_check +static const uint32_t kCrc32Polynomial = 0xEDB88320; +static uint32_t kCrc32Table[256] = { 0 }; + +#define arraysize(f) (sizeof(f) / sizeof(*f)) + +static void EnsureCrc32TableInited() { + if (kCrc32Table[arraysize(kCrc32Table) - 1]) + return; // already inited + for (uint32_t i = 0; i < arraysize(kCrc32Table); ++i) { + uint32_t c = i; + for (size_t j = 0; j < 8; ++j) { + if (c & 1) { + c = kCrc32Polynomial ^ (c >> 1); + } else { + c >>= 1; + } + } + kCrc32Table[i] = c; + } +} + +uint32_t UpdateCrc32(uint32_t start, const void* buf, size_t len) { + EnsureCrc32TableInited(); + + uint32_t c = start ^ 0xFFFFFFFF; + const uint8_t* u = static_cast<const uint8_t*>(buf); + for (size_t i = 0; i < len; ++i) { + c = kCrc32Table[(c ^ u[i]) & 0xFF] ^ (c >> 8); + } + return c ^ 0xFFFFFFFF; +} + +} // namespace google_breakpad diff --git a/contrib/libs/breakpad/src/common/linux/crc32.h b/contrib/libs/breakpad/src/common/linux/crc32.h new file mode 100644 index 0000000000..e3d9db92be --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/crc32.h @@ -0,0 +1,53 @@ +// Copyright 2014 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. + +#ifndef COMMON_LINUX_CRC32_H_ +#define COMMON_LINUX_CRC32_H_ + +#include <stdint.h> + +#include <string> + +namespace google_breakpad { + +// Updates a CRC32 checksum with |len| bytes from |buf|. |initial| holds the +// checksum result from the previous update; for the first call, it should be 0. +uint32_t UpdateCrc32(uint32_t initial, const void* buf, size_t len); + +// Computes a CRC32 checksum using |len| bytes from |buf|. +inline uint32_t ComputeCrc32(const void* buf, size_t len) { + return UpdateCrc32(0, buf, len); +} +inline uint32_t ComputeCrc32(const std::string& str) { + return ComputeCrc32(str.c_str(), str.size()); +} + +} // namespace google_breakpad + +#endif // COMMON_LINUX_CRC32_H_ diff --git a/contrib/libs/breakpad/src/common/linux/dump_symbols.cc b/contrib/libs/breakpad/src/common/linux/dump_symbols.cc new file mode 100644 index 0000000000..75a4ceed27 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/dump_symbols.cc @@ -0,0 +1,1148 @@ +// Copyright (c) 2011 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. + +// Restructured in 2009 by: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> + +// dump_symbols.cc: implement google_breakpad::WriteSymbolFile: +// Find all the debugging info in a file and dump it as a Breakpad symbol file. + +#include "common/linux/dump_symbols.h" + +#include <assert.h> +#include <elf.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <link.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <iostream> +#include <set> +#include <string> +#include <utility> +#include <vector> + +#include "common/dwarf/bytereader-inl.h" +#include "common/dwarf/dwarf2diehandler.h" +#include "common/dwarf_cfi_to_module.h" +#include "common/dwarf_cu_to_module.h" +#include "common/dwarf_line_to_module.h" +#include "common/dwarf_range_list_handler.h" +#include "common/linux/crc32.h" +#include "common/linux/eintr_wrapper.h" +#include "common/linux/elfutils.h" +#include "common/linux/elfutils-inl.h" +#include "common/linux/elf_symbols_to_module.h" +#include "common/linux/file_id.h" +#include "common/memory_allocator.h" +#include "common/module.h" +#include "common/path_helper.h" +#include "common/scoped_ptr.h" +#ifndef NO_STABS_SUPPORT +#include "common/stabs_reader.h" +#include "common/stabs_to_module.h" +#endif +#include "common/using_std_string.h" + +// This namespace contains helper functions. +namespace { + +using google_breakpad::DumpOptions; +using google_breakpad::DwarfCFIToModule; +using google_breakpad::DwarfCUToModule; +using google_breakpad::DwarfLineToModule; +using google_breakpad::DwarfRangeListHandler; +using google_breakpad::ElfClass; +using google_breakpad::ElfClass32; +using google_breakpad::ElfClass64; +using google_breakpad::elf::FileID; +using google_breakpad::FindElfSectionByName; +using google_breakpad::GetOffset; +using google_breakpad::IsValidElf; +using google_breakpad::elf::kDefaultBuildIdSize; +using google_breakpad::Module; +using google_breakpad::PageAllocator; +#ifndef NO_STABS_SUPPORT +using google_breakpad::StabsToModule; +#endif +using google_breakpad::scoped_ptr; +using google_breakpad::wasteful_vector; + +// Define AARCH64 ELF architecture if host machine does not include this define. +#ifndef EM_AARCH64 +#define EM_AARCH64 183 +#endif + +// +// FDWrapper +// +// Wrapper class to make sure opened file is closed. +// +class FDWrapper { + public: + explicit FDWrapper(int fd) : + fd_(fd) {} + ~FDWrapper() { + if (fd_ != -1) + close(fd_); + } + int get() { + return fd_; + } + int release() { + int fd = fd_; + fd_ = -1; + return fd; + } + private: + int fd_; +}; + +// +// MmapWrapper +// +// Wrapper class to make sure mapped regions are unmapped. +// +class MmapWrapper { + public: + MmapWrapper() : is_set_(false) {} + ~MmapWrapper() { + if (is_set_ && base_ != NULL) { + assert(size_ > 0); + munmap(base_, size_); + } + } + void set(void* mapped_address, size_t mapped_size) { + is_set_ = true; + base_ = mapped_address; + size_ = mapped_size; + } + void release() { + assert(is_set_); + is_set_ = false; + base_ = NULL; + size_ = 0; + } + + private: + bool is_set_; + void* base_; + size_t size_; +}; + +// Find the preferred loading address of the binary. +template<typename ElfClass> +typename ElfClass::Addr GetLoadingAddress( + const typename ElfClass::Phdr* program_headers, + int nheader) { + typedef typename ElfClass::Phdr Phdr; + + // For non-PIC executables (e_type == ET_EXEC), the load address is + // the start address of the first PT_LOAD segment. (ELF requires + // the segments to be sorted by load address.) For PIC executables + // and dynamic libraries (e_type == ET_DYN), this address will + // normally be zero. + for (int i = 0; i < nheader; ++i) { + const Phdr& header = program_headers[i]; + if (header.p_type == PT_LOAD) + return header.p_vaddr; + } + return 0; +} + +// Find the set of address ranges for all PT_LOAD segments. +template <typename ElfClass> +vector<Module::Range> GetPtLoadSegmentRanges( + const typename ElfClass::Phdr* program_headers, + int nheader) { + typedef typename ElfClass::Phdr Phdr; + vector<Module::Range> ranges; + + for (int i = 0; i < nheader; ++i) { + const Phdr& header = program_headers[i]; + if (header.p_type == PT_LOAD) { + ranges.push_back(Module::Range(header.p_vaddr, header.p_memsz)); + } + } + return ranges; +} + +#ifndef NO_STABS_SUPPORT +template<typename ElfClass> +bool LoadStabs(const typename ElfClass::Ehdr* elf_header, + const typename ElfClass::Shdr* stab_section, + const typename ElfClass::Shdr* stabstr_section, + const bool big_endian, + Module* module) { + // A callback object to handle data from the STABS reader. + StabsToModule handler(module); + // Find the addresses of the STABS data, and create a STABS reader object. + // On Linux, STABS entries always have 32-bit values, regardless of the + // address size of the architecture whose code they're describing, and + // the strings are always "unitized". + const uint8_t* stabs = + GetOffset<ElfClass, uint8_t>(elf_header, stab_section->sh_offset); + const uint8_t* stabstr = + GetOffset<ElfClass, uint8_t>(elf_header, stabstr_section->sh_offset); + google_breakpad::StabsReader reader(stabs, stab_section->sh_size, + stabstr, stabstr_section->sh_size, + big_endian, 4, true, &handler); + // Read the STABS data, and do post-processing. + if (!reader.Process()) + return false; + handler.Finalize(); + return true; +} +#endif // NO_STABS_SUPPORT + +// A range handler that accepts rangelist data parsed by +// google_breakpad::RangeListReader and populates a range vector (typically +// owned by a function) with the results. +class DumperRangesHandler : public DwarfCUToModule::RangesHandler { + public: + DumperRangesHandler(google_breakpad::ByteReader* reader) : + reader_(reader) { } + + bool ReadRanges( + enum google_breakpad::DwarfForm form, uint64_t data, + google_breakpad::RangeListReader::CURangesInfo* cu_info, + vector<Module::Range>* ranges) { + DwarfRangeListHandler handler(ranges); + google_breakpad::RangeListReader range_list_reader(reader_, cu_info, + &handler); + return range_list_reader.ReadRanges(form, data); + } + + private: + google_breakpad::ByteReader* reader_; +}; + +// A line-to-module loader that accepts line number info parsed by +// google_breakpad::LineInfo and populates a Module and a line vector +// with the results. +class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler { + public: + // Create a line-to-module converter using BYTE_READER. + explicit DumperLineToModule(google_breakpad::ByteReader* byte_reader) + : byte_reader_(byte_reader) { } + void StartCompilationUnit(const string& compilation_dir) { + compilation_dir_ = compilation_dir; + } + void ReadProgram(const uint8_t* program, + uint64_t length, + const uint8_t* string_section, + uint64_t string_section_length, + const uint8_t* line_string_section, + uint64_t line_string_section_length, + Module* module, + std::vector<Module::Line>* lines, + std::map<uint32_t, Module::File*>* files) { + DwarfLineToModule handler(module, compilation_dir_, lines, files); + google_breakpad::LineInfo parser(program, length, byte_reader_, + string_section, string_section_length, + line_string_section, + line_string_section_length, + &handler); + parser.Start(); + } + private: + string compilation_dir_; + google_breakpad::ByteReader* byte_reader_; +}; + +template<typename ElfClass> +bool LoadDwarf(const string& dwarf_filename, + const typename ElfClass::Ehdr* elf_header, + const bool big_endian, + bool handle_inter_cu_refs, + bool handle_inline, + Module* module) { + typedef typename ElfClass::Shdr Shdr; + + const google_breakpad::Endianness endianness = big_endian ? + google_breakpad::ENDIANNESS_BIG : google_breakpad::ENDIANNESS_LITTLE; + google_breakpad::ByteReader byte_reader(endianness); + + // Construct a context for this file. + DwarfCUToModule::FileContext file_context(dwarf_filename, + module, + handle_inter_cu_refs); + + // Build a map of the ELF file's sections. + const Shdr* sections = + GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff); + int num_sections = elf_header->e_shnum; + const Shdr* section_names = sections + elf_header->e_shstrndx; + for (int i = 0; i < num_sections; i++) { + const Shdr* section = §ions[i]; + string name = GetOffset<ElfClass, char>(elf_header, + section_names->sh_offset) + + section->sh_name; + const uint8_t* contents = GetOffset<ElfClass, uint8_t>(elf_header, + section->sh_offset); + file_context.AddSectionToSectionMap(name, contents, section->sh_size); + } + + // .debug_ranges and .debug_rnglists reader + DumperRangesHandler ranges_handler(&byte_reader); + + // Parse all the compilation units in the .debug_info section. + DumperLineToModule line_to_module(&byte_reader); + google_breakpad::SectionMap::const_iterator debug_info_entry = + file_context.section_map().find(".debug_info"); + assert(debug_info_entry != file_context.section_map().end()); + const std::pair<const uint8_t*, uint64_t>& debug_info_section = + debug_info_entry->second; + // This should never have been called if the file doesn't have a + // .debug_info section. + assert(debug_info_section.first); + uint64_t debug_info_length = debug_info_section.second; + for (uint64_t offset = 0; offset < debug_info_length;) { + // Make a handler for the root DIE that populates MODULE with the + // data that was found. + DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset); + DwarfCUToModule root_handler(&file_context, &line_to_module, + &ranges_handler, &reporter, handle_inline); + // Make a Dwarf2Handler that drives the DIEHandler. + google_breakpad::DIEDispatcher die_dispatcher(&root_handler); + // Make a DWARF parser for the compilation unit at OFFSET. + google_breakpad::CompilationUnit reader(dwarf_filename, + file_context.section_map(), + offset, + &byte_reader, + &die_dispatcher); + // Process the entire compilation unit; get the offset of the next. + offset += reader.Start(); + } + return true; +} + +// Fill REGISTER_NAMES with the register names appropriate to the +// machine architecture given in HEADER, indexed by the register +// numbers used in DWARF call frame information. Return true on +// success, or false if HEADER's machine architecture is not +// supported. +template<typename ElfClass> +bool DwarfCFIRegisterNames(const typename ElfClass::Ehdr* elf_header, + std::vector<string>* register_names) { + switch (elf_header->e_machine) { + case EM_386: + *register_names = DwarfCFIToModule::RegisterNames::I386(); + return true; + case EM_ARM: + *register_names = DwarfCFIToModule::RegisterNames::ARM(); + return true; + case EM_AARCH64: + *register_names = DwarfCFIToModule::RegisterNames::ARM64(); + return true; + case EM_MIPS: + *register_names = DwarfCFIToModule::RegisterNames::MIPS(); + return true; + case EM_X86_64: + *register_names = DwarfCFIToModule::RegisterNames::X86_64(); + return true; + default: + return false; + } +} + +template<typename ElfClass> +bool LoadDwarfCFI(const string& dwarf_filename, + const typename ElfClass::Ehdr* elf_header, + const char* section_name, + const typename ElfClass::Shdr* section, + const bool eh_frame, + const typename ElfClass::Shdr* got_section, + const typename ElfClass::Shdr* text_section, + const bool big_endian, + Module* module) { + // Find the appropriate set of register names for this file's + // architecture. + std::vector<string> register_names; + if (!DwarfCFIRegisterNames<ElfClass>(elf_header, ®ister_names)) { + fprintf(stderr, "%s: unrecognized ELF machine architecture '%d';" + " cannot convert DWARF call frame information\n", + dwarf_filename.c_str(), elf_header->e_machine); + return false; + } + + const google_breakpad::Endianness endianness = big_endian ? + google_breakpad::ENDIANNESS_BIG : google_breakpad::ENDIANNESS_LITTLE; + + // Find the call frame information and its size. + const uint8_t* cfi = + GetOffset<ElfClass, uint8_t>(elf_header, section->sh_offset); + size_t cfi_size = section->sh_size; + + // Plug together the parser, handler, and their entourages. + DwarfCFIToModule::Reporter module_reporter(dwarf_filename, section_name); + DwarfCFIToModule handler(module, register_names, &module_reporter); + google_breakpad::ByteReader byte_reader(endianness); + + byte_reader.SetAddressSize(ElfClass::kAddrSize); + + // Provide the base addresses for .eh_frame encoded pointers, if + // possible. + byte_reader.SetCFIDataBase(section->sh_addr, cfi); + if (got_section) + byte_reader.SetDataBase(got_section->sh_addr); + if (text_section) + byte_reader.SetTextBase(text_section->sh_addr); + + google_breakpad::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename, + section_name); + google_breakpad::CallFrameInfo parser(cfi, cfi_size, + &byte_reader, &handler, &dwarf_reporter, + eh_frame); + parser.Start(); + return true; +} + +bool LoadELF(const string& obj_file, MmapWrapper* map_wrapper, + void** elf_header) { + int obj_fd = open(obj_file.c_str(), O_RDONLY); + if (obj_fd < 0) { + fprintf(stderr, "Failed to open ELF file '%s': %s\n", + obj_file.c_str(), strerror(errno)); + return false; + } + FDWrapper obj_fd_wrapper(obj_fd); + struct stat st; + if (fstat(obj_fd, &st) != 0 && st.st_size <= 0) { + fprintf(stderr, "Unable to fstat ELF file '%s': %s\n", + obj_file.c_str(), strerror(errno)); + return false; + } + void* obj_base = mmap(NULL, st.st_size, + PROT_READ | PROT_WRITE, MAP_PRIVATE, obj_fd, 0); + if (obj_base == MAP_FAILED) { + fprintf(stderr, "Failed to mmap ELF file '%s': %s\n", + obj_file.c_str(), strerror(errno)); + return false; + } + map_wrapper->set(obj_base, st.st_size); + *elf_header = obj_base; + if (!IsValidElf(*elf_header)) { + fprintf(stderr, "Not a valid ELF file: %s\n", obj_file.c_str()); + return false; + } + return true; +} + +// Get the endianness of ELF_HEADER. If it's invalid, return false. +template<typename ElfClass> +bool ElfEndianness(const typename ElfClass::Ehdr* elf_header, + bool* big_endian) { + if (elf_header->e_ident[EI_DATA] == ELFDATA2LSB) { + *big_endian = false; + return true; + } + if (elf_header->e_ident[EI_DATA] == ELFDATA2MSB) { + *big_endian = true; + return true; + } + + fprintf(stderr, "bad data encoding in ELF header: %d\n", + elf_header->e_ident[EI_DATA]); + return false; +} + +// Given |left_abspath|, find the absolute path for |right_path| and see if the +// two absolute paths are the same. +bool IsSameFile(const char* left_abspath, const string& right_path) { + char right_abspath[PATH_MAX]; + if (!realpath(right_path.c_str(), right_abspath)) + return false; + return strcmp(left_abspath, right_abspath) == 0; +} + +// Read the .gnu_debuglink and get the debug file name. If anything goes +// wrong, return an empty string. +string ReadDebugLink(const uint8_t* debuglink, + const size_t debuglink_size, + const bool big_endian, + const string& obj_file, + const std::vector<string>& debug_dirs) { + // Include '\0' + CRC32 (4 bytes). + size_t debuglink_len = strlen(reinterpret_cast<const char*>(debuglink)) + 5; + debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round up to 4 bytes. + + // Sanity check. + if (debuglink_len != debuglink_size) { + fprintf(stderr, "Mismatched .gnu_debuglink string / section size: " + "%zx %zx\n", debuglink_len, debuglink_size); + return string(); + } + + char obj_file_abspath[PATH_MAX]; + if (!realpath(obj_file.c_str(), obj_file_abspath)) { + fprintf(stderr, "Cannot resolve absolute path for %s\n", obj_file.c_str()); + return string(); + } + + std::vector<string> searched_paths; + string debuglink_path; + std::vector<string>::const_iterator it; + for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) { + const string& debug_dir = *it; + debuglink_path = debug_dir + "/" + + reinterpret_cast<const char*>(debuglink); + + // There is the annoying case of /path/to/foo.so having foo.so as the + // debug link file name. Thus this may end up opening /path/to/foo.so again, + // and there is a small chance of the two files having the same CRC. + if (IsSameFile(obj_file_abspath, debuglink_path)) + continue; + + searched_paths.push_back(debug_dir); + int debuglink_fd = open(debuglink_path.c_str(), O_RDONLY); + if (debuglink_fd < 0) + continue; + + FDWrapper debuglink_fd_wrapper(debuglink_fd); + + // The CRC is the last 4 bytes in |debuglink|. + const google_breakpad::Endianness endianness = big_endian ? + google_breakpad::ENDIANNESS_BIG : google_breakpad::ENDIANNESS_LITTLE; + google_breakpad::ByteReader byte_reader(endianness); + uint32_t expected_crc = + byte_reader.ReadFourBytes(&debuglink[debuglink_size - 4]); + + uint32_t actual_crc = 0; + while (true) { + const size_t kReadSize = 4096; + char buf[kReadSize]; + ssize_t bytes_read = HANDLE_EINTR(read(debuglink_fd, &buf, kReadSize)); + if (bytes_read < 0) { + fprintf(stderr, "Error reading debug ELF file %s.\n", + debuglink_path.c_str()); + return string(); + } + if (bytes_read == 0) + break; + actual_crc = google_breakpad::UpdateCrc32(actual_crc, buf, bytes_read); + } + if (actual_crc != expected_crc) { + fprintf(stderr, "Error reading debug ELF file - CRC32 mismatch: %s\n", + debuglink_path.c_str()); + continue; + } + + // Found debug file. + return debuglink_path; + } + + // Not found case. + fprintf(stderr, "Failed to find debug ELF file for '%s' after trying:\n", + obj_file.c_str()); + for (it = searched_paths.begin(); it < searched_paths.end(); ++it) { + const string& debug_dir = *it; + fprintf(stderr, " %s/%s\n", debug_dir.c_str(), debuglink); + } + return string(); +} + +// +// LoadSymbolsInfo +// +// Holds the state between the two calls to LoadSymbols() in case it's necessary +// to follow the .gnu_debuglink section and load debug information from a +// different file. +// +template<typename ElfClass> +class LoadSymbolsInfo { + public: + typedef typename ElfClass::Addr Addr; + + explicit LoadSymbolsInfo(const std::vector<string>& dbg_dirs) : + debug_dirs_(dbg_dirs), + has_loading_addr_(false) {} + + // Keeps track of which sections have been loaded so sections don't + // accidentally get loaded twice from two different files. + void LoadedSection(const string& section) { + if (loaded_sections_.count(section) == 0) { + loaded_sections_.insert(section); + } else { + fprintf(stderr, "Section %s has already been loaded.\n", + section.c_str()); + } + } + + // The ELF file and linked debug file are expected to have the same preferred + // loading address. + void set_loading_addr(Addr addr, const string& filename) { + if (!has_loading_addr_) { + loading_addr_ = addr; + loaded_file_ = filename; + return; + } + + if (addr != loading_addr_) { + fprintf(stderr, + "ELF file '%s' and debug ELF file '%s' " + "have different load addresses.\n", + loaded_file_.c_str(), filename.c_str()); + assert(false); + } + } + + // Setters and getters + const std::vector<string>& debug_dirs() const { + return debug_dirs_; + } + + string debuglink_file() const { + return debuglink_file_; + } + void set_debuglink_file(string file) { + debuglink_file_ = file; + } + + private: + const std::vector<string>& debug_dirs_; // Directories in which to + // search for the debug ELF file. + + string debuglink_file_; // Full path to the debug ELF file. + + bool has_loading_addr_; // Indicate if LOADING_ADDR_ is valid. + + Addr loading_addr_; // Saves the preferred loading address from the + // first call to LoadSymbols(). + + string loaded_file_; // Name of the file loaded from the first call to + // LoadSymbols(). + + std::set<string> loaded_sections_; // Tracks the Loaded ELF sections + // between calls to LoadSymbols(). +}; + +template<typename ElfClass> +bool LoadSymbols(const string& obj_file, + const bool big_endian, + const typename ElfClass::Ehdr* elf_header, + const bool read_gnu_debug_link, + LoadSymbolsInfo<ElfClass>* info, + const DumpOptions& options, + Module* module) { + typedef typename ElfClass::Addr Addr; + typedef typename ElfClass::Phdr Phdr; + typedef typename ElfClass::Shdr Shdr; + + Addr loading_addr = GetLoadingAddress<ElfClass>( + GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff), + elf_header->e_phnum); + module->SetLoadAddress(loading_addr); + info->set_loading_addr(loading_addr, obj_file); + + // Allow filtering of extraneous debug information in partitioned libraries. + // Such libraries contain debug information for all libraries extracted from + // the same combined library, implying extensive duplication. + vector<Module::Range> address_ranges = GetPtLoadSegmentRanges<ElfClass>( + GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff), + elf_header->e_phnum); + module->SetAddressRanges(address_ranges); + + const Shdr* sections = + GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff); + const Shdr* section_names = sections + elf_header->e_shstrndx; + const char* names = + GetOffset<ElfClass, char>(elf_header, section_names->sh_offset); + const char* names_end = names + section_names->sh_size; + bool found_debug_info_section = false; + bool found_usable_info = false; + + if ((options.symbol_data & SYMBOLS_AND_FILES) || + (options.symbol_data & INLINES)) { +#ifndef NO_STABS_SUPPORT + // Look for STABS debugging information, and load it if present. + const Shdr* stab_section = + FindElfSectionByName<ElfClass>(".stab", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + if (stab_section) { + const Shdr* stabstr_section = stab_section->sh_link + sections; + if (stabstr_section) { + found_debug_info_section = true; + found_usable_info = true; + info->LoadedSection(".stab"); + if (!LoadStabs<ElfClass>(elf_header, stab_section, stabstr_section, + big_endian, module)) { + fprintf(stderr, "%s: \".stab\" section found, but failed to load" + " STABS debugging information\n", obj_file.c_str()); + } + } + } +#endif // NO_STABS_SUPPORT + + // See if there are export symbols available. + const Shdr* symtab_section = + FindElfSectionByName<ElfClass>(".symtab", SHT_SYMTAB, + sections, names, names_end, + elf_header->e_shnum); + const Shdr* strtab_section = + FindElfSectionByName<ElfClass>(".strtab", SHT_STRTAB, + sections, names, names_end, + elf_header->e_shnum); + if (symtab_section && strtab_section) { + info->LoadedSection(".symtab"); + + const uint8_t* symtab = + GetOffset<ElfClass, uint8_t>(elf_header, + symtab_section->sh_offset); + const uint8_t* strtab = + GetOffset<ElfClass, uint8_t>(elf_header, + strtab_section->sh_offset); + bool result = + ELFSymbolsToModule(symtab, + symtab_section->sh_size, + strtab, + strtab_section->sh_size, + big_endian, + ElfClass::kAddrSize, + module); + found_usable_info = found_usable_info || result; + } else { + // Look in dynsym only if full symbol table was not available. + const Shdr* dynsym_section = + FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM, + sections, names, names_end, + elf_header->e_shnum); + const Shdr* dynstr_section = + FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB, + sections, names, names_end, + elf_header->e_shnum); + if (dynsym_section && dynstr_section) { + info->LoadedSection(".dynsym"); + + const uint8_t* dynsyms = + GetOffset<ElfClass, uint8_t>(elf_header, + dynsym_section->sh_offset); + const uint8_t* dynstrs = + GetOffset<ElfClass, uint8_t>(elf_header, + dynstr_section->sh_offset); + bool result = + ELFSymbolsToModule(dynsyms, + dynsym_section->sh_size, + dynstrs, + dynstr_section->sh_size, + big_endian, + ElfClass::kAddrSize, + module); + found_usable_info = found_usable_info || result; + } + } + + // Only Load .debug_info after loading symbol table to avoid duplicate + // PUBLIC records. + // Look for DWARF debugging information, and load it if present. + const Shdr* dwarf_section = + FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + + // .debug_info section type is SHT_PROGBITS for mips on pnacl toolchains, + // but MIPS_DWARF for regular gnu toolchains, so both need to be checked + if (elf_header->e_machine == EM_MIPS && !dwarf_section) { + dwarf_section = + FindElfSectionByName<ElfClass>(".debug_info", SHT_MIPS_DWARF, + sections, names, names_end, + elf_header->e_shnum); + } + + if (dwarf_section) { + found_debug_info_section = true; + found_usable_info = true; + info->LoadedSection(".debug_info"); + if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian, + options.handle_inter_cu_refs, + options.symbol_data & INLINES, module)) { + fprintf(stderr, "%s: \".debug_info\" section found, but failed to load " + "DWARF debugging information\n", obj_file.c_str()); + } + } + } + + if (options.symbol_data & CFI) { + // Dwarf Call Frame Information (CFI) is actually independent from + // the other DWARF debugging information, and can be used alone. + const Shdr* dwarf_cfi_section = + FindElfSectionByName<ElfClass>(".debug_frame", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + + // .debug_frame section type is SHT_PROGBITS for mips on pnacl toolchains, + // but MIPS_DWARF for regular gnu toolchains, so both need to be checked + if (elf_header->e_machine == EM_MIPS && !dwarf_cfi_section) { + dwarf_cfi_section = + FindElfSectionByName<ElfClass>(".debug_frame", SHT_MIPS_DWARF, + sections, names, names_end, + elf_header->e_shnum); + } + + if (dwarf_cfi_section) { + // Ignore the return value of this function; even without call frame + // information, the other debugging information could be perfectly + // useful. + info->LoadedSection(".debug_frame"); + bool result = + LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".debug_frame", + dwarf_cfi_section, false, 0, 0, big_endian, + module); + found_usable_info = found_usable_info || result; + } + + // Linux C++ exception handling information can also provide + // unwinding data. + const Shdr* eh_frame_section = + FindElfSectionByName<ElfClass>(".eh_frame", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + if (eh_frame_section) { + // Pointers in .eh_frame data may be relative to the base addresses of + // certain sections. Provide those sections if present. + const Shdr* got_section = + FindElfSectionByName<ElfClass>(".got", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + const Shdr* text_section = + FindElfSectionByName<ElfClass>(".text", SHT_PROGBITS, + sections, names, names_end, + elf_header->e_shnum); + info->LoadedSection(".eh_frame"); + // As above, ignore the return value of this function. + bool result = + LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".eh_frame", + eh_frame_section, true, + got_section, text_section, big_endian, module); + found_usable_info = found_usable_info || result; + } + } + + if (!found_debug_info_section) { + fprintf(stderr, "%s: file contains no debugging information" + " (no \".stab\" or \".debug_info\" sections)\n", + obj_file.c_str()); + + // Failed, but maybe there's a .gnu_debuglink section? + if (read_gnu_debug_link) { + const Shdr* gnu_debuglink_section + = FindElfSectionByName<ElfClass>(".gnu_debuglink", SHT_PROGBITS, + sections, names, + names_end, elf_header->e_shnum); + if (gnu_debuglink_section) { + if (!info->debug_dirs().empty()) { + const uint8_t* debuglink_contents = + GetOffset<ElfClass, uint8_t>(elf_header, + gnu_debuglink_section->sh_offset); + string debuglink_file = + ReadDebugLink(debuglink_contents, + gnu_debuglink_section->sh_size, + big_endian, + obj_file, + info->debug_dirs()); + info->set_debuglink_file(debuglink_file); + } else { + fprintf(stderr, ".gnu_debuglink section found in '%s', " + "but no debug path specified.\n", obj_file.c_str()); + } + } else { + fprintf(stderr, "%s does not contain a .gnu_debuglink section.\n", + obj_file.c_str()); + } + } else { + // Return true if some usable information was found, since the caller + // doesn't want to use .gnu_debuglink. + return found_usable_info; + } + + // No debug info was found, let the user try again with .gnu_debuglink + // if present. + return false; + } + + return true; +} + +// Return the breakpad symbol file identifier for the architecture of +// ELF_HEADER. +template<typename ElfClass> +const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) { + typedef typename ElfClass::Half Half; + Half arch = elf_header->e_machine; + switch (arch) { + case EM_386: return "x86"; + case EM_ARM: return "arm"; + case EM_AARCH64: return "arm64"; + case EM_MIPS: return "mips"; + case EM_PPC64: return "ppc64"; + case EM_PPC: return "ppc"; + case EM_S390: return "s390"; + case EM_SPARC: return "sparc"; + case EM_SPARCV9: return "sparcv9"; + case EM_X86_64: return "x86_64"; + default: return NULL; + } +} + +template<typename ElfClass> +bool SanitizeDebugFile(const typename ElfClass::Ehdr* debug_elf_header, + const string& debuglink_file, + const string& obj_filename, + const char* obj_file_architecture, + const bool obj_file_is_big_endian) { + const char* debug_architecture = + ElfArchitecture<ElfClass>(debug_elf_header); + if (!debug_architecture) { + fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n", + debuglink_file.c_str(), debug_elf_header->e_machine); + return false; + } + if (strcmp(obj_file_architecture, debug_architecture)) { + fprintf(stderr, "%s with ELF machine architecture %s does not match " + "%s with ELF architecture %s\n", + debuglink_file.c_str(), debug_architecture, + obj_filename.c_str(), obj_file_architecture); + return false; + } + bool debug_big_endian; + if (!ElfEndianness<ElfClass>(debug_elf_header, &debug_big_endian)) + return false; + if (debug_big_endian != obj_file_is_big_endian) { + fprintf(stderr, "%s and %s does not match in endianness\n", + obj_filename.c_str(), debuglink_file.c_str()); + return false; + } + return true; +} + +template<typename ElfClass> +bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header, + const string& obj_filename, + const string& obj_os, + scoped_ptr<Module>& module) { + PageAllocator allocator; + wasteful_vector<uint8_t> identifier(&allocator, kDefaultBuildIdSize); + if (!FileID::ElfFileIdentifierFromMappedFile(elf_header, identifier)) { + fprintf(stderr, "%s: unable to generate file identifier\n", + obj_filename.c_str()); + return false; + } + + const char* architecture = ElfArchitecture<ElfClass>(elf_header); + if (!architecture) { + fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n", + obj_filename.c_str(), elf_header->e_machine); + return false; + } + + char name_buf[NAME_MAX] = {}; + std::string name = google_breakpad::ElfFileSoNameFromMappedFile( + elf_header, name_buf, sizeof(name_buf)) + ? name_buf + : google_breakpad::BaseName(obj_filename); + + // Add an extra "0" at the end. PDB files on Windows have an 'age' + // number appended to the end of the file identifier; this isn't + // really used or necessary on other platforms, but be consistent. + string id = FileID::ConvertIdentifierToUUIDString(identifier) + "0"; + // This is just the raw Build ID in hex. + string code_id = FileID::ConvertIdentifierToString(identifier); + + module.reset(new Module(name, obj_os, architecture, id, code_id)); + + return true; +} + +template<typename ElfClass> +bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header, + const string& obj_filename, + const string& obj_os, + const std::vector<string>& debug_dirs, + const DumpOptions& options, + Module** out_module) { + typedef typename ElfClass::Ehdr Ehdr; + + *out_module = NULL; + + scoped_ptr<Module> module; + if (!InitModuleForElfClass<ElfClass>(elf_header, obj_filename, obj_os, + module)) { + return false; + } + + // Figure out what endianness this file is. + bool big_endian; + if (!ElfEndianness<ElfClass>(elf_header, &big_endian)) + return false; + + LoadSymbolsInfo<ElfClass> info(debug_dirs); + if (!LoadSymbols<ElfClass>(obj_filename, big_endian, elf_header, + !debug_dirs.empty(), &info, + options, module.get())) { + const string debuglink_file = info.debuglink_file(); + if (debuglink_file.empty()) + return false; + + // Load debuglink ELF file. + fprintf(stderr, "Found debugging info in %s\n", debuglink_file.c_str()); + MmapWrapper debug_map_wrapper; + Ehdr* debug_elf_header = NULL; + if (!LoadELF(debuglink_file, &debug_map_wrapper, + reinterpret_cast<void**>(&debug_elf_header)) || + !SanitizeDebugFile<ElfClass>(debug_elf_header, debuglink_file, + obj_filename, + module->architecture().c_str(), + big_endian)) { + return false; + } + + if (!LoadSymbols<ElfClass>(debuglink_file, big_endian, + debug_elf_header, false, &info, + options, module.get())) { + return false; + } + } + + *out_module = module.release(); + return true; +} + +} // namespace + +namespace google_breakpad { + +// Not explicitly exported, but not static so it can be used in unit tests. +bool ReadSymbolDataInternal(const uint8_t* obj_file, + const string& obj_filename, + const string& obj_os, + const std::vector<string>& debug_dirs, + const DumpOptions& options, + Module** module) { + if (!IsValidElf(obj_file)) { + fprintf(stderr, "Not a valid ELF file: %s\n", obj_filename.c_str()); + return false; + } + + int elfclass = ElfClass(obj_file); + if (elfclass == ELFCLASS32) { + return ReadSymbolDataElfClass<ElfClass32>( + reinterpret_cast<const Elf32_Ehdr*>(obj_file), obj_filename, obj_os, + debug_dirs, options, module); + } + if (elfclass == ELFCLASS64) { + return ReadSymbolDataElfClass<ElfClass64>( + reinterpret_cast<const Elf64_Ehdr*>(obj_file), obj_filename, obj_os, + debug_dirs, options, module); + } + + return false; +} + +bool WriteSymbolFile(const string& load_path, + const string& obj_file, + const string& obj_os, + const std::vector<string>& debug_dirs, + const DumpOptions& options, + std::ostream& sym_stream) { + Module* module; + if (!ReadSymbolData(load_path, obj_file, obj_os, debug_dirs, options, + &module)) + return false; + + bool result = module->Write(sym_stream, options.symbol_data); + delete module; + return result; +} + +// Read the selected object file's debugging information, and write out the +// header only to |stream|. Return true on success; if an error occurs, report +// it and return false. +bool WriteSymbolFileHeader(const string& load_path, + const string& obj_file, + const string& obj_os, + std::ostream& sym_stream) { + MmapWrapper map_wrapper; + void* elf_header = NULL; + if (!LoadELF(load_path, &map_wrapper, &elf_header)) { + fprintf(stderr, "Could not load ELF file: %s\n", obj_file.c_str()); + return false; + } + + if (!IsValidElf(elf_header)) { + fprintf(stderr, "Not a valid ELF file: %s\n", obj_file.c_str()); + return false; + } + + int elfclass = ElfClass(elf_header); + scoped_ptr<Module> module; + if (elfclass == ELFCLASS32) { + if (!InitModuleForElfClass<ElfClass32>( + reinterpret_cast<const Elf32_Ehdr*>(elf_header), obj_file, obj_os, + module)) { + fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str()); + return false; + } + } else if (elfclass == ELFCLASS64) { + if (!InitModuleForElfClass<ElfClass64>( + reinterpret_cast<const Elf64_Ehdr*>(elf_header), obj_file, obj_os, + module)) { + fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str()); + return false; + } + } else { + fprintf(stderr, "Unsupported module file: %s\n", obj_file.c_str()); + return false; + } + + return module->Write(sym_stream, ALL_SYMBOL_DATA); +} + +bool ReadSymbolData(const string& load_path, + const string& obj_file, + const string& obj_os, + const std::vector<string>& debug_dirs, + const DumpOptions& options, + Module** module) { + MmapWrapper map_wrapper; + void* elf_header = NULL; + if (!LoadELF(load_path, &map_wrapper, &elf_header)) + return false; + + return ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(elf_header), + obj_file, obj_os, debug_dirs, options, module); +} + +} // namespace google_breakpad diff --git a/contrib/libs/breakpad/src/common/linux/dump_symbols.h b/contrib/libs/breakpad/src/common/linux/dump_symbols.h new file mode 100644 index 0000000000..b033ce00ea --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/dump_symbols.h @@ -0,0 +1,93 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2011, 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. + +// dump_symbols.h: Read debugging information from an ELF file, and write +// it out as a Breakpad symbol file. + +#ifndef COMMON_LINUX_DUMP_SYMBOLS_H__ +#define COMMON_LINUX_DUMP_SYMBOLS_H__ + +#include <iostream> +#include <string> +#include <vector> + +#include "common/symbol_data.h" +#include "common/using_std_string.h" + +namespace google_breakpad { + +class Module; + +struct DumpOptions { + DumpOptions(SymbolData symbol_data, bool handle_inter_cu_refs) + : symbol_data(symbol_data), + handle_inter_cu_refs(handle_inter_cu_refs) { + } + + SymbolData symbol_data; + bool handle_inter_cu_refs; +}; + +// Find all the debugging information in OBJ_FILE, an ELF executable +// or shared library, and write it to SYM_STREAM in the Breakpad symbol +// file format. +// If OBJ_FILE has been stripped but contains a .gnu_debuglink section, +// then look for the debug file in DEBUG_DIRS. +// SYMBOL_DATA allows limiting the type of symbol data written. +bool WriteSymbolFile(const string& load_path, + const string& obj_file, + const string& obj_os, + const std::vector<string>& debug_dirs, + const DumpOptions& options, + std::ostream& sym_stream); + +// Read the selected object file's debugging information, and write out the +// header only to |stream|. Return true on success; if an error occurs, report +// it and return false. |obj_file| becomes the MODULE file name and |obj_os| +// becomes the MODULE operating system. +bool WriteSymbolFileHeader(const string& load_path, + const string& obj_file, + const string& obj_os, + std::ostream& sym_stream); + +// As above, but simply return the debugging information in MODULE +// instead of writing it to a stream. The caller owns the resulting +// Module object and must delete it when finished. +bool ReadSymbolData(const string& load_path, + const string& obj_file, + const string& obj_os, + const std::vector<string>& debug_dirs, + const DumpOptions& options, + Module** module); + +} // namespace google_breakpad + +#endif // COMMON_LINUX_DUMP_SYMBOLS_H__ diff --git a/contrib/libs/breakpad/src/common/linux/eintr_wrapper.h b/contrib/libs/breakpad/src/common/linux/eintr_wrapper.h new file mode 100644 index 0000000000..3f1d184817 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/eintr_wrapper.h @@ -0,0 +1,58 @@ +// Copyright (c) 2010 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. + +#ifndef COMMON_LINUX_EINTR_WRAPPER_H_ +#define COMMON_LINUX_EINTR_WRAPPER_H_ + +#include <errno.h> + +// This provides a wrapper around system calls which may be interrupted by a +// signal and return EINTR. See man 7 signal. +// + +#define HANDLE_EINTR(x) ({ \ + __typeof__(x) eintr_wrapper_result; \ + do { \ + eintr_wrapper_result = (x); \ + } while (eintr_wrapper_result == -1 && errno == EINTR); \ + eintr_wrapper_result; \ +}) + +#define IGNORE_EINTR(x) ({ \ + __typeof__(x) eintr_wrapper_result; \ + do { \ + eintr_wrapper_result = (x); \ + if (eintr_wrapper_result == -1 && errno == EINTR) { \ + eintr_wrapper_result = 0; \ + } \ + } while (0); \ + eintr_wrapper_result; \ +}) + +#endif // COMMON_LINUX_EINTR_WRAPPER_H_ diff --git a/contrib/libs/breakpad/src/common/linux/elf_core_dump.cc b/contrib/libs/breakpad/src/common/linux/elf_core_dump.cc new file mode 100644 index 0000000000..f3206092b3 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/elf_core_dump.cc @@ -0,0 +1,203 @@ +// Copyright (c) 2011, 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. + +// elf_core_dump.cc: Implement google_breakpad::ElfCoreDump. +// See elf_core_dump.h for details. + +#include "common/linux/elf_core_dump.h" + +#include <stddef.h> +#include <string.h> +#include <unistd.h> + +namespace google_breakpad { + +// Implementation of ElfCoreDump::Note. + +ElfCoreDump::Note::Note() {} + +ElfCoreDump::Note::Note(const MemoryRange& content) : content_(content) {} + +bool ElfCoreDump::Note::IsValid() const { + return GetHeader() != NULL; +} + +const ElfCoreDump::Nhdr* ElfCoreDump::Note::GetHeader() const { + return content_.GetData<Nhdr>(0); +} + +ElfCoreDump::Word ElfCoreDump::Note::GetType() const { + const Nhdr* header = GetHeader(); + // 0 is not being used as a NOTE type. + return header ? header->n_type : 0; +} + +MemoryRange ElfCoreDump::Note::GetName() const { + const Nhdr* header = GetHeader(); + if (header) { + return content_.Subrange(sizeof(Nhdr), header->n_namesz); + } + return MemoryRange(); +} + +MemoryRange ElfCoreDump::Note::GetDescription() const { + const Nhdr* header = GetHeader(); + if (header) { + return content_.Subrange(AlignedSize(sizeof(Nhdr) + header->n_namesz), + header->n_descsz); + } + return MemoryRange(); +} + +ElfCoreDump::Note ElfCoreDump::Note::GetNextNote() const { + MemoryRange next_content; + const Nhdr* header = GetHeader(); + if (header) { + size_t next_offset = AlignedSize(sizeof(Nhdr) + header->n_namesz); + next_offset = AlignedSize(next_offset + header->n_descsz); + next_content = + content_.Subrange(next_offset, content_.length() - next_offset); + } + return Note(next_content); +} + +// static +size_t ElfCoreDump::Note::AlignedSize(size_t size) { + size_t mask = sizeof(Word) - 1; + return (size + mask) & ~mask; +} + + +// Implementation of ElfCoreDump. + +ElfCoreDump::ElfCoreDump() : proc_mem_fd_(-1) {} + +ElfCoreDump::ElfCoreDump(const MemoryRange& content) + : content_(content), proc_mem_fd_(-1) {} + +ElfCoreDump::~ElfCoreDump() { + if (proc_mem_fd_ != -1) { + close(proc_mem_fd_); + proc_mem_fd_ = -1; + } +} + +void ElfCoreDump::SetContent(const MemoryRange& content) { + content_ = content; +} + +void ElfCoreDump::SetProcMem(int fd) { + if (proc_mem_fd_ != -1) { + close(proc_mem_fd_); + } + proc_mem_fd_ = fd; +} + +bool ElfCoreDump::IsValid() const { + const Ehdr* header = GetHeader(); + return (header && + header->e_ident[0] == ELFMAG0 && + header->e_ident[1] == ELFMAG1 && + header->e_ident[2] == ELFMAG2 && + header->e_ident[3] == ELFMAG3 && + header->e_ident[4] == kClass && + header->e_version == EV_CURRENT && + header->e_type == ET_CORE); +} + +const ElfCoreDump::Ehdr* ElfCoreDump::GetHeader() const { + return content_.GetData<Ehdr>(0); +} + +const ElfCoreDump::Phdr* ElfCoreDump::GetProgramHeader(unsigned index) const { + const Ehdr* header = GetHeader(); + if (header) { + return reinterpret_cast<const Phdr*>(content_.GetArrayElement( + header->e_phoff, header->e_phentsize, index)); + } + return NULL; +} + +const ElfCoreDump::Phdr* ElfCoreDump::GetFirstProgramHeaderOfType( + Word type) const { + for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) { + const Phdr* program = GetProgramHeader(i); + if (program->p_type == type) { + return program; + } + } + return NULL; +} + +unsigned ElfCoreDump::GetProgramHeaderCount() const { + const Ehdr* header = GetHeader(); + return header ? header->e_phnum : 0; +} + +bool ElfCoreDump::CopyData(void* buffer, Addr virtual_address, size_t length) { + for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) { + const Phdr* program = GetProgramHeader(i); + if (program->p_type != PT_LOAD) + continue; + + size_t offset_in_segment = virtual_address - program->p_vaddr; + if (virtual_address >= program->p_vaddr && + offset_in_segment < program->p_filesz) { + const void* data = + content_.GetData(program->p_offset + offset_in_segment, length); + if (data) { + memcpy(buffer, data, length); + return true; + } + } + } + + /* fallback: if available, read from /proc/<pid>/mem */ + if (proc_mem_fd_ != -1) { + off_t offset = virtual_address; + ssize_t r = pread(proc_mem_fd_, buffer, length, offset); + if (r < ssize_t(length)) { + return false; + } + return true; + } + return false; +} + +ElfCoreDump::Note ElfCoreDump::GetFirstNote() const { + MemoryRange note_content; + const Phdr* program_header = GetFirstProgramHeaderOfType(PT_NOTE); + if (program_header) { + note_content = content_.Subrange(program_header->p_offset, + program_header->p_filesz); + } + return Note(note_content); +} + +} // namespace google_breakpad diff --git a/contrib/libs/breakpad/src/common/linux/elf_core_dump.h b/contrib/libs/breakpad/src/common/linux/elf_core_dump.h new file mode 100644 index 0000000000..c8117a0e26 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/elf_core_dump.h @@ -0,0 +1,157 @@ +// Copyright (c) 2011, 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. + +// elf_core_dump.h: Define the google_breakpad::ElfCoreDump class, which +// encapsulates an ELF core dump file mapped into memory. + +#ifndef COMMON_LINUX_ELF_CORE_DUMP_H_ +#define COMMON_LINUX_ELF_CORE_DUMP_H_ + +#include <elf.h> +#include <limits.h> +#include <link.h> +#include <stddef.h> + +#include "common/memory_range.h" + +namespace google_breakpad { + +// A class encapsulating an ELF core dump file mapped into memory, which +// provides methods for accessing program headers and the note section. +class ElfCoreDump { + public: + // ELF types based on the native word size. + typedef ElfW(Ehdr) Ehdr; + typedef ElfW(Nhdr) Nhdr; + typedef ElfW(Phdr) Phdr; + typedef ElfW(Word) Word; + typedef ElfW(Addr) Addr; +#if ULONG_MAX == 0xffffffff + static const int kClass = ELFCLASS32; +#elif ULONG_MAX == 0xffffffffffffffff + static const int kClass = ELFCLASS64; +#else +#error "Unsupported word size for ElfCoreDump." +#endif + + // A class encapsulating the note content in a core dump, which provides + // methods for accessing the name and description of a note. + class Note { + public: + Note(); + + // Constructor that takes the note content from |content|. + explicit Note(const MemoryRange& content); + + // Returns true if this note is valid, i,e. a note header is found in + // |content_|, or false otherwise. + bool IsValid() const; + + // Returns the note header, or NULL if no note header is found in + // |content_|. + const Nhdr* GetHeader() const; + + // Returns the note type, or 0 if no note header is found in |content_|. + Word GetType() const; + + // Returns a memory range covering the note name, or an empty range + // if no valid note name is found in |content_|. + MemoryRange GetName() const; + + // Returns a memory range covering the note description, or an empty + // range if no valid note description is found in |content_|. + MemoryRange GetDescription() const; + + // Returns the note following this note, or an empty note if no valid + // note is found after this note. + Note GetNextNote() const; + + private: + // Returns the size in bytes round up to the word alignment, specified + // for the note section, of a given size in bytes. + static size_t AlignedSize(size_t size); + + // Note content. + MemoryRange content_; + }; + + ElfCoreDump(); + + // Constructor that takes the core dump content from |content|. + explicit ElfCoreDump(const MemoryRange& content); + + ~ElfCoreDump(); + + // Sets the core dump content to |content|. + void SetContent(const MemoryRange& content); + + // Returns true if a valid ELF header in the core dump, or false otherwise. + bool IsValid() const; + + // Returns the ELF header in the core dump, or NULL if no ELF header + // is found in |content_|. + const Ehdr* GetHeader() const; + + // Returns the |index|-th program header in the core dump, or NULL if no + // ELF header is found in |content_| or |index| is out of bounds. + const Phdr* GetProgramHeader(unsigned index) const; + + // Returns the first program header of |type| in the core dump, or NULL if + // no ELF header is found in |content_| or no program header of |type| is + // found. + const Phdr* GetFirstProgramHeaderOfType(Word type) const; + + // Returns the number of program headers in the core dump, or 0 if no + // ELF header is found in |content_|. + unsigned GetProgramHeaderCount() const; + + // Copies |length| bytes of data starting at |virtual_address| in the core + // dump to |buffer|. |buffer| should be a valid pointer to a buffer of at + // least |length| bytes. Returns true if the data to be copied is found in + // the core dump, or false otherwise. + bool CopyData(void* buffer, Addr virtual_address, size_t length); + + // Returns the first note found in the note section of the core dump, or + // an empty note if no note is found. + Note GetFirstNote() const; + + // Sets the mem fd. + void SetProcMem(const int fd); + + private: + // Core dump content. + MemoryRange content_; + + // Descriptor for /proc/<pid>/mem. + int proc_mem_fd_; +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_ELF_CORE_DUMP_H_ diff --git a/contrib/libs/breakpad/src/common/linux/elf_gnu_compat.h b/contrib/libs/breakpad/src/common/linux/elf_gnu_compat.h new file mode 100644 index 0000000000..0a3dfedb57 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/elf_gnu_compat.h @@ -0,0 +1,51 @@ +// -*- mode: C++ -*- + +// Copyright (c) 2013, 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. + +// Original author: Lei Zhang <thestig@google.com> + +// elf_gnu_compat.h: #defines unique to glibc's elf.h. + +#ifndef COMMON_LINUX_ELF_GNU_COMPAT_H_ +#define COMMON_LINUX_ELF_GNU_COMPAT_H_ + +#include <elf.h> + +// A note type on GNU systems corresponding to the .note.gnu.build-id section. +#ifndef NT_GNU_BUILD_ID +#define NT_GNU_BUILD_ID 3 +#endif + +// Newer Linux systems offer this. +#ifndef NT_SIGINFO +#define NT_SIGINFO 0x53494749 +#endif + +#endif // COMMON_LINUX_ELF_GNU_COMPAT_H_ diff --git a/contrib/libs/breakpad/src/common/linux/elf_symbols_to_module.cc b/contrib/libs/breakpad/src/common/linux/elf_symbols_to_module.cc new file mode 100644 index 0000000000..81e985a722 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/elf_symbols_to_module.cc @@ -0,0 +1,178 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2011 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. + +// Original author: Ted Mielczarek <ted.mielczarek@gmail.com> + +#include "common/linux/elf_symbols_to_module.h" + +#include <cxxabi.h> +#include <elf.h> +#include <string.h> + +#include "common/byte_cursor.h" +#include "common/module.h" + +namespace google_breakpad { + +class ELFSymbolIterator { +public: + // The contents of an ELF symbol, adjusted for the host's endianness, + // word size, and so on. Corresponds to the data in Elf32_Sym / Elf64_Sym. + struct Symbol { + // True if this iterator has reached the end of the symbol array. When + // this is set, the other members of this structure are not valid. + bool at_end; + + // The number of this symbol within the list. + size_t index; + + // The current symbol's name offset. This is the offset within the + // string table. + size_t name_offset; + + // The current symbol's value, size, info and shndx fields. + uint64_t value; + uint64_t size; + unsigned char info; + uint16_t shndx; + }; + + // Create an ELFSymbolIterator walking the symbols in BUFFER. Treat the + // symbols as big-endian if BIG_ENDIAN is true, as little-endian + // otherwise. Assume each symbol has a 'value' field whose size is + // VALUE_SIZE. + // + ELFSymbolIterator(const ByteBuffer* buffer, bool big_endian, + size_t value_size) + : value_size_(value_size), cursor_(buffer, big_endian) { + // Actually, weird sizes could be handled just fine, but they're + // probably mistakes --- expressed in bits, say. + assert(value_size == 4 || value_size == 8); + symbol_.index = 0; + Fetch(); + } + + // Move to the next symbol. This function's behavior is undefined if + // at_end() is true when it is called. + ELFSymbolIterator& operator++() { Fetch(); symbol_.index++; return *this; } + + // Dereferencing this iterator produces a reference to an Symbol structure + // that holds the current symbol's values. The symbol is owned by this + // SymbolIterator, and will be invalidated at the next call to operator++. + const Symbol& operator*() const { return symbol_; } + const Symbol* operator->() const { return &symbol_; } + +private: + // Read the symbol at cursor_, and set symbol_ appropriately. + void Fetch() { + // Elf32_Sym and Elf64_Sym have different layouts. + unsigned char other; + if (value_size_ == 4) { + // Elf32_Sym + cursor_ + .Read(4, false, &symbol_.name_offset) + .Read(4, false, &symbol_.value) + .Read(4, false, &symbol_.size) + .Read(1, false, &symbol_.info) + .Read(1, false, &other) + .Read(2, false, &symbol_.shndx); + } else { + // Elf64_Sym + cursor_ + .Read(4, false, &symbol_.name_offset) + .Read(1, false, &symbol_.info) + .Read(1, false, &other) + .Read(2, false, &symbol_.shndx) + .Read(8, false, &symbol_.value) + .Read(8, false, &symbol_.size); + } + symbol_.at_end = !cursor_; + } + + // The size of symbols' value field, in bytes. + size_t value_size_; + + // A byte cursor traversing buffer_. + ByteCursor cursor_; + + // Values for the symbol this iterator refers to. + Symbol symbol_; +}; + +const char* SymbolString(ptrdiff_t offset, ByteBuffer& strings) { + if (offset < 0 || (size_t) offset >= strings.Size()) { + // Return the null string. + offset = 0; + } + return reinterpret_cast<const char*>(strings.start + offset); +} + +bool ELFSymbolsToModule(const uint8_t* symtab_section, + size_t symtab_size, + const uint8_t* string_section, + size_t string_size, + const bool big_endian, + size_t value_size, + Module* module) { + ByteBuffer symbols(symtab_section, symtab_size); + // Ensure that the string section is null-terminated. + if (string_section[string_size - 1] != '\0') { + const void* null_terminator = memrchr(string_section, '\0', string_size); + string_size = reinterpret_cast<const uint8_t*>(null_terminator) + - string_section; + } + ByteBuffer strings(string_section, string_size); + + // The iterator walking the symbol table. + ELFSymbolIterator iterator(&symbols, big_endian, value_size); + + while(!iterator->at_end) { + if (ELF32_ST_TYPE(iterator->info) == STT_FUNC && + iterator->shndx != SHN_UNDEF) { + Module::Extern* ext = new Module::Extern(iterator->value); + ext->name = SymbolString(iterator->name_offset, strings); +#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle. + int status = 0; + char* demangled = + abi::__cxa_demangle(ext->name.c_str(), NULL, NULL, &status); + if (demangled) { + if (status == 0) + ext->name = demangled; + free(demangled); + } +#endif + module->AddExtern(ext); + } + ++iterator; + } + return true; +} + +} // namespace google_breakpad diff --git a/contrib/libs/breakpad/src/common/linux/elf_symbols_to_module.h b/contrib/libs/breakpad/src/common/linux/elf_symbols_to_module.h new file mode 100644 index 0000000000..861f725297 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/elf_symbols_to_module.h @@ -0,0 +1,58 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2011 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. + +// Original author: Ted Mielczarek <ted.mielczarek@gmail.com> + +// elf_symbols_to_module.h: Exposes ELFSymbolsToModule, a function +// for reading ELF symbol tables and inserting exported symbol names +// into a google_breakpad::Module as Extern definitions. + +#ifndef BREAKPAD_COMMON_LINUX_ELF_SYMBOLS_TO_MODULE_H_ +#define BREAKPAD_COMMON_LINUX_ELF_SYMBOLS_TO_MODULE_H_ + +#include <stddef.h> +#include <stdint.h> + +namespace google_breakpad { + +class Module; + +bool ELFSymbolsToModule(const uint8_t* symtab_section, + size_t symtab_size, + const uint8_t* string_section, + size_t string_size, + const bool big_endian, + size_t value_size, + Module* module); + +} // namespace google_breakpad + + +#endif // BREAKPAD_COMMON_LINUX_ELF_SYMBOLS_TO_MODULE_H_ diff --git a/contrib/libs/breakpad/src/common/linux/elfutils-inl.h b/contrib/libs/breakpad/src/common/linux/elfutils-inl.h new file mode 100644 index 0000000000..e56b37a9f5 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/elfutils-inl.h @@ -0,0 +1,74 @@ +// Copyright (c) 2012, 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. + +#ifndef COMMON_LINUX_ELFUTILS_INL_H__ +#define COMMON_LINUX_ELFUTILS_INL_H__ + +#include "common/linux/linux_libc_support.h" +#include "elfutils.h" + +namespace google_breakpad { + +template<typename ElfClass, typename T> +const T* GetOffset(const typename ElfClass::Ehdr* elf_header, + typename ElfClass::Off offset) { + return reinterpret_cast<const T*>(reinterpret_cast<uintptr_t>(elf_header) + + offset); +} + +template<typename ElfClass> +const typename ElfClass::Shdr* FindElfSectionByName( + const char* name, + typename ElfClass::Word section_type, + const typename ElfClass::Shdr* sections, + const char* section_names, + const char* names_end, + int nsection) { + assert(name != NULL); + assert(sections != NULL); + assert(nsection > 0); + + int name_len = my_strlen(name); + if (name_len == 0) + return NULL; + + for (int i = 0; i < nsection; ++i) { + const char* section_name = section_names + sections[i].sh_name; + if (sections[i].sh_type == section_type && + names_end - section_name >= name_len + 1 && + my_strcmp(name, section_name) == 0) { + return sections + i; + } + } + return NULL; +} + +} // namespace google_breakpad + +#endif // COMMON_LINUX_ELFUTILS_INL_H__ diff --git a/contrib/libs/breakpad/src/common/linux/elfutils.cc b/contrib/libs/breakpad/src/common/linux/elfutils.cc new file mode 100644 index 0000000000..aa95357a3a --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/elfutils.cc @@ -0,0 +1,243 @@ +// Copyright (c) 2012, 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. + +#include "common/linux/elfutils.h" + +#include <assert.h> +#include <string.h> + +#include "common/linux/linux_libc_support.h" +#include "common/linux/elfutils-inl.h" + +namespace google_breakpad { + +namespace { + +template<typename ElfClass> +void FindElfClassSection(const char* elf_base, + const char* section_name, + typename ElfClass::Word section_type, + const void** section_start, + size_t* section_size) { + typedef typename ElfClass::Ehdr Ehdr; + typedef typename ElfClass::Shdr Shdr; + + assert(elf_base); + assert(section_start); + assert(section_size); + + assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0); + + const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base); + assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass); + + if (elf_header->e_shoff == 0) { + *section_start = NULL; + *section_size = 0; + return; + } + + const Shdr* sections = + GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff); + const Shdr* section_names = sections + elf_header->e_shstrndx; + const char* names = + GetOffset<ElfClass, char>(elf_header, section_names->sh_offset); + const char* names_end = names + section_names->sh_size; + + const Shdr* section = + FindElfSectionByName<ElfClass>(section_name, section_type, + sections, names, names_end, + elf_header->e_shnum); + + if (section != NULL && section->sh_size > 0) { + *section_start = elf_base + section->sh_offset; + *section_size = section->sh_size; + } +} + +template<typename ElfClass> +void FindElfClassSegment(const char* elf_base, + typename ElfClass::Word segment_type, + wasteful_vector<ElfSegment>* segments) { + typedef typename ElfClass::Ehdr Ehdr; + typedef typename ElfClass::Phdr Phdr; + + assert(elf_base); + assert(segments); + + assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0); + + const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base); + assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass); + + const Phdr* phdrs = + GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff); + + for (int i = 0; i < elf_header->e_phnum; ++i) { + if (phdrs[i].p_type == segment_type) { + ElfSegment seg = {}; + seg.start = elf_base + phdrs[i].p_offset; + seg.size = phdrs[i].p_filesz; + segments->push_back(seg); + } + } +} + +} // namespace + +bool IsValidElf(const void* elf_base) { + return my_strncmp(reinterpret_cast<const char*>(elf_base), + ELFMAG, SELFMAG) == 0; +} + +int ElfClass(const void* elf_base) { + const ElfW(Ehdr)* elf_header = + reinterpret_cast<const ElfW(Ehdr)*>(elf_base); + + return elf_header->e_ident[EI_CLASS]; +} + +bool FindElfSection(const void* elf_mapped_base, + const char* section_name, + uint32_t section_type, + const void** section_start, + size_t* section_size) { + assert(elf_mapped_base); + assert(section_start); + assert(section_size); + + *section_start = NULL; + *section_size = 0; + + if (!IsValidElf(elf_mapped_base)) + return false; + + int cls = ElfClass(elf_mapped_base); + const char* elf_base = + static_cast<const char*>(elf_mapped_base); + + if (cls == ELFCLASS32) { + FindElfClassSection<ElfClass32>(elf_base, section_name, section_type, + section_start, section_size); + return *section_start != NULL; + } else if (cls == ELFCLASS64) { + FindElfClassSection<ElfClass64>(elf_base, section_name, section_type, + section_start, section_size); + return *section_start != NULL; + } + + return false; +} + +bool FindElfSegments(const void* elf_mapped_base, + uint32_t segment_type, + wasteful_vector<ElfSegment>* segments) { + assert(elf_mapped_base); + assert(segments); + + if (!IsValidElf(elf_mapped_base)) + return false; + + int cls = ElfClass(elf_mapped_base); + const char* elf_base = + static_cast<const char*>(elf_mapped_base); + + if (cls == ELFCLASS32) { + FindElfClassSegment<ElfClass32>(elf_base, segment_type, segments); + return true; + } else if (cls == ELFCLASS64) { + FindElfClassSegment<ElfClass64>(elf_base, segment_type, segments); + return true; + } + + return false; +} + +template <typename ElfClass> +bool FindElfSoNameFromDynamicSection(const void* section_start, + size_t section_size, + const void* dynstr_start, + size_t dynstr_size, + char* soname, + size_t soname_size) { + typedef typename ElfClass::Dyn Dyn; + + auto* dynamic = static_cast<const Dyn*>(section_start); + size_t dcount = section_size / sizeof(Dyn); + for (const Dyn* dyn = dynamic; dyn < dynamic + dcount; ++dyn) { + if (dyn->d_tag == DT_SONAME) { + const char* dynstr = static_cast<const char*>(dynstr_start); + if (dyn->d_un.d_val >= dynstr_size) { + // Beyond the end of the dynstr section + return false; + } + const char* str = dynstr + dyn->d_un.d_val; + const size_t maxsize = dynstr_size - dyn->d_un.d_val; + my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size); + return true; + } + } + + return false; +} + +bool ElfFileSoNameFromMappedFile(const void* elf_base, + char* soname, + size_t soname_size) { + if (!IsValidElf(elf_base)) { + // Not ELF + return false; + } + + const void* segment_start; + size_t segment_size; + if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC, &segment_start, + &segment_size)) { + // No dynamic section + return false; + } + + const void* dynstr_start; + size_t dynstr_size; + if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB, &dynstr_start, + &dynstr_size)) { + // No dynstr section + return false; + } + + int cls = ElfClass(elf_base); + return cls == ELFCLASS32 ? FindElfSoNameFromDynamicSection<ElfClass32>( + segment_start, segment_size, dynstr_start, + dynstr_size, soname, soname_size) + : FindElfSoNameFromDynamicSection<ElfClass64>( + segment_start, segment_size, dynstr_start, + dynstr_size, soname, soname_size); +} + +} // namespace google_breakpad diff --git a/contrib/libs/breakpad/src/common/linux/elfutils.h b/contrib/libs/breakpad/src/common/linux/elfutils.h new file mode 100644 index 0000000000..ec5872a4f3 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/elfutils.h @@ -0,0 +1,135 @@ +// Copyright (c) 2012, 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. +// +// elfutils.h: Utilities for dealing with ELF files. +// + +#ifndef COMMON_LINUX_ELFUTILS_H_ +#define COMMON_LINUX_ELFUTILS_H_ + +#include <elf.h> +#include <link.h> +#include <stdint.h> + +#include "common/memory_allocator.h" + +namespace google_breakpad { + +// Traits classes so consumers can write templatized code to deal +// with specific ELF bits. +struct ElfClass32 { + typedef Elf32_Addr Addr; + typedef Elf32_Dyn Dyn; + typedef Elf32_Ehdr Ehdr; + typedef Elf32_Nhdr Nhdr; + typedef Elf32_Phdr Phdr; + typedef Elf32_Shdr Shdr; + typedef Elf32_Half Half; + typedef Elf32_Off Off; + typedef Elf32_Sym Sym; + typedef Elf32_Word Word; + + static const int kClass = ELFCLASS32; + static const uint16_t kMachine = EM_386; + static const size_t kAddrSize = sizeof(Elf32_Addr); + static constexpr const char* kMachineName = "x86"; +}; + +struct ElfClass64 { + typedef Elf64_Addr Addr; + typedef Elf64_Dyn Dyn; + typedef Elf64_Ehdr Ehdr; + typedef Elf64_Nhdr Nhdr; + typedef Elf64_Phdr Phdr; + typedef Elf64_Shdr Shdr; + typedef Elf64_Half Half; + typedef Elf64_Off Off; + typedef Elf64_Sym Sym; + typedef Elf64_Word Word; + + static const int kClass = ELFCLASS64; + static const uint16_t kMachine = EM_X86_64; + static const size_t kAddrSize = sizeof(Elf64_Addr); + static constexpr const char* kMachineName = "x86_64"; +}; + +bool IsValidElf(const void* elf_header); +int ElfClass(const void* elf_base); + +// Attempt to find a section named |section_name| of type |section_type| +// in the ELF binary data at |elf_mapped_base|. On success, returns true +// and sets |*section_start| to point to the start of the section data, +// and |*section_size| to the size of the section's data. +bool FindElfSection(const void* elf_mapped_base, + const char* section_name, + uint32_t section_type, + const void** section_start, + size_t* section_size); + +// Internal helper method, exposed for convenience for callers +// that already have more info. +template<typename ElfClass> +const typename ElfClass::Shdr* +FindElfSectionByName(const char* name, + typename ElfClass::Word section_type, + const typename ElfClass::Shdr* sections, + const char* section_names, + const char* names_end, + int nsection); + +struct ElfSegment { + const void* start; + size_t size; +}; + +// Attempt to find all segments of type |segment_type| in the ELF +// binary data at |elf_mapped_base|. On success, returns true and fills +// |*segments| with a list of segments of the given type. +bool FindElfSegments(const void* elf_mapped_base, + uint32_t segment_type, + wasteful_vector<ElfSegment>* segments); + +// Convert an offset from an Elf header into a pointer to the mapped +// address in the current process. Takes an extra template parameter +// to specify the return type to avoid having to dynamic_cast the +// result. +template<typename ElfClass, typename T> +const T* +GetOffset(const typename ElfClass::Ehdr* elf_header, + typename ElfClass::Off offset); + +// Read the value of DT_SONAME from the elf file mapped at |elf_base|. Returns +// true and fills |soname| with the result if found. +bool ElfFileSoNameFromMappedFile(const void* elf_base, + char* soname, + size_t soname_size); + +} // namespace google_breakpad + +#endif // COMMON_LINUX_ELFUTILS_H_ diff --git a/contrib/libs/breakpad/src/common/linux/file_id.cc b/contrib/libs/breakpad/src/common/linux/file_id.cc new file mode 100644 index 0000000000..b483eb5c02 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/file_id.cc @@ -0,0 +1,203 @@ +// Copyright (c) 2006, 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. +// +// file_id.cc: Return a unique identifier for a file +// +// See file_id.h for documentation +// + +#include "common/linux/file_id.h" + +#include <arpa/inet.h> +#include <assert.h> +#include <string.h> + +#include <algorithm> +#include <string> + +#include "common/linux/elf_gnu_compat.h" +#include "common/linux/elfutils.h" +#include "common/linux/linux_libc_support.h" +#include "common/linux/memory_mapped_file.h" +#include "common/using_std_string.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { +namespace elf { + +// Used in a few places for backwards-compatibility. +const size_t kMDGUIDSize = sizeof(MDGUID); + +FileID::FileID(const char* path) : path_(path) {} + +// ELF note name and desc are 32-bits word padded. +#define NOTE_PADDING(a) ((a + 3) & ~3) + +// These functions are also used inside the crashed process, so be safe +// and use the syscall/libc wrappers instead of direct syscalls or libc. + +static bool ElfClassBuildIDNoteIdentifier(const void* section, size_t length, + wasteful_vector<uint8_t>& identifier) { + static_assert(sizeof(ElfClass32::Nhdr) == sizeof(ElfClass64::Nhdr), + "Elf32_Nhdr and Elf64_Nhdr should be the same"); + typedef typename ElfClass32::Nhdr Nhdr; + + const void* section_end = reinterpret_cast<const char*>(section) + length; + const Nhdr* note_header = reinterpret_cast<const Nhdr*>(section); + while (reinterpret_cast<const void*>(note_header) < section_end) { + if (note_header->n_type == NT_GNU_BUILD_ID) + break; + note_header = reinterpret_cast<const Nhdr*>( + reinterpret_cast<const char*>(note_header) + sizeof(Nhdr) + + NOTE_PADDING(note_header->n_namesz) + + NOTE_PADDING(note_header->n_descsz)); + } + if (reinterpret_cast<const void*>(note_header) >= section_end || + note_header->n_descsz == 0) { + return false; + } + + const uint8_t* build_id = reinterpret_cast<const uint8_t*>(note_header) + + sizeof(Nhdr) + NOTE_PADDING(note_header->n_namesz); + identifier.insert(identifier.end(), + build_id, + build_id + note_header->n_descsz); + + return true; +} + +// Attempt to locate a .note.gnu.build-id section in an ELF binary +// and copy it into |identifier|. +static bool FindElfBuildIDNote(const void* elf_mapped_base, + wasteful_vector<uint8_t>& identifier) { + PageAllocator allocator; + // lld normally creates 2 PT_NOTEs, gold normally creates 1. + auto_wasteful_vector<ElfSegment, 2> segs(&allocator); + if (FindElfSegments(elf_mapped_base, PT_NOTE, &segs)) { + for (ElfSegment& seg : segs) { + if (ElfClassBuildIDNoteIdentifier(seg.start, seg.size, identifier)) { + return true; + } + } + } + + void* note_section; + size_t note_size; + if (FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE, + (const void**)¬e_section, ¬e_size)) { + return ElfClassBuildIDNoteIdentifier(note_section, note_size, identifier); + } + + return false; +} + +// Attempt to locate the .text section of an ELF binary and generate +// a simple hash by XORing the first page worth of bytes into |identifier|. +static bool HashElfTextSection(const void* elf_mapped_base, + wasteful_vector<uint8_t>& identifier) { + identifier.resize(kMDGUIDSize); + + void* text_section; + size_t text_size; + if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS, + (const void**)&text_section, &text_size) || + text_size == 0) { + return false; + } + + // Only provide |kMDGUIDSize| bytes to keep identifiers produced by this + // function backwards-compatible. + my_memset(&identifier[0], 0, kMDGUIDSize); + const uint8_t* ptr = reinterpret_cast<const uint8_t*>(text_section); + const uint8_t* ptr_end = ptr + std::min(text_size, static_cast<size_t>(4096)); + while (ptr < ptr_end) { + for (unsigned i = 0; i < kMDGUIDSize; i++) + identifier[i] ^= ptr[i]; + ptr += kMDGUIDSize; + } + return true; +} + +// static +bool FileID::ElfFileIdentifierFromMappedFile(const void* base, + wasteful_vector<uint8_t>& identifier) { + // Look for a build id note first. + if (FindElfBuildIDNote(base, identifier)) + return true; + + // Fall back on hashing the first page of the text section. + return HashElfTextSection(base, identifier); +} + +bool FileID::ElfFileIdentifier(wasteful_vector<uint8_t>& identifier) { + MemoryMappedFile mapped_file(path_.c_str(), 0); + if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)? + return false; + + return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier); +} + +// These three functions are not ever called in an unsafe context, so it's OK +// to allocate memory and use libc. +static string bytes_to_hex_string(const uint8_t* bytes, size_t count) { + string result; + for (unsigned int idx = 0; idx < count; ++idx) { + char buf[3]; + snprintf(buf, sizeof(buf), "%02X", bytes[idx]); + result.append(buf); + } + return result; +} + +// static +string FileID::ConvertIdentifierToUUIDString( + const wasteful_vector<uint8_t>& identifier) { + uint8_t identifier_swapped[kMDGUIDSize] = { 0 }; + + // Endian-ness swap to match dump processor expectation. + memcpy(identifier_swapped, &identifier[0], + std::min(kMDGUIDSize, identifier.size())); + uint32_t* data1 = reinterpret_cast<uint32_t*>(identifier_swapped); + *data1 = htonl(*data1); + uint16_t* data2 = reinterpret_cast<uint16_t*>(identifier_swapped + 4); + *data2 = htons(*data2); + uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6); + *data3 = htons(*data3); + + return bytes_to_hex_string(identifier_swapped, kMDGUIDSize); +} + +// static +string FileID::ConvertIdentifierToString( + const wasteful_vector<uint8_t>& identifier) { + return bytes_to_hex_string(&identifier[0], identifier.size()); +} + +} // elf +} // namespace google_breakpad diff --git a/contrib/libs/breakpad/src/common/linux/file_id.h b/contrib/libs/breakpad/src/common/linux/file_id.h new file mode 100644 index 0000000000..8556a2e5ae --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/file_id.h @@ -0,0 +1,90 @@ +// Copyright (c) 2006, 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. +// +// file_id.h: Return a unique identifier for a file +// + +#ifndef COMMON_LINUX_FILE_ID_H__ +#define COMMON_LINUX_FILE_ID_H__ + +#include <limits.h> +#include <string> + +#include "common/linux/guid_creator.h" +#include "common/memory_allocator.h" +#include "common/using_std_string.h" + +namespace google_breakpad { +namespace elf { + +// GNU binutils' ld defaults to 'sha1', which is 160 bits == 20 bytes, +// so this is enough to fit that, which most binaries will use. +// This is just a sensible default for auto_wasteful_vector so most +// callers can get away with stack allocation. +static const size_t kDefaultBuildIdSize = 20; + +class FileID { + public: + explicit FileID(const char* path); + ~FileID() {} + + // Load the identifier for the elf file path specified in the constructor into + // |identifier|. + // + // The current implementation will look for a .note.gnu.build-id + // section and use that as the file id, otherwise it falls back to + // XORing the first 4096 bytes of the .text section to generate an identifier. + bool ElfFileIdentifier(wasteful_vector<uint8_t>& identifier); + + // Load the identifier for the elf file mapped into memory at |base| into + // |identifier|. Return false if the identifier could not be created for this + // file. + static bool ElfFileIdentifierFromMappedFile( + const void* base, + wasteful_vector<uint8_t>& identifier); + + // Convert the |identifier| data to a string. The string will + // be formatted as a UUID in all uppercase without dashes. + // (e.g., 22F065BBFC9C49F780FE26A7CEBD7BCE). + static string ConvertIdentifierToUUIDString( + const wasteful_vector<uint8_t>& identifier); + + // Convert the entire |identifier| data to a hex string. + static string ConvertIdentifierToString( + const wasteful_vector<uint8_t>& identifier); + + private: + // Storage for the path specified + string path_; +}; + +} // namespace elf +} // namespace google_breakpad + +#endif // COMMON_LINUX_FILE_ID_H__ diff --git a/contrib/libs/breakpad/src/common/linux/guid_creator.cc b/contrib/libs/breakpad/src/common/linux/guid_creator.cc new file mode 100644 index 0000000000..6374063825 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/guid_creator.cc @@ -0,0 +1,189 @@ +// Copyright (c) 2006, 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. + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "common/linux/eintr_wrapper.h" +#include "common/linux/guid_creator.h" + +#include <assert.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> + +#if defined(HAVE_SYS_RANDOM_H) +#include <sys/random.h> +#endif + +// +// GUIDGenerator +// +// This class is used to generate random GUID. +// Currently use random number to generate a GUID since Linux has +// no native GUID generator. This should be OK since we don't expect +// crash to happen very offen. +// +class GUIDGenerator { + public: + static uint32_t BytesToUInt32(const uint8_t bytes[]) { + return ((uint32_t) bytes[0] + | ((uint32_t) bytes[1] << 8) + | ((uint32_t) bytes[2] << 16) + | ((uint32_t) bytes[3] << 24)); + } + + static void UInt32ToBytes(uint8_t bytes[], uint32_t n) { + bytes[0] = n & 0xff; + bytes[1] = (n >> 8) & 0xff; + bytes[2] = (n >> 16) & 0xff; + bytes[3] = (n >> 24) & 0xff; + } + + static bool CreateGUID(GUID *guid) { +#if defined(HAVE_ARC4RANDOM) // Android, BSD, ... + CreateGuidFromArc4Random(guid); +#else // Linux + bool success = false; + +#if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM) + success = CreateGUIDFromGetrandom(guid); +#endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM + if (!success) { + success = CreateGUIDFromDevUrandom(guid); + } + + if (!success) { + CreateGUIDFromRand(guid); + success = true; + } +#endif + + // Put in the version according to RFC 4122. + guid->data3 &= 0x0fff; + guid->data3 |= 0x4000; + + // Put in the variant according to RFC 4122. + guid->data4[0] &= 0x3f; + guid->data4[0] |= 0x80; + + return true; + } + + private: +#ifdef HAVE_ARC4RANDOM + static void CreateGuidFromArc4Random(GUID *guid) { + char *buf = reinterpret_cast<char*>(guid); + + for (size_t i = 0; i < sizeof(GUID); i += sizeof(uint32_t)) { + uint32_t random_data = arc4random(); + + memcpy(buf + i, &random_data, sizeof(uint32_t)); + } + } +#else + static void InitOnce() { + pthread_once(&once_control, &InitOnceImpl); + } + + static void InitOnceImpl() { + // time(NULL) is a very poor seed, so lacking anything better mix an + // address into it. We drop the four rightmost bits as they're likely to + // be 0 on almost all architectures. + srand(time(NULL) | ((uintptr_t)&once_control >> 4)); + } + + static pthread_once_t once_control; + +#if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM) + static bool CreateGUIDFromGetrandom(GUID *guid) { + char *buf = reinterpret_cast<char*>(guid); + int read_bytes = getrandom(buf, sizeof(GUID), GRND_NONBLOCK); + + return (read_bytes == static_cast<int>(sizeof(GUID))); + } +#endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM + + // Populate the GUID using random bytes read from /dev/urandom, returns false + // if the GUID wasn't fully populated with random data. + static bool CreateGUIDFromDevUrandom(GUID *guid) { + char *buf = reinterpret_cast<char*>(guid); + int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC); + + if (fd == -1) { + return false; + } + + ssize_t read_bytes = HANDLE_EINTR(read(fd, buf, sizeof(GUID))); + close(fd); + + return (read_bytes == static_cast<ssize_t>(sizeof(GUID))); + } + + // Populate the GUID using a stream of random bytes obtained from rand(). + static void CreateGUIDFromRand(GUID *guid) { + char *buf = reinterpret_cast<char*>(guid); + + InitOnce(); + + for (size_t i = 0; i < sizeof(GUID); i++) { + buf[i] = rand(); + } + } +#endif +}; + +#ifndef HAVE_ARC4RANDOM +pthread_once_t GUIDGenerator::once_control = PTHREAD_ONCE_INIT; +#endif + +bool CreateGUID(GUID *guid) { + return GUIDGenerator::CreateGUID(guid); +} + +// Parse guid to string. +bool GUIDToString(const GUID *guid, char *buf, int buf_len) { + // Should allow more space the the max length of GUID. + assert(buf_len > kGUIDStringLength); + int num = snprintf(buf, buf_len, kGUIDFormatString, + guid->data1, guid->data2, guid->data3, + GUIDGenerator::BytesToUInt32(&(guid->data4[0])), + GUIDGenerator::BytesToUInt32(&(guid->data4[4]))); + if (num != kGUIDStringLength) + return false; + + buf[num] = '\0'; + return true; +} diff --git a/contrib/libs/breakpad/src/common/linux/guid_creator.h b/contrib/libs/breakpad/src/common/linux/guid_creator.h new file mode 100644 index 0000000000..c86d856c4d --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/guid_creator.h @@ -0,0 +1,48 @@ +// Copyright (c) 2006, 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. + +#ifndef COMMON_LINUX_GUID_CREATOR_H__ +#define COMMON_LINUX_GUID_CREATOR_H__ + +#include "google_breakpad/common/minidump_format.h" + +typedef MDGUID GUID; + +// Format string for parsing GUID. +#define kGUIDFormatString "%08x-%04x-%04x-%08x-%08x" +// Length of GUID string. Don't count the ending '\0'. +#define kGUIDStringLength 36 + +// Create a guid. +bool CreateGUID(GUID *guid); + +// Get the string from guid. +bool GUIDToString(const GUID *guid, char *buf, int buf_len); + +#endif diff --git a/contrib/libs/breakpad/src/common/linux/http_upload.cc b/contrib/libs/breakpad/src/common/linux/http_upload.cc new file mode 100644 index 0000000000..ace12b84e1 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/http_upload.cc @@ -0,0 +1,230 @@ +// Copyright (c) 2006, 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. + +#include "common/linux/http_upload.h" + +#include <assert.h> +#include <dlfcn.h> +#include "third_party/curl/curl.h" + +namespace { + +// Callback to get the response data from server. +static size_t WriteCallback(void* ptr, size_t size, + size_t nmemb, void* userp) { + if (!userp) + return 0; + + string* response = reinterpret_cast<string*>(userp); + size_t real_size = size * nmemb; + response->append(reinterpret_cast<char*>(ptr), real_size); + return real_size; +} + +} // namespace + +namespace google_breakpad { + +static const char kUserAgent[] = "Breakpad/1.0 (Linux)"; + +// static +bool HTTPUpload::SendRequest(const string& url, + const map<string, string>& parameters, + const map<string, string>& files, + const string& proxy, + const string& proxy_user_pwd, + const string& ca_certificate_file, + string* response_body, + long* response_code, + string* error_description) { + if (response_code != NULL) + *response_code = 0; + + if (!CheckParameters(parameters)) + return false; + + // We may have been linked statically; if curl_easy_init is in the + // current binary, no need to search for a dynamic version. + void* curl_lib = dlopen(NULL, RTLD_NOW); + if (!CheckCurlLib(curl_lib)) { + fprintf(stderr, + "Failed to open curl lib from binary, use libcurl.so instead\n"); + dlerror(); // Clear dlerror before attempting to open libraries. + dlclose(curl_lib); + curl_lib = NULL; + } + if (!curl_lib) { + curl_lib = dlopen("libcurl.so", RTLD_NOW); + } + if (!curl_lib) { + if (error_description != NULL) + *error_description = dlerror(); + curl_lib = dlopen("libcurl.so.4", RTLD_NOW); + } + if (!curl_lib) { + // Debian gives libcurl a different name when it is built against GnuTLS + // instead of OpenSSL. + curl_lib = dlopen("libcurl-gnutls.so.4", RTLD_NOW); + } + if (!curl_lib) { + curl_lib = dlopen("libcurl.so.3", RTLD_NOW); + } + if (!curl_lib) { + return false; + } + + CURL* (*curl_easy_init)(void); + *(void**) (&curl_easy_init) = dlsym(curl_lib, "curl_easy_init"); + CURL* curl = (*curl_easy_init)(); + if (error_description != NULL) + *error_description = "No Error"; + + if (!curl) { + dlclose(curl_lib); + return false; + } + + CURLcode err_code = CURLE_OK; + CURLcode (*curl_easy_setopt)(CURL*, CURLoption, ...); + *(void**) (&curl_easy_setopt) = dlsym(curl_lib, "curl_easy_setopt"); + (*curl_easy_setopt)(curl, CURLOPT_URL, url.c_str()); + (*curl_easy_setopt)(curl, CURLOPT_USERAGENT, kUserAgent); + // Support multithread by disabling timeout handling, would get SIGSEGV with + // Curl_resolv_timeout in stack trace otherwise. + // See https://curl.haxx.se/libcurl/c/threadsafe.html + (*curl_easy_setopt)(curl, CURLOPT_NOSIGNAL, 1); + // Set proxy information if necessary. + if (!proxy.empty()) + (*curl_easy_setopt)(curl, CURLOPT_PROXY, proxy.c_str()); + if (!proxy_user_pwd.empty()) + (*curl_easy_setopt)(curl, CURLOPT_PROXYUSERPWD, proxy_user_pwd.c_str()); + + if (!ca_certificate_file.empty()) + (*curl_easy_setopt)(curl, CURLOPT_CAINFO, ca_certificate_file.c_str()); + + struct curl_httppost* formpost = NULL; + struct curl_httppost* lastptr = NULL; + // Add form data. + CURLFORMcode (*curl_formadd)(struct curl_httppost**, struct curl_httppost**, ...); + *(void**) (&curl_formadd) = dlsym(curl_lib, "curl_formadd"); + map<string, string>::const_iterator iter = parameters.begin(); + for (; iter != parameters.end(); ++iter) + (*curl_formadd)(&formpost, &lastptr, + CURLFORM_COPYNAME, iter->first.c_str(), + CURLFORM_COPYCONTENTS, iter->second.c_str(), + CURLFORM_END); + + // Add form files. + for (iter = files.begin(); iter != files.end(); ++iter) { + (*curl_formadd)(&formpost, &lastptr, + CURLFORM_COPYNAME, iter->first.c_str(), + CURLFORM_FILE, iter->second.c_str(), + CURLFORM_END); + } + + (*curl_easy_setopt)(curl, CURLOPT_HTTPPOST, formpost); + + // Disable 100-continue header. + struct curl_slist* headerlist = NULL; + char buf[] = "Expect:"; + struct curl_slist* (*curl_slist_append)(struct curl_slist*, const char*); + *(void**) (&curl_slist_append) = dlsym(curl_lib, "curl_slist_append"); + headerlist = (*curl_slist_append)(headerlist, buf); + (*curl_easy_setopt)(curl, CURLOPT_HTTPHEADER, headerlist); + + if (response_body != NULL) { + (*curl_easy_setopt)(curl, CURLOPT_WRITEFUNCTION, WriteCallback); + (*curl_easy_setopt)(curl, CURLOPT_WRITEDATA, + reinterpret_cast<void*>(response_body)); + } + + // Fail if 400+ is returned from the web server. + (*curl_easy_setopt)(curl, CURLOPT_FAILONERROR, 1); + + CURLcode (*curl_easy_perform)(CURL*); + *(void**) (&curl_easy_perform) = dlsym(curl_lib, "curl_easy_perform"); + err_code = (*curl_easy_perform)(curl); + if (response_code != NULL) { + CURLcode (*curl_easy_getinfo)(CURL*, CURLINFO, ...); + *(void**) (&curl_easy_getinfo) = dlsym(curl_lib, "curl_easy_getinfo"); + (*curl_easy_getinfo)(curl, CURLINFO_RESPONSE_CODE, response_code); + } + const char* (*curl_easy_strerror)(CURLcode); + *(void**) (&curl_easy_strerror) = dlsym(curl_lib, "curl_easy_strerror"); +#ifndef NDEBUG + if (err_code != CURLE_OK) + fprintf(stderr, "Failed to send http request to %s, error: %s\n", + url.c_str(), + (*curl_easy_strerror)(err_code)); +#endif + if (error_description != NULL) + *error_description = (*curl_easy_strerror)(err_code); + + void (*curl_easy_cleanup)(CURL*); + *(void**) (&curl_easy_cleanup) = dlsym(curl_lib, "curl_easy_cleanup"); + (*curl_easy_cleanup)(curl); + if (formpost != NULL) { + void (*curl_formfree)(struct curl_httppost*); + *(void**) (&curl_formfree) = dlsym(curl_lib, "curl_formfree"); + (*curl_formfree)(formpost); + } + if (headerlist != NULL) { + void (*curl_slist_free_all)(struct curl_slist*); + *(void**) (&curl_slist_free_all) = dlsym(curl_lib, "curl_slist_free_all"); + (*curl_slist_free_all)(headerlist); + } + dlclose(curl_lib); + return err_code == CURLE_OK; +} + +// static +bool HTTPUpload::CheckCurlLib(void* curl_lib) { + return curl_lib && + dlsym(curl_lib, "curl_easy_init") && + dlsym(curl_lib, "curl_easy_setopt"); +} + +// static +bool HTTPUpload::CheckParameters(const map<string, string>& parameters) { + for (map<string, string>::const_iterator pos = parameters.begin(); + pos != parameters.end(); ++pos) { + const string& str = pos->first; + if (str.size() == 0) + return false; // disallow empty parameter names + for (unsigned int i = 0; i < str.size(); ++i) { + int c = str[i]; + if (c < 32 || c == '"' || c > 127) { + return false; + } + } + } + return true; +} + +} // namespace google_breakpad diff --git a/contrib/libs/breakpad/src/common/linux/http_upload.h b/contrib/libs/breakpad/src/common/linux/http_upload.h new file mode 100644 index 0000000000..13f3d56cc8 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/http_upload.h @@ -0,0 +1,90 @@ +// Copyright (c) 2006, 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. + +// HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST +// request using libcurl. It currently supports requests that contain +// a set of string parameters (key/value pairs), and a file to upload. + +#ifndef COMMON_LINUX_HTTP_UPLOAD_H__ +#define COMMON_LINUX_HTTP_UPLOAD_H__ + +#include <map> +#include <string> + +#include "common/using_std_string.h" + +namespace google_breakpad { + +using std::map; + +class HTTPUpload { + public: + // Sends the given sets of parameters and files as a multipart POST + // request to the given URL. + // Each key in |files| is the name of the file part of the request + // (i.e. it corresponds to the name= attribute on an <input type="file">. + // Parameter names must contain only printable ASCII characters, + // and may not contain a quote (") character. + // Only HTTP(S) URLs are currently supported. Returns true on success. + // If the request is successful and response_body is non-NULL, + // the response body will be returned in response_body. + // If response_code is non-NULL, it will be set to the HTTP response code + // received (or 0 if the request failed before getting an HTTP response). + // If the send fails, a description of the error will be + // returned in error_description. + static bool SendRequest(const string& url, + const map<string, string>& parameters, + const map<string, string>& files, + const string& proxy, + const string& proxy_user_pwd, + const string& ca_certificate_file, + string* response_body, + long* response_code, + string* error_description); + + private: + // Checks that the given list of parameters has only printable + // ASCII characters in the parameter name, and does not contain + // any quote (") characters. Returns true if so. + static bool CheckParameters(const map<string, string>& parameters); + + // Checks the curl_lib parameter points to a valid curl lib. + static bool CheckCurlLib(void* curl_lib); + + // No instances of this class should be created. + // Disallow all constructors, destructors, and operator=. + HTTPUpload(); + explicit HTTPUpload(const HTTPUpload&); + void operator=(const HTTPUpload&); + ~HTTPUpload(); +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_HTTP_UPLOAD_H__ diff --git a/contrib/libs/breakpad/src/common/linux/ignore_ret.h b/contrib/libs/breakpad/src/common/linux/ignore_ret.h new file mode 100644 index 0000000000..efd274c20c --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/ignore_ret.h @@ -0,0 +1,40 @@ +// Copyright (c) 2012 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. + +#ifndef COMMON_LINUX_IGNORE_RET_H_ +#define COMMON_LINUX_IGNORE_RET_H_ + +// Some compilers are prone to warn about unused return values. In cases where +// either a) the call cannot fail, or b) there is nothing that can be done when +// the call fails, IGNORE_RET() can be used to mark the return code as ignored. +// This avoids spurious compiler warnings. + +#define IGNORE_RET(x) do { if (x) {} } while (0) + +#endif // COMMON_LINUX_IGNORE_RET_H_ diff --git a/contrib/libs/breakpad/src/common/linux/libcurl_wrapper.cc b/contrib/libs/breakpad/src/common/linux/libcurl_wrapper.cc new file mode 100644 index 0000000000..fdb200f8e3 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/libcurl_wrapper.cc @@ -0,0 +1,338 @@ +// Copyright (c) 2009, 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. + +#include <dlfcn.h> + +#include <iostream> +#include <string> + +#include "common/linux/libcurl_wrapper.h" +#include "common/using_std_string.h" + +namespace google_breakpad { +LibcurlWrapper::LibcurlWrapper() + : init_ok_(false), + curl_lib_(nullptr), + last_curl_error_(""), + curl_(nullptr), + formpost_(nullptr), + lastptr_(nullptr), + headerlist_(nullptr) {} + +LibcurlWrapper::~LibcurlWrapper() { + if (init_ok_) { + (*easy_cleanup_)(curl_); + dlclose(curl_lib_); + } +} + +bool LibcurlWrapper::SetProxy(const string& proxy_host, + const string& proxy_userpwd) { + if (!CheckInit()) return false; + + // Set proxy information if necessary. + if (!proxy_host.empty()) { + (*easy_setopt_)(curl_, CURLOPT_PROXY, proxy_host.c_str()); + } else { + std::cout << "SetProxy called with empty proxy host."; + return false; + } + if (!proxy_userpwd.empty()) { + (*easy_setopt_)(curl_, CURLOPT_PROXYUSERPWD, proxy_userpwd.c_str()); + } else { + std::cout << "SetProxy called with empty proxy username/password."; + return false; + } + std::cout << "Set proxy host to " << proxy_host; + return true; +} + +bool LibcurlWrapper::AddFile(const string& upload_file_path, + const string& basename) { + if (!CheckInit()) return false; + + std::cout << "Adding " << upload_file_path << " to form upload."; + // Add form file. + (*formadd_)(&formpost_, &lastptr_, + CURLFORM_COPYNAME, basename.c_str(), + CURLFORM_FILE, upload_file_path.c_str(), + CURLFORM_END); + + return true; +} + +// Callback to get the response data from server. +static size_t WriteCallback(void* ptr, size_t size, + size_t nmemb, void* userp) { + if (!userp) + return 0; + + string* response = reinterpret_cast<string*>(userp); + size_t real_size = size * nmemb; + response->append(reinterpret_cast<char*>(ptr), real_size); + return real_size; +} + +bool LibcurlWrapper::SendRequest(const string& url, + const std::map<string, string>& parameters, + long* http_status_code, + string* http_header_data, + string* http_response_data) { + if (!CheckInit()) return false; + + std::map<string, string>::const_iterator iter = parameters.begin(); + for (; iter != parameters.end(); ++iter) + (*formadd_)(&formpost_, &lastptr_, + CURLFORM_COPYNAME, iter->first.c_str(), + CURLFORM_COPYCONTENTS, iter->second.c_str(), + CURLFORM_END); + + (*easy_setopt_)(curl_, CURLOPT_HTTPPOST, formpost_); + + return SendRequestInner(url, http_status_code, http_header_data, + http_response_data); +} + +bool LibcurlWrapper::SendGetRequest(const string& url, + long* http_status_code, + string* http_header_data, + string* http_response_data) { + if (!CheckInit()) return false; + + (*easy_setopt_)(curl_, CURLOPT_HTTPGET, 1L); + + return SendRequestInner(url, http_status_code, http_header_data, + http_response_data); +} + +bool LibcurlWrapper::SendPutRequest(const string& url, + const string& path, + long* http_status_code, + string* http_header_data, + string* http_response_data) { + if (!CheckInit()) return false; + + FILE* file = fopen(path.c_str(), "rb"); + (*easy_setopt_)(curl_, CURLOPT_UPLOAD, 1L); + (*easy_setopt_)(curl_, CURLOPT_PUT, 1L); + (*easy_setopt_)(curl_, CURLOPT_READDATA, file); + + bool success = SendRequestInner(url, http_status_code, http_header_data, + http_response_data); + + fclose(file); + return success; +} + +bool LibcurlWrapper::SendSimplePostRequest(const string& url, + const string& body, + const string& content_type, + long* http_status_code, + string* http_header_data, + string* http_response_data) { + if (!CheckInit()) return false; + + (*easy_setopt_)(curl_, CURLOPT_POSTFIELDSIZE, body.size()); + (*easy_setopt_)(curl_, CURLOPT_COPYPOSTFIELDS, body.c_str()); + + if (!content_type.empty()) { + string content_type_header = "Content-Type: " + content_type; + headerlist_ = (*slist_append_)( + headerlist_, + content_type_header.c_str()); + } + + return SendRequestInner(url, http_status_code, http_header_data, + http_response_data); +} + +bool LibcurlWrapper::Init() { + // First check to see if libcurl was statically linked: + curl_lib_ = dlopen(nullptr, RTLD_NOW); + if (curl_lib_ && + (!dlsym(curl_lib_, "curl_easy_init") || + !dlsym(curl_lib_, "curl_easy_setopt"))) { + // Not statically linked, try again below. + dlerror(); // Clear dlerror before attempting to open libraries. + dlclose(curl_lib_); + curl_lib_ = nullptr; + } + if (!curl_lib_) { + curl_lib_ = dlopen("libcurl.so", RTLD_NOW); + } + if (!curl_lib_) { + curl_lib_ = dlopen("libcurl.so.4", RTLD_NOW); + } + if (!curl_lib_) { + curl_lib_ = dlopen("libcurl.so.3", RTLD_NOW); + } + if (!curl_lib_) { + std::cout << "Could not find libcurl via dlopen"; + return false; + } + + if (!SetFunctionPointers()) { + std::cout << "Could not find function pointers"; + return false; + } + + curl_ = (*easy_init_)(); + + last_curl_error_ = "No Error"; + + if (!curl_) { + dlclose(curl_lib_); + std::cout << "Curl initialization failed"; + return false; + } + + init_ok_ = true; + return true; +} + +#define SET_AND_CHECK_FUNCTION_POINTER(var, function_name, type) \ + var = reinterpret_cast<type>(dlsym(curl_lib_, function_name)); \ + if (!var) { \ + std::cout << "Could not find libcurl function " << function_name; \ + init_ok_ = false; \ + return false; \ + } + +bool LibcurlWrapper::SetFunctionPointers() { + + SET_AND_CHECK_FUNCTION_POINTER(easy_init_, + "curl_easy_init", + CURL*(*)()); + + SET_AND_CHECK_FUNCTION_POINTER(easy_setopt_, + "curl_easy_setopt", + CURLcode(*)(CURL*, CURLoption, ...)); + + SET_AND_CHECK_FUNCTION_POINTER(formadd_, "curl_formadd", + CURLFORMcode(*)(curl_httppost**, curl_httppost**, ...)); + + SET_AND_CHECK_FUNCTION_POINTER(slist_append_, "curl_slist_append", + curl_slist*(*)(curl_slist*, const char*)); + + SET_AND_CHECK_FUNCTION_POINTER(easy_perform_, + "curl_easy_perform", + CURLcode(*)(CURL*)); + + SET_AND_CHECK_FUNCTION_POINTER(easy_cleanup_, + "curl_easy_cleanup", + void(*)(CURL*)); + + SET_AND_CHECK_FUNCTION_POINTER(easy_getinfo_, + "curl_easy_getinfo", + CURLcode(*)(CURL*, CURLINFO info, ...)); + + SET_AND_CHECK_FUNCTION_POINTER(easy_reset_, + "curl_easy_reset", + void(*)(CURL*)); + + SET_AND_CHECK_FUNCTION_POINTER(slist_free_all_, + "curl_slist_free_all", + void(*)(curl_slist*)); + + SET_AND_CHECK_FUNCTION_POINTER(formfree_, + "curl_formfree", + void(*)(curl_httppost*)); + return true; +} + +bool LibcurlWrapper::SendRequestInner(const string& url, + long* http_status_code, + string* http_header_data, + string* http_response_data) { + string url_copy(url); + (*easy_setopt_)(curl_, CURLOPT_URL, url_copy.c_str()); + + // Disable 100-continue header. + char buf[] = "Expect:"; + headerlist_ = (*slist_append_)(headerlist_, buf); + (*easy_setopt_)(curl_, CURLOPT_HTTPHEADER, headerlist_); + + if (http_response_data != nullptr) { + http_response_data->clear(); + (*easy_setopt_)(curl_, CURLOPT_WRITEFUNCTION, WriteCallback); + (*easy_setopt_)(curl_, CURLOPT_WRITEDATA, + reinterpret_cast<void*>(http_response_data)); + } + if (http_header_data != nullptr) { + http_header_data->clear(); + (*easy_setopt_)(curl_, CURLOPT_HEADERFUNCTION, WriteCallback); + (*easy_setopt_)(curl_, CURLOPT_HEADERDATA, + reinterpret_cast<void*>(http_header_data)); + } + CURLcode err_code = CURLE_OK; + err_code = (*easy_perform_)(curl_); + easy_strerror_ = reinterpret_cast<const char* (*)(CURLcode)> + (dlsym(curl_lib_, "curl_easy_strerror")); + + if (http_status_code != nullptr) { + (*easy_getinfo_)(curl_, CURLINFO_RESPONSE_CODE, http_status_code); + } + +#ifndef NDEBUG + if (err_code != CURLE_OK) + fprintf(stderr, "Failed to send http request to %s, error: %s\n", + url.c_str(), + (*easy_strerror_)(err_code)); +#endif + + Reset(); + + return err_code == CURLE_OK; +} + +void LibcurlWrapper::Reset() { + if (headerlist_ != nullptr) { + (*slist_free_all_)(headerlist_); + headerlist_ = nullptr; + } + + if (formpost_ != nullptr) { + (*formfree_)(formpost_); + formpost_ = nullptr; + } + + (*easy_reset_)(curl_); +} + +bool LibcurlWrapper::CheckInit() { + if (!init_ok_) { + std::cout << "LibcurlWrapper: You must call Init(), and have it return " + "'true' before invoking any other methods.\n"; + return false; + } + + return true; +} + +} // namespace google_breakpad diff --git a/contrib/libs/breakpad/src/common/linux/libcurl_wrapper.h b/contrib/libs/breakpad/src/common/linux/libcurl_wrapper.h new file mode 100644 index 0000000000..823f83c7ee --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/libcurl_wrapper.h @@ -0,0 +1,119 @@ +// Copyright (c) 2009, 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. + +// A wrapper for libcurl to do HTTP Uploads, to support easy mocking +// and unit testing of the HTTPUpload class. + +#ifndef COMMON_LINUX_LIBCURL_WRAPPER_H_ +#define COMMON_LINUX_LIBCURL_WRAPPER_H_ + +#include <string> +#include <map> + +#include "common/using_std_string.h" +#include "third_party/curl/curl.h" + +namespace google_breakpad { +class LibcurlWrapper { + public: + LibcurlWrapper(); + virtual ~LibcurlWrapper(); + virtual bool Init(); + virtual bool SetProxy(const string& proxy_host, + const string& proxy_userpwd); + virtual bool AddFile(const string& upload_file_path, + const string& basename); + virtual bool SendRequest(const string& url, + const std::map<string, string>& parameters, + long* http_status_code, + string* http_header_data, + string* http_response_data); + bool SendGetRequest(const string& url, + long* http_status_code, + string* http_header_data, + string* http_response_data); + bool SendPutRequest(const string& url, + const string& path, + long* http_status_code, + string* http_header_data, + string* http_response_data); + bool SendSimplePostRequest(const string& url, + const string& body, + const string& content_type, + long* http_status_code, + string* http_header_data, + string* http_response_data); + + private: + // This function initializes class state corresponding to function + // pointers into the CURL library. + bool SetFunctionPointers(); + + bool SendRequestInner(const string& url, + long* http_status_code, + string* http_header_data, + string* http_response_data); + + void Reset(); + + bool CheckInit(); + + bool init_ok_; // Whether init succeeded + void* curl_lib_; // Pointer to result of dlopen() on + // curl library + string last_curl_error_; // The text of the last error when + // dealing + // with CURL. + + CURL* curl_; // Pointer for handle for CURL calls. + + CURL* (*easy_init_)(void); + + // Stateful pointers for calling into curl_formadd() + struct curl_httppost* formpost_; + struct curl_httppost* lastptr_; + struct curl_slist* headerlist_; + + // Function pointers into CURL library + CURLcode (*easy_setopt_)(CURL*, CURLoption, ...); + CURLFORMcode (*formadd_)(struct curl_httppost**, + struct curl_httppost**, ...); + struct curl_slist* (*slist_append_)(struct curl_slist*, const char*); + void (*slist_free_all_)(struct curl_slist*); + CURLcode (*easy_perform_)(CURL*); + const char* (*easy_strerror_)(CURLcode); + void (*easy_cleanup_)(CURL*); + CURLcode (*easy_getinfo_)(CURL*, CURLINFO info, ...); + void (*easy_reset_)(CURL*); + void (*formfree_)(struct curl_httppost*); + +}; +} + +#endif // COMMON_LINUX_LIBCURL_WRAPPER_H_ diff --git a/contrib/libs/breakpad/src/common/linux/linux_libc_support.cc b/contrib/libs/breakpad/src/common/linux/linux_libc_support.cc new file mode 100644 index 0000000000..dd29296262 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/linux_libc_support.cc @@ -0,0 +1,237 @@ +// Copyright (c) 2012, 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. + +// This source file provides replacements for libc functions that we need. If +// we call the libc functions directly we risk crashing in the dynamic linker +// as it tries to resolve uncached PLT entries. + +#include "common/linux/linux_libc_support.h" + +#include <stddef.h> + +extern "C" { + +size_t my_strlen(const char* s) { + size_t len = 0; + while (*s++) len++; + return len; +} + +int my_strcmp(const char* a, const char* b) { + for (;;) { + if (*a < *b) + return -1; + else if (*a > *b) + return 1; + else if (*a == 0) + return 0; + a++; + b++; + } +} + +int my_strncmp(const char* a, const char* b, size_t len) { + for (size_t i = 0; i < len; ++i) { + if (*a < *b) + return -1; + else if (*a > *b) + return 1; + else if (*a == 0) + return 0; + a++; + b++; + } + + return 0; +} + +// Parse a non-negative integer. +// result: (output) the resulting non-negative integer +// s: a NUL terminated string +// Return true iff successful. +bool my_strtoui(int* result, const char* s) { + if (*s == 0) + return false; + int r = 0; + for (;; s++) { + if (*s == 0) + break; + const int old_r = r; + r *= 10; + if (*s < '0' || *s > '9') + return false; + r += *s - '0'; + if (r < old_r) + return false; + } + + *result = r; + return true; +} + +// Return the length of the given unsigned integer when expressed in base 10. +unsigned my_uint_len(uintmax_t i) { + if (!i) + return 1; + + int len = 0; + while (i) { + len++; + i /= 10; + } + + return len; +} + +// Convert an unsigned integer to a string +// output: (output) the resulting string is written here. This buffer must be +// large enough to hold the resulting string. Call |my_uint_len| to get the +// required length. +// i: the unsigned integer to serialise. +// i_len: the length of the integer in base 10 (see |my_uint_len|). +void my_uitos(char* output, uintmax_t i, unsigned i_len) { + for (unsigned index = i_len; index; --index, i /= 10) + output[index - 1] = '0' + (i % 10); +} + +const char* my_strchr(const char* haystack, char needle) { + while (*haystack && *haystack != needle) + haystack++; + if (*haystack == needle) + return haystack; + return (const char*) 0; +} + +const char* my_strrchr(const char* haystack, char needle) { + const char* ret = NULL; + while (*haystack) { + if (*haystack == needle) + ret = haystack; + haystack++; + } + return ret; +} + +void* my_memchr(const void* src, int needle, size_t src_len) { + const unsigned char* p = (const unsigned char*)src; + const unsigned char* p_end = p + src_len; + for (; p < p_end; ++p) { + if (*p == needle) + return (void*)p; + } + return NULL; +} + +// Read a hex value +// result: (output) the resulting value +// s: a string +// Returns a pointer to the first invalid charactor. +const char* my_read_hex_ptr(uintptr_t* result, const char* s) { + uintptr_t r = 0; + + for (;; ++s) { + if (*s >= '0' && *s <= '9') { + r <<= 4; + r += *s - '0'; + } else if (*s >= 'a' && *s <= 'f') { + r <<= 4; + r += (*s - 'a') + 10; + } else if (*s >= 'A' && *s <= 'F') { + r <<= 4; + r += (*s - 'A') + 10; + } else { + break; + } + } + + *result = r; + return s; +} + +const char* my_read_decimal_ptr(uintptr_t* result, const char* s) { + uintptr_t r = 0; + + for (;; ++s) { + if (*s >= '0' && *s <= '9') { + r *= 10; + r += *s - '0'; + } else { + break; + } + } + *result = r; + return s; +} + +void my_memset(void* ip, char c, size_t len) { + char* p = (char*) ip; + while (len--) + *p++ = c; +} + +size_t my_strlcpy(char* s1, const char* s2, size_t len) { + size_t pos1 = 0; + size_t pos2 = 0; + + while (s2[pos2] != '\0') { + if (pos1 + 1 < len) { + s1[pos1] = s2[pos2]; + pos1++; + } + pos2++; + } + if (len > 0) + s1[pos1] = '\0'; + + return pos2; +} + +size_t my_strlcat(char* s1, const char* s2, size_t len) { + size_t pos1 = 0; + + while (pos1 < len && s1[pos1] != '\0') + pos1++; + + if (pos1 == len) + return pos1; + + return pos1 + my_strlcpy(s1 + pos1, s2, len - pos1); +} + +int my_isspace(int ch) { + // Matches the C locale. + const char spaces[] = " \t\f\n\r\t\v"; + for (size_t i = 0; i < sizeof(spaces); i++) { + if (ch == spaces[i]) + return 1; + } + return 0; +} + +} // extern "C" diff --git a/contrib/libs/breakpad/src/common/linux/linux_libc_support.h b/contrib/libs/breakpad/src/common/linux/linux_libc_support.h new file mode 100644 index 0000000000..ec5a8d6b6b --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/linux_libc_support.h @@ -0,0 +1,96 @@ +// Copyright (c) 2009, 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. + +// This header provides replacements for libc functions that we need. We if +// call the libc functions directly we risk crashing in the dynamic linker as +// it tries to resolve uncached PLT entries. + +#ifndef CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_ +#define CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_ + +#include <stdint.h> +#include <limits.h> +#include <sys/types.h> + +extern "C" { + +extern size_t my_strlen(const char* s); + +extern int my_strcmp(const char* a, const char* b); + +extern int my_strncmp(const char* a, const char* b, size_t len); + +// Parse a non-negative integer. +// result: (output) the resulting non-negative integer +// s: a NUL terminated string +// Return true iff successful. +extern bool my_strtoui(int* result, const char* s); + +// Return the length of the given unsigned integer when expressed in base 10. +extern unsigned my_uint_len(uintmax_t i); + +// Convert an unsigned integer to a string +// output: (output) the resulting string is written here. This buffer must be +// large enough to hold the resulting string. Call |my_uint_len| to get the +// required length. +// i: the unsigned integer to serialise. +// i_len: the length of the integer in base 10 (see |my_uint_len|). +extern void my_uitos(char* output, uintmax_t i, unsigned i_len); + +extern const char* my_strchr(const char* haystack, char needle); + +extern const char* my_strrchr(const char* haystack, char needle); + +// Read a hex value +// result: (output) the resulting value +// s: a string +// Returns a pointer to the first invalid charactor. +extern const char* my_read_hex_ptr(uintptr_t* result, const char* s); + +extern const char* my_read_decimal_ptr(uintptr_t* result, const char* s); + +extern void my_memset(void* ip, char c, size_t len); + +extern void* my_memchr(const void* src, int c, size_t len); + +// The following are considered safe to use in a compromised environment. +// Besides, this gives the compiler an opportunity to optimize their calls. +#define my_memcpy memcpy +#define my_memmove memmove +#define my_memcmp memcmp + +extern size_t my_strlcpy(char* s1, const char* s2, size_t len); + +extern size_t my_strlcat(char* s1, const char* s2, size_t len); + +extern int my_isspace(int ch); + +} // extern "C" + +#endif // CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_ diff --git a/contrib/libs/breakpad/src/common/linux/memory_mapped_file.cc b/contrib/libs/breakpad/src/common/linux/memory_mapped_file.cc new file mode 100644 index 0000000000..99362945ca --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/memory_mapped_file.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2011, 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. + +// memory_mapped_file.cc: Implement google_breakpad::MemoryMappedFile. +// See memory_mapped_file.h for details. + +#include "common/linux/memory_mapped_file.h" + +#include <fcntl.h> +#include <sys/mman.h> +#if defined(__ANDROID__) +#include <sys/stat.h> +#endif +#include <unistd.h> + +#include "common/memory_range.h" +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +MemoryMappedFile::MemoryMappedFile() {} + +MemoryMappedFile::MemoryMappedFile(const char* path, size_t offset) { + Map(path, offset); +} + +MemoryMappedFile::~MemoryMappedFile() { + Unmap(); +} + +#include <unistd.h> + +bool MemoryMappedFile::Map(const char* path, size_t offset) { + Unmap(); + + int fd = sys_open(path, O_RDONLY, 0); + if (fd == -1) { + return false; + } + +#if defined(__x86_64__) || defined(__aarch64__) || \ + (defined(__mips__) && _MIPS_SIM == _ABI64) + + struct kernel_stat st; + if (sys_fstat(fd, &st) == -1 || st.st_size < 0) { +#else + struct kernel_stat64 st; + if (sys_fstat64(fd, &st) == -1 || st.st_size < 0) { +#endif + sys_close(fd); + return false; + } + + // Strangely file size can be negative, but we check above that it is not. + size_t file_len = static_cast<size_t>(st.st_size); + // If the file does not extend beyond the offset, simply use an empty + // MemoryRange and return true. Don't bother to call mmap() + // even though mmap() can handle an empty file on some platforms. + if (offset >= file_len) { + sys_close(fd); + return true; + } + + size_t content_len = file_len - offset; + void* data = sys_mmap(NULL, content_len, PROT_READ, MAP_PRIVATE, fd, offset); + sys_close(fd); + if (data == MAP_FAILED) { + return false; + } + + content_.Set(data, content_len); + return true; +} + +void MemoryMappedFile::Unmap() { + if (content_.data()) { + sys_munmap(const_cast<uint8_t*>(content_.data()), content_.length()); + content_.Set(NULL, 0); + } +} + +} // namespace google_breakpad diff --git a/contrib/libs/breakpad/src/common/linux/memory_mapped_file.h b/contrib/libs/breakpad/src/common/linux/memory_mapped_file.h new file mode 100644 index 0000000000..fa660cc91a --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/memory_mapped_file.h @@ -0,0 +1,87 @@ +// Copyright (c) 2011, 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. + +// memory_mapped_file.h: Define the google_breakpad::MemoryMappedFile +// class, which maps a file into memory for read-only access. + +#ifndef COMMON_LINUX_MEMORY_MAPPED_FILE_H_ +#define COMMON_LINUX_MEMORY_MAPPED_FILE_H_ + +#include <stddef.h> +#include "common/basictypes.h" +#include "common/memory_range.h" + +namespace google_breakpad { + +// A utility class for mapping a file into memory for read-only access of +// the file content. Its implementation avoids calling into libc functions +// by directly making system calls for open, close, mmap, and munmap. +class MemoryMappedFile { + public: + MemoryMappedFile(); + + // Constructor that calls Map() to map a file at |path| into memory. + // If Map() fails, the object behaves as if it is default constructed. + MemoryMappedFile(const char* path, size_t offset); + + ~MemoryMappedFile(); + + // Maps a file at |path| into memory, which can then be accessed via + // content() as a MemoryRange object or via data(), and returns true on + // success. Mapping an empty file will succeed but with data() and size() + // returning NULL and 0, respectively. An existing mapping is unmapped + // before a new mapping is created. + bool Map(const char* path, size_t offset); + + // Unmaps the memory for the mapped file. It's a no-op if no file is + // mapped. + void Unmap(); + + // Returns a MemoryRange object that covers the memory for the mapped + // file. The MemoryRange object is empty if no file is mapped. + const MemoryRange& content() const { return content_; } + + // Returns a pointer to the beginning of the memory for the mapped file. + // or NULL if no file is mapped or the mapped file is empty. + const void* data() const { return content_.data(); } + + // Returns the size in bytes of the mapped file, or zero if no file + // is mapped. + size_t size() const { return content_.length(); } + + private: + // Mapped file content as a MemoryRange object. + MemoryRange content_; + + DISALLOW_COPY_AND_ASSIGN(MemoryMappedFile); +}; + +} // namespace google_breakpad + +#endif // COMMON_LINUX_MEMORY_MAPPED_FILE_H_ diff --git a/contrib/libs/breakpad/src/common/linux/safe_readlink.cc b/contrib/libs/breakpad/src/common/linux/safe_readlink.cc new file mode 100644 index 0000000000..870c28af3b --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/safe_readlink.cc @@ -0,0 +1,53 @@ +// Copyright (c) 2011, 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. + +// safe_readlink.cc: Implement google_breakpad::SafeReadLink. +// See safe_readlink.h for details. + +#include <stddef.h> + +#include "third_party/lss/linux_syscall_support.h" + +namespace google_breakpad { + +bool SafeReadLink(const char* path, char* buffer, size_t buffer_size) { + // sys_readlink() does not add a NULL byte to |buffer|. In order to return + // a NULL-terminated string in |buffer|, |buffer_size| should be at least + // one byte longer than the expected path length. Also, sys_readlink() + // returns the actual path length on success, which does not count the + // NULL byte, so |result_size| should be less than |buffer_size|. + ssize_t result_size = sys_readlink(path, buffer, buffer_size); + if (result_size >= 0 && static_cast<size_t>(result_size) < buffer_size) { + buffer[result_size] = '\0'; + return true; + } + return false; +} + +} // namespace google_breakpad diff --git a/contrib/libs/breakpad/src/common/linux/safe_readlink.h b/contrib/libs/breakpad/src/common/linux/safe_readlink.h new file mode 100644 index 0000000000..4ae131b580 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/safe_readlink.h @@ -0,0 +1,65 @@ +// Copyright (c) 2011, 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. + +// safe_readlink.h: Define the google_breakpad::SafeReadLink function, +// which wraps sys_readlink and gurantees the result is NULL-terminated. + +#ifndef COMMON_LINUX_SAFE_READLINK_H_ +#define COMMON_LINUX_SAFE_READLINK_H_ + +#include <stddef.h> + +namespace google_breakpad { + +// This function wraps sys_readlink() and performs the same functionalty, +// but guarantees |buffer| is NULL-terminated if sys_readlink() returns +// no error. It takes the same arguments as sys_readlink(), but unlike +// sys_readlink(), it returns true on success. +// +// |buffer_size| specifies the size of |buffer| in bytes. As this function +// always NULL-terminates |buffer| on success, |buffer_size| should be +// at least one byte longer than the expected path length (e.g. PATH_MAX, +// which is typically defined as the maximum length of a path name +// including the NULL byte). +// +// The implementation of this function calls sys_readlink() instead of +// readlink(), it can thus be used in the context where calling to libc +// functions is discouraged. +bool SafeReadLink(const char* path, char* buffer, size_t buffer_size); + +// Same as the three-argument version of SafeReadLink() but deduces the +// size of |buffer| if it is a char array of known size. +template <size_t N> +bool SafeReadLink(const char* path, char (&buffer)[N]) { + return SafeReadLink(path, buffer, sizeof(buffer)); +} + +} // namespace google_breakpad + +#endif // COMMON_LINUX_SAFE_READLINK_H_ diff --git a/contrib/libs/breakpad/src/common/linux/symbol_collector_client.cc b/contrib/libs/breakpad/src/common/linux/symbol_collector_client.cc new file mode 100644 index 0000000000..92b25ddba9 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/symbol_collector_client.cc @@ -0,0 +1,195 @@ +// Copyright (c) 2019 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. + +#include "common/linux/symbol_collector_client.h" + +#include <stdio.h> + +#include <iostream> +#include <regex> + +#include "common/linux/libcurl_wrapper.h" + +namespace google_breakpad { +namespace sym_upload { + +// static +bool SymbolCollectorClient::CreateUploadUrl( + LibcurlWrapper* libcurl_wrapper, + const string& api_url, + const string& api_key, + UploadUrlResponse* uploadUrlResponse) { + string header, response; + long response_code; + + string url = api_url + "/v1/uploads:create"; + if (!api_key.empty()) { + url += "?key=" + api_key; + } + + if (!libcurl_wrapper->SendSimplePostRequest(url, + /*body=*/"", + /*content_type=*/"", + &response_code, + &header, + &response)) { + printf("Failed to create upload url.\n"); + printf("Response code: %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return false; + } + + // Note camel-case rather than underscores. + std::regex upload_url_regex("\"uploadUrl\": \"([^\"]+)\""); + std::regex upload_key_regex("\"uploadKey\": \"([^\"]+)\""); + + std::smatch upload_url_match; + if (!std::regex_search(response, upload_url_match, upload_url_regex) || + upload_url_match.size() != 2) { + printf("Failed to parse create url response."); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return false; + } + string upload_url = upload_url_match[1].str(); + + std::smatch upload_key_match; + if (!std::regex_search(response, upload_key_match, upload_key_regex) || + upload_key_match.size() != 2) { + printf("Failed to parse create url response."); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return false; + } + string upload_key = upload_key_match[1].str(); + + uploadUrlResponse->upload_url = upload_url; + uploadUrlResponse->upload_key = upload_key; + return true; +} + +// static +CompleteUploadResult SymbolCollectorClient::CompleteUpload( + LibcurlWrapper* libcurl_wrapper, + const string& api_url, + const string& api_key, + const string& upload_key, + const string& debug_file, + const string& debug_id, + const string& type) { + string header, response; + long response_code; + + string url = api_url + "/v1/uploads/" + upload_key + ":complete"; + if (!api_key.empty()) { + url += "?key=" + api_key; + } + string body = + "{ symbol_id: {" + "debug_file: \"" + debug_file + "\", " + "debug_id: \"" + debug_id + "\" }, " + "symbol_upload_type: \"" + type + "\" }"; + + if (!libcurl_wrapper->SendSimplePostRequest(url, + body, + "application/son", + &response_code, + &header, + &response)) { + printf("Failed to complete upload.\n"); + printf("Response code: %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return CompleteUploadResult::Error; + } + + std::regex result_regex("\"result\": \"([^\"]+)\""); + std::smatch result_match; + if (!std::regex_search(response, result_match, result_regex) || + result_match.size() != 2) { + printf("Failed to parse complete upload response."); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return CompleteUploadResult::Error; + } + string result = result_match[1].str(); + + if (result.compare("DUPLICATE_DATA") == 0) { + return CompleteUploadResult::DuplicateData; + } + + return CompleteUploadResult::Ok; +} + +// static +SymbolStatus SymbolCollectorClient::CheckSymbolStatus( + LibcurlWrapper* libcurl_wrapper, + const string& api_url, + const string& api_key, + const string& debug_file, + const string& debug_id) { + string header, response; + long response_code; + string url = api_url + + "/v1/symbols/" + debug_file + "/" + debug_id + ":checkStatus"; + if (!api_key.empty()) { + url += "?key=" + api_key; + } + + if (!libcurl_wrapper->SendGetRequest( + url, + &response_code, + &header, + &response)) { + printf("Failed to check symbol status, error message.\n"); + printf("Response code: %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return SymbolStatus::Unknown; + } + + std::regex status_regex("\"status\": \"([^\"]+)\""); + std::smatch status_match; + if (!std::regex_search(response, status_match, status_regex) || + status_match.size() != 2) { + printf("Failed to parse check symbol status response."); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return SymbolStatus::Unknown; + } + string status = status_match[1].str(); + + return (status.compare("FOUND") == 0) ? + SymbolStatus::Found : + SymbolStatus::Missing; +} + +} // namespace sym_upload +} // namespace google_breakpad diff --git a/contrib/libs/breakpad/src/common/linux/symbol_collector_client.h b/contrib/libs/breakpad/src/common/linux/symbol_collector_client.h new file mode 100644 index 0000000000..0e23242a2b --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/symbol_collector_client.h @@ -0,0 +1,88 @@ +// Copyright (c) 2019, 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. + +#ifndef COMMON_LINUX_SYMBOL_COLLECTOR_CLIENT_H_ +#define COMMON_LINUX_SYMBOL_COLLECTOR_CLIENT_H_ + +#include <string> + +#include "common/linux/libcurl_wrapper.h" +#include "common/using_std_string.h" + +namespace google_breakpad { +namespace sym_upload { + +struct UploadUrlResponse { + string upload_url; + string upload_key; +}; + +enum SymbolStatus { + Found, + Missing, + Unknown +}; + +enum CompleteUploadResult { + Ok, + DuplicateData, + Error +}; + +// Helper class to communicate with a sym-upload-v2 service over HTTP/REST, +// via libcurl. +class SymbolCollectorClient { + public: + static bool CreateUploadUrl( + LibcurlWrapper* libcurl_wrapper, + const string& api_url, + const string& api_key, + UploadUrlResponse* uploadUrlResponse); + + static CompleteUploadResult CompleteUpload( + LibcurlWrapper* libcurl_wrapper, + const string& api_url, + const string& api_key, + const string& upload_key, + const string& debug_file, + const string& debug_id, + const string& type); + + static SymbolStatus CheckSymbolStatus( + LibcurlWrapper* libcurl_wrapper, + const string& api_url, + const string& api_key, + const string& debug_file, + const string& debug_id); +}; + +} // namespace sym_upload +} // namespace google_breakpad + +#endif // COMMON_LINUX_SYMBOL_COLLECTOR_CLIENT_H_ diff --git a/contrib/libs/breakpad/src/common/linux/symbol_upload.cc b/contrib/libs/breakpad/src/common/linux/symbol_upload.cc new file mode 100644 index 0000000000..1d5ff71965 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/symbol_upload.cc @@ -0,0 +1,284 @@ +// Copyright (c) 2011 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. + +// symbol_upload.cc: implemented google_breakpad::sym_upload::Start, a helper +// function for linux symbol upload tool. + +#include "common/linux/symbol_upload.h" + +#include <assert.h> +#include <stdio.h> + +#include <functional> +#include <iostream> +#include <vector> + +#include "common/linux/http_upload.h" +#include "common/linux/libcurl_wrapper.h" +#include "common/linux/symbol_collector_client.h" + +namespace google_breakpad { +namespace sym_upload { + +void TokenizeByChar(const string& source_string, int c, + std::vector<string>* results) { + assert(results); + string::size_type cur_pos = 0, next_pos = 0; + while ((next_pos = source_string.find(c, cur_pos)) != string::npos) { + if (next_pos != cur_pos) + results->push_back(source_string.substr(cur_pos, next_pos - cur_pos)); + cur_pos = next_pos + 1; + } + if (cur_pos < source_string.size() && next_pos != cur_pos) + results->push_back(source_string.substr(cur_pos)); +} + +//============================================================================= +// Parse out the module line which have 5 parts. +// MODULE <os> <cpu> <uuid> <module-name> +bool ModuleDataForSymbolFile(const string& file, + std::vector<string>* module_parts) { + assert(module_parts); + const size_t kModulePartNumber = 5; + FILE* fp = fopen(file.c_str(), "r"); + if (fp) { + char buffer[1024]; + if (fgets(buffer, sizeof(buffer), fp)) { + string line(buffer); + string::size_type line_break_pos = line.find_first_of('\n'); + if (line_break_pos == string::npos) { + assert(0 && "The file is invalid!"); + fclose(fp); + return false; + } + line.resize(line_break_pos); + const char kDelimiter = ' '; + TokenizeByChar(line, kDelimiter, module_parts); + if (module_parts->size() != kModulePartNumber) + module_parts->clear(); + } + fclose(fp); + } + + return module_parts->size() == kModulePartNumber; +} + +//============================================================================= +string CompactIdentifier(const string& uuid) { + std::vector<string> components; + TokenizeByChar(uuid, '-', &components); + string result; + for (size_t i = 0; i < components.size(); ++i) + result += components[i]; + return result; +} + +// |options| describes the current sym_upload options. +// |module_parts| contains the strings parsed from the MODULE entry of the +// Breakpad symbol file being uploaded. +// |compacted_id| is the debug_id from the MODULE entry of the Breakpad symbol +// file being uploaded, with all hyphens removed. +bool SymUploadV1Start( + const Options& options, + std::vector<string> module_parts, + const string& compacted_id) { + std::map<string, string> parameters; + // Add parameters + if (!options.version.empty()) + parameters["version"] = options.version; + + // MODULE <os> <cpu> <uuid> <module-name> + // 0 1 2 3 4 + parameters["os"] = module_parts[1]; + parameters["cpu"] = module_parts[2]; + parameters["debug_file"] = module_parts[4]; + parameters["code_file"] = module_parts[4]; + parameters["debug_identifier"] = compacted_id; + + std::map<string, string> files; + files["symbol_file"] = options.symbolsPath; + + string response, error; + long response_code; + bool success = HTTPUpload::SendRequest(options.uploadURLStr, + parameters, + files, + options.proxy, + options.proxy_user_pwd, + /*ca_certificate_file=*/"", + &response, + &response_code, + &error); + + if (!success) { + printf("Failed to send symbol file: %s\n", error.c_str()); + printf("Response code: %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + } else if (response_code == 0) { + printf("Failed to send symbol file: No response code\n"); + } else if (response_code != 200) { + printf("Failed to send symbol file: Response code %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + } else { + printf("Successfully sent the symbol file.\n"); + } + + return success; +} + +// |options| describes the current sym_upload options. +// |code_id| is the basename of the module for which symbols are being +// uploaded. +// |debug_id| is the debug_id of the module for which symbols are being +// uploaded. +bool SymUploadV2Start( + const Options& options, + const string& code_file, + const string& debug_id, + const string& type) { + google_breakpad::LibcurlWrapper libcurl_wrapper; + if (!libcurl_wrapper.Init()) { + printf("Failed to init google_breakpad::LibcurlWrapper.\n"); + return false; + } + + if (!options.force) { + SymbolStatus symbolStatus = SymbolCollectorClient::CheckSymbolStatus( + &libcurl_wrapper, + options.uploadURLStr, + options.api_key, + code_file, + debug_id); + if (symbolStatus == SymbolStatus::Found) { + printf("Symbol file already exists, upload aborted." + " Use \"-f\" to overwrite.\n"); + return true; + } else if (symbolStatus == SymbolStatus::Unknown) { + printf("Failed to check for existing symbol.\n"); + return false; + } + } + + UploadUrlResponse uploadUrlResponse; + if (!SymbolCollectorClient::CreateUploadUrl( + &libcurl_wrapper, + options.uploadURLStr, + options.api_key, + &uploadUrlResponse)) { + printf("Failed to create upload URL.\n"); + return false; + } + + string signed_url = uploadUrlResponse.upload_url; + string upload_key = uploadUrlResponse.upload_key; + string header; + string response; + long response_code; + + if (!libcurl_wrapper.SendPutRequest(signed_url, + options.symbolsPath, + &response_code, + &header, + &response)) { + printf("Failed to send symbol file.\n"); + printf("Response code: %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return false; + } else if (response_code == 0) { + printf("Failed to send symbol file: No response code\n"); + return false; + } else if (response_code != 200) { + printf("Failed to send symbol file: Response code %ld\n", response_code); + printf("Response:\n"); + printf("%s\n", response.c_str()); + return false; + } + + CompleteUploadResult completeUploadResult = + SymbolCollectorClient::CompleteUpload(&libcurl_wrapper, + options.uploadURLStr, + options.api_key, + upload_key, + code_file, + debug_id, + type); + if (completeUploadResult == CompleteUploadResult::Error) { + printf("Failed to complete upload.\n"); + return false; + } else if (completeUploadResult == CompleteUploadResult::DuplicateData) { + printf("Uploaded file checksum matched existing file checksum," + " no change necessary.\n"); + } else { + printf("Successfully sent the symbol file.\n"); + } + + return true; +} + +//============================================================================= +void Start(Options* options) { + if (options->upload_protocol == UploadProtocol::SYM_UPLOAD_V2) { + string code_file; + string debug_id; + string type; + + if (options->type.empty() || options->type == kBreakpadSymbolType) { + // Breakpad upload so read these from input file. + std::vector<string> module_parts; + if (!ModuleDataForSymbolFile(options->symbolsPath, &module_parts)) { + fprintf(stderr, "Failed to parse symbol file!\n"); + return; + } + code_file = module_parts[4]; + debug_id = CompactIdentifier(module_parts[3]); + type = kBreakpadSymbolType; + } else { + // Native upload so these must be explicitly set. + code_file = options->code_file; + debug_id = options->debug_id; + type = options->type; + } + + options->success = SymUploadV2Start(*options, code_file, debug_id, type); + } else { + std::vector<string> module_parts; + if (!ModuleDataForSymbolFile(options->symbolsPath, &module_parts)) { + fprintf(stderr, "Failed to parse symbol file!\n"); + return; + } + const string compacted_id = CompactIdentifier(module_parts[3]); + options->success = SymUploadV1Start(*options, module_parts, compacted_id); + } +} + +} // namespace sym_upload +} // namespace google_breakpad diff --git a/contrib/libs/breakpad/src/common/linux/symbol_upload.h b/contrib/libs/breakpad/src/common/linux/symbol_upload.h new file mode 100644 index 0000000000..9033152bf2 --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/symbol_upload.h @@ -0,0 +1,76 @@ +// -*- mode: c++ -*- + +// Copyright (c) 2011 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. + +// symbol_upload.h: helper functions for linux symbol upload tool. + +#ifndef COMMON_LINUX_SYMBOL_UPLOAD_H_ +#define COMMON_LINUX_SYMBOL_UPLOAD_H_ + +#include <string> + +#include "common/using_std_string.h" + +namespace google_breakpad { +namespace sym_upload { + +enum class UploadProtocol { + SYM_UPLOAD_V1, + SYM_UPLOAD_V2, +}; + +constexpr char kBreakpadSymbolType[] = "BREAKPAD"; + +struct Options { + Options() : upload_protocol(UploadProtocol::SYM_UPLOAD_V1), force(false) {} + + string symbolsPath; + string uploadURLStr; + string proxy; + string proxy_user_pwd; + string version; + bool success; + UploadProtocol upload_protocol; + bool force; + string api_key; + + // These only need to be set for native symbol uploads. + string code_file; + string debug_id; + string type; +}; + +// Starts upload to symbol server with options. +void Start(Options* options); + +} // namespace sym_upload +} // namespace google_breakpad + +#endif // COMMON_LINUX_SYMBOL_UPLOAD_H_ diff --git a/contrib/libs/breakpad/src/common/linux/ucontext_constants.h b/contrib/libs/breakpad/src/common/linux/ucontext_constants.h new file mode 100644 index 0000000000..c390508a1a --- /dev/null +++ b/contrib/libs/breakpad/src/common/linux/ucontext_constants.h @@ -0,0 +1,153 @@ +// Copyright (c) 2012, 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. + +// This header can be included either from a C, C++ or Assembly file. +// Its purpose is to contain constants that must match the offsets of +// various fields in ucontext_t. +// +// They should match the definitions from signal.h. +// +// Used by src/common/linux/breakpad_getcontext.S +// Tested by src/common/linux/breakpad_getcontext_unittest.cc +// +// This header should not be used by anything else. + +#ifndef GOOGLEBREAKPAD_COMMON_LINUX_UCONTEXT_CONSTANTS_H +#define GOOGLEBREAKPAD_COMMON_LINUX_UCONTEXT_CONSTANTS_H + +#if defined(__arm__) + +#define MCONTEXT_GREGS_OFFSET 32 +#define UCONTEXT_SIGMASK_OFFSET 104 + +#elif defined(__aarch64__) + +#define UCONTEXT_SIGMASK_OFFSET 40 + +#define MCONTEXT_GREGS_OFFSET 184 +#define MCONTEXT_SP_OFFSET 432 +#define MCONTEXT_PC_OFFSET 440 +#define MCONTEXT_PSTATE_OFFSET 448 +#define MCONTEXT_EXTENSION_OFFSET 464 + +#define FPSIMD_MAGIC 0x46508001 + +#define FPSIMD_CONTEXT_MAGIC_OFFSET 0 +#define FPSIMD_CONTEXT_SIZE_OFFSET 4 +#define FPSIMD_CONTEXT_FPSR_OFFSET 8 +#define FPSIMD_CONTEXT_FPCR_OFFSET 12 +#define FPSIMD_CONTEXT_VREGS_OFFSET 16 +#define FPSIMD_CONTEXT_SIZE 528 + +#define REGISTER_SIZE 8 +#define SIMD_REGISTER_SIZE 16 + +#elif defined(__i386__) + +#define MCONTEXT_GREGS_OFFSET 20 +#define MCONTEXT_GS_OFFSET (MCONTEXT_GREGS_OFFSET + 0*4) +#define MCONTEXT_FS_OFFSET (MCONTEXT_GREGS_OFFSET + 1*4) +#define MCONTEXT_ES_OFFSET (MCONTEXT_GREGS_OFFSET + 2*4) +#define MCONTEXT_DS_OFFSET (MCONTEXT_GREGS_OFFSET + 3*4) +#define MCONTEXT_EDI_OFFSET (MCONTEXT_GREGS_OFFSET + 4*4) +#define MCONTEXT_ESI_OFFSET (MCONTEXT_GREGS_OFFSET + 5*4) +#define MCONTEXT_EBP_OFFSET (MCONTEXT_GREGS_OFFSET + 6*4) +#define MCONTEXT_ESP_OFFSET (MCONTEXT_GREGS_OFFSET + 7*4) +#define MCONTEXT_EBX_OFFSET (MCONTEXT_GREGS_OFFSET + 8*4) +#define MCONTEXT_EDX_OFFSET (MCONTEXT_GREGS_OFFSET + 9*4) +#define MCONTEXT_ECX_OFFSET (MCONTEXT_GREGS_OFFSET + 10*4) +#define MCONTEXT_EAX_OFFSET (MCONTEXT_GREGS_OFFSET + 11*4) +#define MCONTEXT_TRAPNO_OFFSET (MCONTEXT_GREGS_OFFSET + 12*4) +#define MCONTEXT_ERR_OFFSET (MCONTEXT_GREGS_OFFSET + 13*4) +#define MCONTEXT_EIP_OFFSET (MCONTEXT_GREGS_OFFSET + 14*4) +#define MCONTEXT_CS_OFFSET (MCONTEXT_GREGS_OFFSET + 15*4) +#define MCONTEXT_EFL_OFFSET (MCONTEXT_GREGS_OFFSET + 16*4) +#define MCONTEXT_UESP_OFFSET (MCONTEXT_GREGS_OFFSET + 17*4) +#define MCONTEXT_SS_OFFSET (MCONTEXT_GREGS_OFFSET + 18*4) + +#define UCONTEXT_SIGMASK_OFFSET 108 + +#define UCONTEXT_FPREGS_OFFSET 96 +#if defined(__BIONIC__) +#define UCONTEXT_FPREGS_MEM_OFFSET 116 +#else +#define UCONTEXT_FPREGS_MEM_OFFSET 236 +#endif + +#elif defined(__mips__) + +#if _MIPS_SIM == _ABIO32 +#define MCONTEXT_PC_OFFSET 32 +#define MCONTEXT_GREGS_OFFSET 40 +#define MCONTEXT_FPREGS_OFFSET 296 +#define MCONTEXT_FPC_CSR 556 +#define UCONTEXT_SIGMASK_OFFSET 616 +#else +#define MCONTEXT_GREGS_OFFSET 40 +#define MCONTEXT_FPREGS_OFFSET 296 +#define MCONTEXT_PC_OFFSET 616 +#define MCONTEXT_FPC_CSR 624 +#define UCONTEXT_SIGMASK_OFFSET 640 +#endif + +#elif defined(__x86_64__) + +#define MCONTEXT_GREGS_OFFSET 40 +#define UCONTEXT_SIGMASK_OFFSET 296 + +#define MCONTEXT_GREGS_R8 40 +#define MCONTEXT_GREGS_R9 48 +#define MCONTEXT_GREGS_R10 56 +#define MCONTEXT_GREGS_R11 64 +#define MCONTEXT_GREGS_R12 72 +#define MCONTEXT_GREGS_R13 80 +#define MCONTEXT_GREGS_R14 88 +#define MCONTEXT_GREGS_R15 96 +#define MCONTEXT_GREGS_RDI 104 +#define MCONTEXT_GREGS_RSI 112 +#define MCONTEXT_GREGS_RBP 120 +#define MCONTEXT_GREGS_RBX 128 +#define MCONTEXT_GREGS_RDX 136 +#define MCONTEXT_GREGS_RAX 144 +#define MCONTEXT_GREGS_RCX 152 +#define MCONTEXT_GREGS_RSP 160 +#define MCONTEXT_GREGS_RIP 168 +#define MCONTEXT_FPREGS_PTR 224 +#if defined(__BIONIC__) +#define MCONTEXT_FPREGS_MEM 304 +#else +#define MCONTEXT_FPREGS_MEM 424 +#endif +#define FPREGS_OFFSET_MXCSR 24 + +#else +#error "This header has not been ported for your CPU" +#endif + +#endif // GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H |