diff options
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/common')
200 files changed, 0 insertions, 55208 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/common/Makefile.in b/toolkit/crashreporter/google-breakpad/src/common/Makefile.in deleted file mode 100644 index 44a1f79fd..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/Makefile.in +++ /dev/null @@ -1,9 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -include $(topsrcdir)/config/rules.mk - -# memory.h in this dir breaks things if -I$(srcdir) gets added, since memory.h -# is also a system header and the copy here winds up getting included instead. -INCLUDES := $(LOCAL_INCLUDES) -I$(DIST)/include diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/breakpad_getcontext.S b/toolkit/crashreporter/google-breakpad/src/common/android/breakpad_getcontext.S deleted file mode 100644 index fd6326adf..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/breakpad_getcontext.S +++ /dev/null @@ -1,489 +0,0 @@ -// 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 on Android. - -#include "common/android/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__) - -#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: - - /* 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 - 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. -#if _MIPS_SIM == _ABIO32 -#include <asm/asm.h> -#include <asm/regdef.h> -#include <asm/fpregdef.h> -#else -#include <machine/asm.h> -#include <machine/regdef.h> -#endif - -// from asm/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 diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/breakpad_getcontext_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/android/breakpad_getcontext_unittest.cc deleted file mode 100644 index 2c550bf28..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/breakpad_getcontext_unittest.cc +++ /dev/null @@ -1,186 +0,0 @@ -// 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. - -#if defined(__x86_64__) -#include <asm/sigcontext.h> -#endif - -#include <sys/ucontext.h> - -#include "breakpad_googletest_includes.h" -#include "common/android/ucontext_constants.h" - -template <int left, int right> -struct CompileAssertEquals { - // a compilation error here indicates left and right are not equal. - char left_too_large[right - left]; - // a compilation error here indicates left and right are not equal. - char right_too_large[left - right]; -}; - -#define COMPILE_ASSERT_EQ(left, right, tag) \ - CompileAssertEquals<left, right> tag; - -TEST(AndroidUContext, GRegsOffset) { -#if defined(__arm__) - // There is no gregs[] array on ARM, so compare to the offset of - // first register fields, since they're stored in order. - ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.arm_r0)); -#elif defined(__aarch64__) - // There is no gregs[] array on ARM, so compare to the offset of - // first register fields, since they're stored in order. - ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.regs[0])); - ASSERT_EQ(static_cast<size_t>(MCONTEXT_SP_OFFSET), - offsetof(ucontext_t,uc_mcontext.sp)); - ASSERT_EQ(static_cast<size_t>(MCONTEXT_PC_OFFSET), - offsetof(ucontext_t,uc_mcontext.pc)); - ASSERT_EQ(static_cast<size_t>(MCONTEXT_PSTATE_OFFSET), - offsetof(ucontext_t,uc_mcontext.pstate)); - ASSERT_EQ(static_cast<size_t>(MCONTEXT_EXTENSION_OFFSET), - offsetof(ucontext_t,uc_mcontext.__reserved)); -#elif defined(__i386__) - ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.gregs)); -#define CHECK_REG(x) \ - ASSERT_EQ(static_cast<size_t>(MCONTEXT_##x##_OFFSET), \ - offsetof(ucontext_t,uc_mcontext.gregs[REG_##x])) - CHECK_REG(GS); - CHECK_REG(FS); - CHECK_REG(ES); - CHECK_REG(DS); - CHECK_REG(EDI); - CHECK_REG(ESI); - CHECK_REG(EBP); - CHECK_REG(ESP); - CHECK_REG(EBX); - CHECK_REG(EDX); - CHECK_REG(ECX); - CHECK_REG(EAX); - CHECK_REG(TRAPNO); - CHECK_REG(ERR); - CHECK_REG(EIP); - CHECK_REG(CS); - CHECK_REG(EFL); - CHECK_REG(UESP); - CHECK_REG(SS); - - ASSERT_EQ(static_cast<size_t>(UCONTEXT_FPREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.fpregs)); - - ASSERT_EQ(static_cast<size_t>(UCONTEXT_FPREGS_MEM_OFFSET), - offsetof(ucontext_t,__fpregs_mem)); -#elif defined(__mips__) - ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.gregs)); - - // PC for mips is not part of gregs. - ASSERT_EQ(static_cast<size_t>(MCONTEXT_PC_OFFSET), - offsetof(ucontext_t,uc_mcontext.pc)); - - ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.fpregs)); - - ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPC_CSR), - offsetof(ucontext_t,uc_mcontext.fpc_csr)); -#elif defined(__x86_64__) - - COMPILE_ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.gregs), - mcontext_gregs_offset); -#define CHECK_REG(x) \ - COMPILE_ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_##x), \ - offsetof(ucontext_t,uc_mcontext.gregs[REG_##x]), reg_##x) - CHECK_REG(R8); - CHECK_REG(R9); - CHECK_REG(R10); - CHECK_REG(R11); - CHECK_REG(R12); - CHECK_REG(R13); - CHECK_REG(R14); - CHECK_REG(R15); - CHECK_REG(RDI); - CHECK_REG(RSI); - CHECK_REG(RBP); - CHECK_REG(RBX); - CHECK_REG(RDX); - CHECK_REG(RAX); - CHECK_REG(RCX); - CHECK_REG(RSP); - CHECK_REG(RIP); - - // sigcontext is an analog to mcontext_t. The layout should be the same. - COMPILE_ASSERT_EQ(offsetof(mcontext_t,fpregs), - offsetof(sigcontext,fpstate), sigcontext_fpstate); - // Check that _fpstate from asm/sigcontext.h is essentially the same - // as _libc_fpstate. - COMPILE_ASSERT_EQ(sizeof(_libc_fpstate), sizeof(_fpstate), - sigcontext_fpstate_size); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,cwd),offsetof(_fpstate,cwd), - sigcontext_fpstate_cwd); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,swd),offsetof(_fpstate,swd), - sigcontext_fpstate_swd); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,ftw),offsetof(_fpstate,twd), - sigcontext_fpstate_twd); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,fop),offsetof(_fpstate,fop), - sigcontext_fpstate_fop); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,rip),offsetof(_fpstate,rip), - sigcontext_fpstate_rip); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,rdp),offsetof(_fpstate,rdp), - sigcontext_fpstate_rdp); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,mxcsr),offsetof(_fpstate,mxcsr), - sigcontext_fpstate_mxcsr); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,mxcr_mask), - offsetof(_fpstate,mxcsr_mask), - sigcontext_fpstate_mxcsr_mask); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,_st), offsetof(_fpstate,st_space), - sigcontext_fpstate_stspace); - COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,_xmm), offsetof(_fpstate,xmm_space), - sigcontext_fpstate_xmm_space); - - COMPILE_ASSERT_EQ(MCONTEXT_FPREGS_PTR, - offsetof(ucontext_t,uc_mcontext.fpregs), - mcontext_fpregs_ptr); - COMPILE_ASSERT_EQ(MCONTEXT_FPREGS_MEM, offsetof(ucontext_t,__fpregs_mem), - mcontext_fpregs_mem); - COMPILE_ASSERT_EQ(FPREGS_OFFSET_MXCSR, offsetof(_libc_fpstate,mxcsr), - fpregs_offset_mxcsr); - COMPILE_ASSERT_EQ(UCONTEXT_SIGMASK_OFFSET, offsetof(ucontext_t, uc_sigmask), - ucontext_sigmask); -#else - ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET), - offsetof(ucontext_t,uc_mcontext.gregs)); -#endif -} - -TEST(AndroidUContext, SigmakOffset) { - ASSERT_EQ(static_cast<size_t>(UCONTEXT_SIGMASK_OFFSET), - offsetof(ucontext_t,uc_sigmask)); -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/elf.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/elf.h deleted file mode 100644 index b2a28df44..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/include/elf.h +++ /dev/null @@ -1,168 +0,0 @@ -// 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_ANDROID_INCLUDE_ELF_H -#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ELF_H - -#include <stdint.h> -#include <libgen.h> - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -// The Android <elf.h> provides BSD-based definitions for the ElfXX_Nhdr -// types -// always source-compatible with the GLibc/kernel ones. To overcome this -// issue without modifying a lot of code in Breakpad, use an ugly macro -// renaming trick with #include_next - -// Avoid conflict with BSD-based definition of ElfXX_Nhdr. -// Unfortunately, their field member names do not use a 'n_' prefix. -#define Elf32_Nhdr __bsd_Elf32_Nhdr -#define Elf64_Nhdr __bsd_Elf64_Nhdr - -// In case they are defined by the NDK version -#define Elf32_auxv_t __bionic_Elf32_auxv_t -#define Elf64_auxv_t __bionic_Elf64_auxv_t - -#define Elf32_Dyn __bionic_Elf32_Dyn -#define Elf64_Dyn __bionic_Elf64_Dyn - -#include_next <elf.h> - -#undef Elf32_Nhdr -#undef Elf64_Nhdr - -typedef struct { - Elf32_Word n_namesz; - Elf32_Word n_descsz; - Elf32_Word n_type; -} Elf32_Nhdr; - -typedef struct { - Elf64_Word n_namesz; - Elf64_Word n_descsz; - Elf64_Word n_type; -} Elf64_Nhdr; - -#undef Elf32_auxv_t -#undef Elf64_auxv_t - -typedef struct { - uint32_t a_type; - union { - uint32_t a_val; - } a_un; -} Elf32_auxv_t; - -typedef struct { - uint64_t a_type; - union { - uint64_t a_val; - } a_un; -} Elf64_auxv_t; - -#undef Elf32_Dyn -#undef Elf64_Dyn - -typedef struct { - Elf32_Sword d_tag; - union { - Elf32_Word d_val; - Elf32_Addr d_ptr; - } d_un; -} Elf32_Dyn; - -typedef struct { - Elf64_Sxword d_tag; - union { - Elf64_Xword d_val; - Elf64_Addr d_ptr; - } d_un; -} Elf64_Dyn; - - -// __WORDSIZE is GLibc-specific and used by Google Breakpad on Linux. -#ifndef __WORDSIZE -#if defined(__i386__) || defined(__ARM_EABI__) || defined(__mips__) -#define __WORDSIZE 32 -#elif defined(__x86_64__) || defined(__aarch64__) -#define __WORDSIZE 64 -#else -#error "Unsupported Android CPU ABI" -#endif -#endif - -// The Android headers don't always define this constant. -#ifndef EM_X86_64 -#define EM_X86_64 62 -#endif - -#ifndef EM_PPC64 -#define EM_PPC64 21 -#endif - -#ifndef EM_S390 -#define EM_S390 22 -#endif - -#if !defined(AT_SYSINFO_EHDR) -#define AT_SYSINFO_EHDR 33 -#endif - -#if !defined(NT_PRSTATUS) -#define NT_PRSTATUS 1 -#endif - -#if !defined(NT_PRPSINFO) -#define NT_PRPSINFO 3 -#endif - -#if !defined(NT_AUXV) -#define NT_AUXV 6 -#endif - -#if !defined(NT_PRXFPREG) -#define NT_PRXFPREG 0x46e62b7f -#endif - -#if !defined(NT_FPREGSET) -#define NT_FPREGSET 2 -#endif - -#if !defined(SHT_MIPS_DWARF) -#define SHT_MIPS_DWARF 0x7000001e -#endif - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ELF_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/link.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/link.h deleted file mode 100644 index 0f7d98e75..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/include/link.h +++ /dev/null @@ -1,73 +0,0 @@ -// 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_ANDROID_INCLUDE_LINK_H -#define GOOGLE_BREAKPAD_ANDROID_INCLUDE_LINK_H - -/* Android doesn't provide all the data-structures required in its <link.h>. - Provide custom version here. */ -#include_next <link.h> - -// TODO(rmcilroy): Remove this file once the ndk is updated for other -// architectures - crbug.com/358831 -#if !defined(__aarch64__) && !defined(__x86_64__) && \ - !(defined(__mips__) && _MIPS_SIM == _ABI64) - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -#if defined(ANDROID) && ANDROID_VERSION <= 20 -struct r_debug { - int r_version; - struct link_map* r_map; - ElfW(Addr) r_brk; - enum { - RT_CONSISTENT, - RT_ADD, - RT_DELETE } r_state; - ElfW(Addr) r_ldbase; -}; - -struct link_map { - ElfW(Addr) l_addr; - char* l_name; - ElfW(Dyn)* l_ld; - struct link_map* l_next; - struct link_map* l_prev; -}; -#endif - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // !defined(__aarch64__) && !defined(__x86_64__) - -#endif /* GOOGLE_BREAKPAD_ANDROID_INCLUDE_LINK_H */ diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/sgidefs.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/sgidefs.h deleted file mode 100644 index 33796dcf7..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/include/sgidefs.h +++ /dev/null @@ -1,41 +0,0 @@ -// 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. - -#ifndef GOOGLE_BREAKPAD_ANDROID_INCLUDE_SGIDEFS_H -#define GOOGLE_BREAKPAD_ANDROID_INCLUDE_SGIDEFS_H - -#ifdef __mips__ - -// Android doesn't contain sgidefs.h, but does have <asm/sgidefs.h> which -// contains what we need. -#include <asm/sgidefs.h> - -#endif // __mips__ - -#endif // GOOGLE_BREAKPAD_ANDROID_INCLUDE_SGIDEFS_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/stab.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/stab.h deleted file mode 100644 index cd9290215..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/include/stab.h +++ /dev/null @@ -1,100 +0,0 @@ -// 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_ANDROID_INCLUDE_STAB_H -#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_STAB_H - -#include <sys/cdefs.h> - -#ifdef __BIONIC_HAVE_STAB_H -#include <stab.h> -#else - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -#define _STAB_CODE_LIST \ - _STAB_CODE_DEF(UNDF,0x00) \ - _STAB_CODE_DEF(GSYM,0x20) \ - _STAB_CODE_DEF(FNAME,0x22) \ - _STAB_CODE_DEF(FUN,0x24) \ - _STAB_CODE_DEF(STSYM,0x26) \ - _STAB_CODE_DEF(LCSYM,0x28) \ - _STAB_CODE_DEF(MAIN,0x2a) \ - _STAB_CODE_DEF(PC,0x30) \ - _STAB_CODE_DEF(NSYMS,0x32) \ - _STAB_CODE_DEF(NOMAP,0x34) \ - _STAB_CODE_DEF(OBJ,0x38) \ - _STAB_CODE_DEF(OPT,0x3c) \ - _STAB_CODE_DEF(RSYM,0x40) \ - _STAB_CODE_DEF(M2C,0x42) \ - _STAB_CODE_DEF(SLINE,0x44) \ - _STAB_CODE_DEF(DSLINE,0x46) \ - _STAB_CODE_DEF(BSLINE,0x48) \ - _STAB_CODE_DEF(BROWS,0x48) \ - _STAB_CODE_DEF(DEFD,0x4a) \ - _STAB_CODE_DEF(EHDECL,0x50) \ - _STAB_CODE_DEF(MOD2,0x50) \ - _STAB_CODE_DEF(CATCH,0x54) \ - _STAB_CODE_DEF(SSYM,0x60) \ - _STAB_CODE_DEF(SO,0x64) \ - _STAB_CODE_DEF(LSYM,0x80) \ - _STAB_CODE_DEF(BINCL,0x82) \ - _STAB_CODE_DEF(SOL,0x84) \ - _STAB_CODE_DEF(PSYM,0xa0) \ - _STAB_CODE_DEF(EINCL,0xa2) \ - _STAB_CODE_DEF(ENTRY,0xa4) \ - _STAB_CODE_DEF(LBRAC,0xc0) \ - _STAB_CODE_DEF(EXCL,0xc2) \ - _STAB_CODE_DEF(SCOPE,0xc4) \ - _STAB_CODE_DEF(RBRAC,0xe0) \ - _STAB_CODE_DEF(BCOMM,0xe2) \ - _STAB_CODE_DEF(ECOMM,0xe4) \ - _STAB_CODE_DEF(ECOML,0xe8) \ - _STAB_CODE_DEF(NBTEXT,0xf0) \ - _STAB_CODE_DEF(NBDATA,0xf2) \ - _STAB_CODE_DEF(NBBSS,0xf4) \ - _STAB_CODE_DEF(NBSTS,0xf6) \ - _STAB_CODE_DEF(NBLCS,0xf8) \ - _STAB_CODE_DEF(LENG,0xfe) - -enum __stab_debug_code { -#define _STAB_CODE_DEF(x,y) N_##x = y, -_STAB_CODE_LIST -#undef _STAB_CODE_DEF -}; - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // __BIONIC_HAVE_STAB_H - -#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_STAB_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/procfs.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/procfs.h deleted file mode 100644 index 185124364..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/procfs.h +++ /dev/null @@ -1,124 +0,0 @@ -// 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_ANDROID_SYS_PROCFS_H -#define GOOGLE_BREAKPAD_COMMON_ANDROID_SYS_PROCFS_H - -#ifdef __BIONIC_HAVE_SYS_PROCFS_H - -#include_next <sys/procfs.h> - -#else - -#include <asm/ptrace.h> -#include <sys/cdefs.h> -#if defined (__mips__) -#include <sys/types.h> -#endif -#include <sys/user.h> -#include <unistd.h> - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -#if defined(__x86_64__) || defined(__aarch64__) -typedef unsigned long long elf_greg_t; -#else -typedef unsigned long elf_greg_t; -#endif - -#ifdef __arm__ -#define ELF_NGREG (sizeof(struct user_regs) / sizeof(elf_greg_t)) -#elif defined(__aarch64__) -#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t)) -#elif defined(__mips__) -#define ELF_NGREG 45 -#else -#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) -#endif - -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -struct elf_siginfo { - int si_signo; - int si_code; - int si_errno; -}; - -struct elf_prstatus { - struct elf_siginfo pr_info; - short pr_cursig; - unsigned long pr_sigpend; - unsigned long pr_sighold; - pid_t pr_pid; - pid_t pr_ppid; - pid_t pr_pgrp; - pid_t pd_sid; - struct timeval pr_utime; - struct timeval pr_stime; - struct timeval pr_cutime; - struct timeval pr_cstime; - elf_gregset_t pr_reg; - int pr_fpvalid; -}; - -#define ELF_PRARGSZ 80 - -struct elf_prpsinfo { - char pr_state; - char pr_sname; - char pr_zomb; - char pr_nice; - unsigned long pr_flags; -#ifdef __x86_64__ - unsigned int pr_uid; - unsigned int pr_gid; -#elif defined(__mips__) - __kernel_uid_t pr_uid; - __kernel_gid_t pr_gid; -#else - unsigned short pr_uid; - unsigned short pr_gid; -#endif - int pr_pid; - int pr_ppid; - int pr_pgrp; - int pr_sid; - char pr_fname[16]; - char pr_psargs[ELF_PRARGSZ]; -}; - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // __BIONIC_HAVE_SYS_PROCFS_H - -#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_SYS_PROCFS_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/signal.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/signal.h deleted file mode 100644 index 20c81e937..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/signal.h +++ /dev/null @@ -1,35 +0,0 @@ -// 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_ANDROID_INCLUDE_SYS_SIGNAL_H -#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_SIGNAL_H - -#include <signal.h> - -#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_SIGNAL_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/user.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/user.h deleted file mode 100644 index 1eb02a57d..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/include/sys/user.h +++ /dev/null @@ -1,85 +0,0 @@ -// 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_ANDROID_INCLUDE_SYS_USER_H -#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H - -// The purpose of this file is to glue the mismatching headers (Android NDK vs -// glibc) and therefore avoid doing otherwise awkward #ifdefs in the code. -// The following quirks are currently handled by this file: -// - i386: Use the Android NDK but alias user_fxsr_struct > user_fpxregs_struct. -// - aarch64: -// - NDK r10: Add missing user_regs_struct and user_fpsimd_struct structs. -// - NDK r11+: Add missing <stdint.h> include -// - Other platforms: Just use the Android NDK unchanged. - -// TODO(primiano): remove these changes after Chromium has stably rolled to -// an NDK with the appropriate fixes. - -#if defined(ANDROID_NDK_MAJOR_VERSION) && ANDROID_NDK_MAJOR_VERSION > 10 -#ifdef __aarch64__ -#include <stdint.h> -#endif // __aarch64__ -#endif // defined(ANDROID_NDK_MAJOR_VERSION) && ANDROID_NDK_MAJOR_VERSION > 10 - -#include_next <sys/user.h> - -#ifdef __i386__ -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus -typedef struct user_fxsr_struct user_fpxregs_struct; -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus -#endif // __i386__ - -#if !defined(ANDROID_NDK_MAJOR_VERSION) || ANDROID_NDK_MAJOR_VERSION == 10 -#ifdef __aarch64__ -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus -struct user_regs_struct { - __u64 regs[31]; - __u64 sp; - __u64 pc; - __u64 pstate; -}; -struct user_fpsimd_struct { - __uint128_t vregs[32]; - __u32 fpsr; - __u32 fpcr; -}; -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus -#endif // __aarch64__ -#endif // defined(ANDROID_NDK_VERSION) && ANDROID_NDK_MAJOR_VERSION == 10 - -#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/include/ucontext.h b/toolkit/crashreporter/google-breakpad/src/common/android/include/ucontext.h deleted file mode 100644 index 29db8adee..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/include/ucontext.h +++ /dev/null @@ -1,56 +0,0 @@ -// 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_ANDROID_INCLUDE_UCONTEXT_H -#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_UCONTEXT_H - -#include <sys/cdefs.h> - -#ifdef __BIONIC_UCONTEXT_H -#include <ucontext.h> -#else - -#include <sys/ucontext.h> - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -// Provided by src/android/common/breakpad_getcontext.S -int breakpad_getcontext(ucontext_t* ucp); - -#define getcontext(x) breakpad_getcontext(x) - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus - -#endif // __BIONIC_UCONTEXT_H - -#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_UCONTEXT_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/testing/include/wchar.h b/toolkit/crashreporter/google-breakpad/src/common/android/testing/include/wchar.h deleted file mode 100644 index 85373fd2a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/testing/include/wchar.h +++ /dev/null @@ -1,76 +0,0 @@ -// 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. - -// Android doesn't provide wcscasecmp(), so provide an alternative here. -// -// Note that this header is not needed when Breakpad is compiled against -// a recent version of Googletest. It shall be considered for removal once -// src/testing/ is updated to an appropriate revision in the future. - -#ifndef GOOGLEBREAKPAD_COMMON_ANDROID_INCLUDE_WCHAR_H -#define GOOGLEBREAKPAD_COMMON_ANDROID_INCLUDE_WCHAR_H - -#include_next <wchar.h> - -#if !defined(__aarch64__) && !defined(__x86_64__) && \ - !(defined(__mips__) && _MIPS_SIM == _ABI64) - -// This needs to be in an extern "C" namespace, or Googletest will not -// compile against it. -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -static wchar_t inline wcstolower(wchar_t ch) { - if (ch >= L'a' && ch <= L'A') - ch -= L'a' - L'A'; - return ch; -} - -static int inline wcscasecmp(const wchar_t* s1, const wchar_t* s2) { - for (;;) { - wchar_t c1 = wcstolower(*s1); - wchar_t c2 = wcstolower(*s2); - if (c1 < c2) - return -1; - if (c1 > c2) - return 1; - if (c1 == L'0') - return 0; - s1++; - s2++; - } -} - -#ifdef __cplusplus -} // extern "C" -#endif // __cplusplus -#endif - -#endif // GOOGLEBREAKPAD_COMMON_ANDROID_INCLUDE_WCHAR_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/testing/mkdtemp.h b/toolkit/crashreporter/google-breakpad/src/common/android/testing/mkdtemp.h deleted file mode 100644 index b86e2cd78..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/testing/mkdtemp.h +++ /dev/null @@ -1,110 +0,0 @@ -// 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. - -// mkdtemp() wasn't declared in <stdlib.h> until NDK r9b due to a simple -// packaging bug (the function has always been implemented in all versions -// of the C library). This header is provided to build Breakpad with earlier -// NDK revisions (e.g. the one used by Chromium). It may be removed in the -// future once all major projects upgrade to use a more recent NDK. -// -// The reason this is inlined here is to avoid linking a new object file -// into each unit test program (i.e. keep build files simple). - -#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_MKDTEMP_H -#define GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_MKDTEMP_H - -#include <assert.h> -#include <errno.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> - -// Using a macro renaming trick here is necessary when building against -// NDK r9b. Otherwise the compiler will complain that calls to mkdtemp() -// are ambiguous. -#define mkdtemp breakpad_mkdtemp - -namespace { - -char* breakpad_mkdtemp(char* path) { - if (path == NULL) { - errno = EINVAL; - return NULL; - } - - // 'path' must be terminated with six 'X' - const char kSuffix[] = "XXXXXX"; - const size_t kSuffixLen = strlen(kSuffix); - char* path_end = path + strlen(path); - - if (static_cast<size_t>(path_end - path) < kSuffixLen || - memcmp(path_end - kSuffixLen, kSuffix, kSuffixLen) != 0) { - errno = EINVAL; - return NULL; - } - - // If 'path' contains a directory separator, check that it exists to - // avoid looping later. - char* sep = strrchr(path, '/'); - if (sep != NULL) { - struct stat st; - int ret; - *sep = '\0'; // temporarily zero-terminate the dirname. - ret = stat(path, &st); - *sep = '/'; // restore full path. - if (ret < 0) - return NULL; - if (!S_ISDIR(st.st_mode)) { - errno = ENOTDIR; - return NULL; - } - } - - // Loop. On each iteration, replace the XXXXXX suffix with a random - // number. - int tries; - for (tries = 128; tries > 0; tries--) { - int random = rand() % 1000000; - - snprintf(path_end - kSuffixLen, kSuffixLen + 1, "%0d", random); - if (mkdir(path, 0700) == 0) - return path; // Success - - if (errno != EEXIST) - return NULL; - } - - assert(errno == EEXIST); - return NULL; -} - -} // namespace - -#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_MKDTEMP_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/testing/pthread_fixes.h b/toolkit/crashreporter/google-breakpad/src/common/android/testing/pthread_fixes.h deleted file mode 100644 index 15c6309ec..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/testing/pthread_fixes.h +++ /dev/null @@ -1,99 +0,0 @@ -// 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 contains Pthread-related functions not provided by the Android NDK -// but required by the Breakpad unit test. The functions are inlined here -// in a C++ anonymous namespace in order to keep the build files simples. - -#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H -#define GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H - -#include <pthread.h> - -namespace { - -// Android doesn't provide pthread_barrier_t for now. -#ifndef PTHREAD_BARRIER_SERIAL_THREAD - -// Anything except 0 will do here. -#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 - -typedef struct { - pthread_mutex_t mutex; - pthread_cond_t cond; - unsigned count; -} pthread_barrier_t; - -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* /* barrier_attr */, - unsigned count) { - barrier->count = count; - pthread_mutex_init(&barrier->mutex, NULL); - pthread_cond_init(&barrier->cond, NULL); - return 0; -} - -int pthread_barrier_wait(pthread_barrier_t* barrier) { - // Lock the mutex - pthread_mutex_lock(&barrier->mutex); - // Decrement the count. If this is the first thread to reach 0, wake up - // waiters, unlock the mutex, then return PTHREAD_BARRIER_SERIAL_THREAD. - if (--barrier->count == 0) { - // First thread to reach the barrier - pthread_cond_broadcast(&barrier->cond); - pthread_mutex_unlock(&barrier->mutex); - return PTHREAD_BARRIER_SERIAL_THREAD; - } - // Otherwise, wait for other threads until the count reaches 0, then - // return 0 to indicate this is not the first thread. - do { - pthread_cond_wait(&barrier->cond, &barrier->mutex); - } while (barrier->count > 0); - - pthread_mutex_unlock(&barrier->mutex); - return 0; -} - -int pthread_barrier_destroy(pthread_barrier_t *barrier) { - barrier->count = 0; - pthread_cond_destroy(&barrier->cond); - pthread_mutex_destroy(&barrier->mutex); - return 0; -} - -#endif // defined(PTHREAD_BARRIER_SERIAL_THREAD) - -int pthread_yield(void) { - sched_yield(); - return 0; -} - -} // namespace - -#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/android/ucontext_constants.h b/toolkit/crashreporter/google-breakpad/src/common/android/ucontext_constants.h deleted file mode 100644 index 1932d5739..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/android/ucontext_constants.h +++ /dev/null @@ -1,144 +0,0 @@ -// 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 -// src/common/android/include/sys/ucontext.h -// -// Used by src/common/android/breakpad_getcontext.S -// Tested by src/common/android/testing/breakpad_getcontext_unittest.cc - -#ifndef GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H -#define GOOGLEBREAKPAD_COMMON_ANDROID_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 -#define UCONTEXT_FPREGS_MEM_OFFSET 116 - -#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 -#define MCONTEXT_FPREGS_MEM 304 -#define FPREGS_OFFSET_MXCSR 24 - -#else -#error "This header has not been ported for your CPU" -#endif - -#endif // GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc deleted file mode 100644 index 2d1ed983d..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.cc +++ /dev/null @@ -1,487 +0,0 @@ - -/* libunwind - a platform-independent unwind library - Copyright 2011 Linaro Limited - -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. */ - -// 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. - - -// Derived from libunwind, with extensive modifications. - - -#include "common/arm_ex_reader.h" - -#include <assert.h> -#include <stdio.h> - -// This file, in conjunction with arm_ex_to_module.cc, translates -// EXIDX unwind information into the same format that Breakpad uses -// for CFI information. Hence Breakpad's CFI unwinding abilities -// also become usable for EXIDX. -// -// See: "Exception Handling ABI for the ARM Architecture", ARM IHI 0038A -// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038a/IHI0038A_ehabi.pdf - -// EXIDX data is presented in two parts: -// -// * an index table. This contains two words per routine, -// the first of which identifies the routine, and the second -// of which is a reference to the unwind bytecode. If the -// bytecode is very compact -- 3 bytes or less -- it can be -// stored directly in the second word. -// -// * an area containing the unwind bytecodes. - -// General flow is: ExceptionTableInfo::Start iterates over all -// of the index table entries (pairs). For each entry, it: -// -// * calls ExceptionTableInfo::ExtabEntryExtract to copy the bytecode -// out into an intermediate buffer. - -// * uses ExceptionTableInfo::ExtabEntryDecode to parse the intermediate -// buffer. Each bytecode instruction is bundled into a -// arm_ex_to_module::extab_data structure, and handed to .. -// -// * .. ARMExToModule::ImproveStackFrame, which in turn hands it to -// ARMExToModule::TranslateCmd, and that generates the pseudo-CFI -// records that Breakpad stores. - -#define ARM_EXIDX_CANT_UNWIND 0x00000001 -#define ARM_EXIDX_COMPACT 0x80000000 -#define ARM_EXTBL_OP_FINISH 0xb0 -#define ARM_EXIDX_TABLE_LIMIT (255*4) - -namespace arm_ex_reader { - -using arm_ex_to_module::ARM_EXIDX_CMD_FINISH; -using arm_ex_to_module::ARM_EXIDX_CMD_SUB_FROM_VSP; -using arm_ex_to_module::ARM_EXIDX_CMD_ADD_TO_VSP; -using arm_ex_to_module::ARM_EXIDX_CMD_REG_POP; -using arm_ex_to_module::ARM_EXIDX_CMD_REG_TO_SP; -using arm_ex_to_module::ARM_EXIDX_CMD_VFP_POP; -using arm_ex_to_module::ARM_EXIDX_CMD_WREG_POP; -using arm_ex_to_module::ARM_EXIDX_CMD_WCGR_POP; -using arm_ex_to_module::ARM_EXIDX_CMD_RESERVED; -using arm_ex_to_module::ARM_EXIDX_CMD_REFUSED; -using arm_ex_to_module::exidx_entry; -using arm_ex_to_module::ARM_EXIDX_VFP_SHIFT_16; -using arm_ex_to_module::ARM_EXIDX_VFP_FSTMD; -using google_breakpad::MemoryRange; - - -static void* Prel31ToAddr(const void* addr) { - uint32_t offset32 = *reinterpret_cast<const uint32_t*>(addr); - // sign extend offset32[30:0] to 64 bits -- copy bit 30 to positions - // 63:31 inclusive. - uint64_t offset64 = offset32; - if (offset64 & (1ULL << 30)) - offset64 |= 0xFFFFFFFF80000000ULL; - else - offset64 &= 0x000000007FFFFFFFULL; - return ((char*)addr) + (uintptr_t)offset64; -} - - -// Extract unwind bytecode for the function denoted by |entry| into |buf|, -// and return the number of bytes of |buf| written, along with a code -// indicating the outcome. - -ExceptionTableInfo::ExExtractResult ExceptionTableInfo::ExtabEntryExtract( - const struct exidx_entry* entry, - uint8_t* buf, size_t buf_size, - size_t* buf_used) { - MemoryRange mr_out(buf, buf_size); - - *buf_used = 0; - -# define PUT_BUF_U8(_byte) \ - do { if (!mr_out.Covers(*buf_used, 1)) return ExOutBufOverflow; \ - buf[(*buf_used)++] = (_byte); } while (0) - -# define GET_EX_U32(_lval, _addr, _sec_mr) \ - do { if (!(_sec_mr).Covers(reinterpret_cast<const uint8_t*>(_addr) \ - - (_sec_mr).data(), 4)) \ - return ExInBufOverflow; \ - (_lval) = *(reinterpret_cast<const uint32_t*>(_addr)); } while (0) - -# define GET_EXIDX_U32(_lval, _addr) \ - GET_EX_U32(_lval, _addr, mr_exidx_) -# define GET_EXTAB_U32(_lval, _addr) \ - GET_EX_U32(_lval, _addr, mr_extab_) - - uint32_t data; - GET_EXIDX_U32(data, &entry->data); - - // A function can be marked CANT_UNWIND if (eg) it is known to be - // at the bottom of the stack. - if (data == ARM_EXIDX_CANT_UNWIND) - return ExCantUnwind; - - uint32_t pers; // personality number - uint32_t extra; // number of extra data words required - uint32_t extra_allowed; // number of extra data words allowed - uint32_t* extbl_data; // the handler entry, if not inlined - - if (data & ARM_EXIDX_COMPACT) { - // The handler table entry has been inlined into the index table entry. - // In this case it can only be an ARM-defined compact model, since - // bit 31 is 1. Only personalities 0, 1 and 2 are defined for the - // ARM compact model, but 1 and 2 are "Long format" and may require - // extra data words. Hence the allowable personalities here are: - // personality 0, in which case 'extra' has no meaning - // personality 1, with zero extra words - // personality 2, with zero extra words - extbl_data = NULL; - pers = (data >> 24) & 0x0F; - extra = (data >> 16) & 0xFF; - extra_allowed = 0; - } - else { - // The index table entry is a pointer to the handler entry. Note - // that Prel31ToAddr will read the given address, but we already - // range-checked above. - extbl_data = reinterpret_cast<uint32_t*>(Prel31ToAddr(&entry->data)); - GET_EXTAB_U32(data, extbl_data); - if (!(data & ARM_EXIDX_COMPACT)) { - // This denotes a "generic model" handler. That will involve - // executing arbitary machine code, which is something we - // can't represent here; hence reject it. - return ExCantRepresent; - } - // So we have a compact model representation. Again, 3 possible - // personalities, but this time up to 255 allowable extra words. - pers = (data >> 24) & 0x0F; - extra = (data >> 16) & 0xFF; - extra_allowed = 255; - extbl_data++; - } - - // Now look at the the handler table entry. The first word is - // |data| and subsequent words start at |*extbl_data|. The number - // of extra words to use is |extra|, provided that the personality - // allows extra words. Even if it does, none may be available -- - // extra_allowed is the maximum number of extra words allowed. */ - if (pers == 0) { - // "Su16" in the documentation -- 3 unwinding insn bytes - // |extra| has no meaning here; instead that byte is an unwind-info byte - PUT_BUF_U8(data >> 16); - PUT_BUF_U8(data >> 8); - PUT_BUF_U8(data); - } - else if ((pers == 1 || pers == 2) && extra <= extra_allowed) { - // "Lu16" or "Lu32" respectively -- 2 unwinding insn bytes, - // and up to 255 extra words. - PUT_BUF_U8(data >> 8); - PUT_BUF_U8(data); - for (uint32_t j = 0; j < extra; j++) { - GET_EXTAB_U32(data, extbl_data); - extbl_data++; - PUT_BUF_U8(data >> 24); - PUT_BUF_U8(data >> 16); - PUT_BUF_U8(data >> 8); - PUT_BUF_U8(data >> 0); - } - } - else { - // The entry is invalid. - return ExInvalid; - } - - // Make sure the entry is terminated with "FINISH" - if (*buf_used > 0 && buf[(*buf_used) - 1] != ARM_EXTBL_OP_FINISH) - PUT_BUF_U8(ARM_EXTBL_OP_FINISH); - - return ExSuccess; - -# undef GET_EXTAB_U32 -# undef GET_EXIDX_U32 -# undef GET_U32 -# undef PUT_BUF_U8 -} - - -// Take the unwind information extracted by ExtabEntryExtract -// and parse it into frame-unwind instructions. These are as -// specified in "Table 4, ARM-defined frame-unwinding instructions" -// in the specification document detailed in comments at the top -// of this file. -// -// This reads from |buf[0, +data_size)|. It checks for overruns of -// the input buffer and returns a negative value if that happens, or -// for any other failure cases. It returns zero in case of success. -int ExceptionTableInfo::ExtabEntryDecode(const uint8_t* buf, size_t buf_size) { - if (buf == NULL || buf_size == 0) - return -1; - - MemoryRange mr_in(buf, buf_size); - const uint8_t* buf_initially = buf; - -# define GET_BUF_U8(_lval) \ - do { if (!mr_in.Covers(buf - buf_initially, 1)) return -1; \ - (_lval) = *(buf++); } while (0) - - const uint8_t* end = buf + buf_size; - - while (buf < end) { - struct arm_ex_to_module::extab_data edata; - memset(&edata, 0, sizeof(edata)); - - uint8_t op; - GET_BUF_U8(op); - if ((op & 0xc0) == 0x00) { - // vsp = vsp + (xxxxxx << 2) + 4 - edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP; - edata.data = (((int)op & 0x3f) << 2) + 4; - } else if ((op & 0xc0) == 0x40) { - // vsp = vsp - (xxxxxx << 2) - 4 - edata.cmd = ARM_EXIDX_CMD_SUB_FROM_VSP; - edata.data = (((int)op & 0x3f) << 2) + 4; - } else if ((op & 0xf0) == 0x80) { - uint8_t op2; - GET_BUF_U8(op2); - if (op == 0x80 && op2 == 0x00) { - // Refuse to unwind - edata.cmd = ARM_EXIDX_CMD_REFUSED; - } else { - // Pop up to 12 integer registers under masks {r15-r12},{r11-r4} - edata.cmd = ARM_EXIDX_CMD_REG_POP; - edata.data = ((op & 0xf) << 8) | op2; - edata.data = edata.data << 4; - } - } else if ((op & 0xf0) == 0x90) { - if (op == 0x9d || op == 0x9f) { - // 9d: Reserved as prefix for ARM register to register moves - // 9f: Reserved as perfix for Intel Wireless MMX reg to reg moves - edata.cmd = ARM_EXIDX_CMD_RESERVED; - } else { - // Set vsp = r[nnnn] - edata.cmd = ARM_EXIDX_CMD_REG_TO_SP; - edata.data = op & 0x0f; - } - } else if ((op & 0xf0) == 0xa0) { - // Pop r4 to r[4+nnn], or - // Pop r4 to r[4+nnn] and r14 or - unsigned end = (op & 0x07); - edata.data = (1 << (end + 1)) - 1; - edata.data = edata.data << 4; - if (op & 0x08) edata.data |= 1 << 14; - edata.cmd = ARM_EXIDX_CMD_REG_POP; - } else if (op == ARM_EXTBL_OP_FINISH) { - // Finish - edata.cmd = ARM_EXIDX_CMD_FINISH; - buf = end; - } else if (op == 0xb1) { - uint8_t op2; - GET_BUF_U8(op2); - if (op2 == 0 || (op2 & 0xf0)) { - // Spare - edata.cmd = ARM_EXIDX_CMD_RESERVED; - } else { - // Pop integer registers under mask {r3,r2,r1,r0} - edata.cmd = ARM_EXIDX_CMD_REG_POP; - edata.data = op2 & 0x0f; - } - } else if (op == 0xb2) { - // vsp = vsp + 0x204 + (uleb128 << 2) - uint64_t offset = 0; - uint8_t byte, shift = 0; - do { - GET_BUF_U8(byte); - offset |= (byte & 0x7f) << shift; - shift += 7; - } while ((byte & 0x80) && buf < end); - edata.data = offset * 4 + 0x204; - edata.cmd = ARM_EXIDX_CMD_ADD_TO_VSP; - } else if (op == 0xb3 || op == 0xc8 || op == 0xc9) { - // b3: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDX-ishly - // c8: Pop VFP regs D[16+ssss] to D[16+ssss+cccc], FSTMFDD-ishly - // c9: Pop VFP regs D[ssss] to D[ssss+cccc], FSTMFDD-ishly - edata.cmd = ARM_EXIDX_CMD_VFP_POP; - GET_BUF_U8(edata.data); - if (op == 0xc8) edata.data |= ARM_EXIDX_VFP_SHIFT_16; - if (op != 0xb3) edata.data |= ARM_EXIDX_VFP_FSTMD; - } else if ((op & 0xf8) == 0xb8 || (op & 0xf8) == 0xd0) { - // b8: Pop VFP regs D[8] to D[8+nnn], FSTMFDX-ishly - // d0: Pop VFP regs D[8] to D[8+nnn], FSTMFDD-ishly - edata.cmd = ARM_EXIDX_CMD_VFP_POP; - edata.data = 0x80 | (op & 0x07); - if ((op & 0xf8) == 0xd0) edata.data |= ARM_EXIDX_VFP_FSTMD; - } else if (op >= 0xc0 && op <= 0xc5) { - // Intel Wireless MMX pop wR[10]-wr[10+nnn], nnn != 6,7 - edata.cmd = ARM_EXIDX_CMD_WREG_POP; - edata.data = 0xa0 | (op & 0x07); - } else if (op == 0xc6) { - // Intel Wireless MMX pop wR[ssss] to wR[ssss+cccc] - edata.cmd = ARM_EXIDX_CMD_WREG_POP; - GET_BUF_U8(edata.data); - } else if (op == 0xc7) { - uint8_t op2; - GET_BUF_U8(op2); - if (op2 == 0 || (op2 & 0xf0)) { - // Spare - edata.cmd = ARM_EXIDX_CMD_RESERVED; - } else { - // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0} - edata.cmd = ARM_EXIDX_CMD_WCGR_POP; - edata.data = op2 & 0x0f; - } - } else { - // Spare - edata.cmd = ARM_EXIDX_CMD_RESERVED; - } - - int ret = handler_->ImproveStackFrame(&edata); - if (ret < 0) - return ret; - } - return 0; - -# undef GET_BUF_U8 -} - -void ExceptionTableInfo::Start() { - const struct exidx_entry* start - = reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data()); - const struct exidx_entry* end - = reinterpret_cast<const struct exidx_entry*>(mr_exidx_.data() - + mr_exidx_.length()); - - // Iterate over each of the EXIDX entries (pairs of 32-bit words). - // These occupy the entire .exidx section. - for (const struct exidx_entry* entry = start; entry < end; ++entry) { - // Figure out the code address range that this table entry is - // associated with. - uint32_t addr = (reinterpret_cast<char*>(Prel31ToAddr(&entry->addr)) - - mapping_addr_ + loading_addr_) & 0x7fffffff; - uint32_t next_addr; - if (entry < end - 1) { - next_addr = (reinterpret_cast<char*>(Prel31ToAddr(&((entry + 1)->addr))) - - mapping_addr_ + loading_addr_) & 0x7fffffff; - } else { - // This is the last EXIDX entry in the sequence, so we don't - // have an address for the start of the next function, to limit - // this one. Instead use the address of the last byte of the - // text section associated with this .exidx section, that we - // have been given. So as to avoid junking up the CFI unwind - // tables with absurdly large address ranges in the case where - // text_last_svma_ is wrong, only use the value if it is nonzero - // and within one page of |addr|. Otherwise assume a length of 1. - // - // In some cases, gcc has been observed to finish the exidx - // section with an entry of length 1 marked CANT_UNWIND, - // presumably exactly for the purpose of giving a definite - // length for the last real entry, without having to look at - // text segment boundaries. - bool plausible = false; - next_addr = addr + 1; - if (text_last_svma_ != 0) { - uint32_t maybe_next_addr = text_last_svma_ + 1; - if (maybe_next_addr > addr && maybe_next_addr - addr <= 4096) { - next_addr = maybe_next_addr; - plausible = true; - } - } - if (!plausible) { - fprintf(stderr, "ExceptionTableInfo: implausible EXIDX last entry size " - "%d, using 1 instead.", (int32_t)(text_last_svma_ - addr)); - } - } - - // Extract the unwind info into |buf|. This might fail for - // various reasons. It involves reading both the .exidx and - // .extab sections. All accesses to those sections are - // bounds-checked. - uint8_t buf[ARM_EXIDX_TABLE_LIMIT]; - size_t buf_used = 0; - ExExtractResult res = ExtabEntryExtract(entry, buf, sizeof(buf), &buf_used); - if (res != ExSuccess) { - // Couldn't extract the unwind info, for some reason. Move on. - switch (res) { - case ExInBufOverflow: - fprintf(stderr, "ExtabEntryExtract: .exidx/.extab section overrun"); - break; - case ExOutBufOverflow: - fprintf(stderr, "ExtabEntryExtract: bytecode buffer overflow"); - break; - case ExCantUnwind: - fprintf(stderr, "ExtabEntryExtract: function is marked CANT_UNWIND"); - break; - case ExCantRepresent: - fprintf(stderr, "ExtabEntryExtract: bytecode can't be represented"); - break; - case ExInvalid: - fprintf(stderr, "ExtabEntryExtract: index table entry is invalid"); - break; - default: - fprintf(stderr, "ExtabEntryExtract: unknown error: %d", (int)res); - break; - } - continue; - } - - // Finally, work through the unwind instructions in |buf| and - // create CFI entries that Breakpad can use. This can also fail. - // First, add a new stack frame entry, into which ExtabEntryDecode - // will write the CFI entries. - if (!handler_->HasStackFrame(addr, next_addr - addr)) { - handler_->AddStackFrame(addr, next_addr - addr); - int ret = ExtabEntryDecode(buf, buf_used); - if (ret < 0) { - handler_->DeleteStackFrame(); - fprintf(stderr, "ExtabEntryDecode: failed with error code: %d", ret); - continue; - } - handler_->SubmitStackFrame(); - } - - } /* iterating over .exidx */ -} - -} // namespace arm_ex_reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.h b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.h deleted file mode 100644 index 9b54e8a0b..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_reader.h +++ /dev/null @@ -1,114 +0,0 @@ -/* libunwind - a platform-independent unwind library - Copyright 2011 Linaro Limited - -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. */ - -// 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. - - -// Derived from libunwind, with extensive modifications. - -#ifndef COMMON_ARM_EX_READER_H__ -#define COMMON_ARM_EX_READER_H__ - -#include "common/arm_ex_to_module.h" -#include "common/memory_range.h" - -namespace arm_ex_reader { - -// This class is a reader for ARM unwind information -// from .ARM.exidx and .ARM.extab sections. -class ExceptionTableInfo { - public: - ExceptionTableInfo(const char* exidx, size_t exidx_size, - const char* extab, size_t extab_size, - uint32_t text_last_svma, - arm_ex_to_module::ARMExToModule* handler, - const char* mapping_addr, - uint32_t loading_addr) - : mr_exidx_(google_breakpad::MemoryRange(exidx, exidx_size)), - mr_extab_(google_breakpad::MemoryRange(extab, extab_size)), - text_last_svma_(text_last_svma), - handler_(handler), mapping_addr_(mapping_addr), - loading_addr_(loading_addr) { } - - ~ExceptionTableInfo() { } - - // Parses the entries in .ARM.exidx and possibly - // in .ARM.extab tables, reports what we find to - // arm_ex_to_module::ARMExToModule. - void Start(); - - private: - google_breakpad::MemoryRange mr_exidx_; - google_breakpad::MemoryRange mr_extab_; - uint32_t text_last_svma_; - arm_ex_to_module::ARMExToModule* handler_; - const char* mapping_addr_; - uint32_t loading_addr_; - - enum ExExtractResult { - ExSuccess, // success - ExInBufOverflow, // out-of-range while reading .exidx - ExOutBufOverflow, // output buffer is too small - ExCantUnwind, // this function is marked CANT_UNWIND - ExCantRepresent, // entry valid, but we can't represent it - ExInvalid // entry is invalid - }; - ExExtractResult - ExtabEntryExtract(const struct arm_ex_to_module::exidx_entry* entry, - uint8_t* buf, size_t buf_size, - size_t* buf_used); - - int ExtabEntryDecode(const uint8_t* buf, size_t buf_size); -}; - -} // namespace arm_ex_reader - -#endif // COMMON_ARM_EX_READER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.cc deleted file mode 100644 index c326744f6..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.cc +++ /dev/null @@ -1,209 +0,0 @@ - -/* libunwind - a platform-independent unwind library - Copyright 2011 Linaro Limited - -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. */ - -// 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. - - -// Derived from libunwind, with extensive modifications. - -#include "common/arm_ex_to_module.h" - -#include <stdio.h> -#include <assert.h> - -// For big-picture comments on how the EXIDX reader works, -// see arm_ex_reader.cc. - -#define ARM_EXBUF_START(x) (((x) >> 4) & 0x0f) -#define ARM_EXBUF_COUNT(x) ((x) & 0x0f) -#define ARM_EXBUF_END(x) (ARM_EXBUF_START(x) + ARM_EXBUF_COUNT(x)) - -using google_breakpad::Module; - -namespace arm_ex_to_module { - -static const char* const regnames[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "fps", "cpsr" -}; - -// Translate command from extab_data to command for Module. -int ARMExToModule::TranslateCmd(const struct extab_data* edata, - Module::StackFrameEntry* entry, string& vsp) { - int ret = 0; - switch (edata->cmd) { - case ARM_EXIDX_CMD_FINISH: - /* Copy LR to PC if there isn't currently a rule for PC in force. */ - if (entry->initial_rules.find("pc") - == entry->initial_rules.end()) { - if (entry->initial_rules.find("lr") - == entry->initial_rules.end()) { - entry->initial_rules["pc"] = "lr"; - } else { - entry->initial_rules["pc"] = entry->initial_rules["lr"]; - } - } - break; - case ARM_EXIDX_CMD_SUB_FROM_VSP: - { - char c[16]; - sprintf(c, " %d -", edata->data); - vsp += c; - } - break; - case ARM_EXIDX_CMD_ADD_TO_VSP: - { - char c[16]; - sprintf(c, " %d +", edata->data); - vsp += c; - } - break; - case ARM_EXIDX_CMD_REG_POP: - for (unsigned int i = 0; i < 16; i++) { - if (edata->data & (1 << i)) { - entry->initial_rules[regnames[i]] - = vsp + " ^"; - vsp += " 4 +"; - } - } - /* Set cfa in case the SP got popped. */ - if (edata->data & (1 << 13)) { - vsp = entry->initial_rules["sp"]; - } - break; - case ARM_EXIDX_CMD_REG_TO_SP: { - assert (edata->data < 16); - const char* const regname = regnames[edata->data]; - if (entry->initial_rules.find(regname) == entry->initial_rules.end()) { - entry->initial_rules["sp"] = regname; - } else { - entry->initial_rules["sp"] = entry->initial_rules[regname]; - } - vsp = entry->initial_rules["sp"]; - break; - } - case ARM_EXIDX_CMD_VFP_POP: - /* Don't recover VFP registers, but be sure to adjust the stack - pointer. */ - for (unsigned int i = ARM_EXBUF_START(edata->data); - i <= ARM_EXBUF_END(edata->data); i++) { - vsp += " 8 +"; - } - if (!(edata->data & ARM_EXIDX_VFP_FSTMD)) { - vsp += " 4 +"; - } - break; - case ARM_EXIDX_CMD_WREG_POP: - for (unsigned int i = ARM_EXBUF_START(edata->data); - i <= ARM_EXBUF_END(edata->data); i++) { - vsp += " 8 +"; - } - break; - case ARM_EXIDX_CMD_WCGR_POP: - // Pop wCGR registers under mask {wCGR3,2,1,0}, hence "i < 4" - for (unsigned int i = 0; i < 4; i++) { - if (edata->data & (1 << i)) { - vsp += " 4 +"; - } - } - break; - case ARM_EXIDX_CMD_REFUSED: - case ARM_EXIDX_CMD_RESERVED: - ret = -1; - break; - } - return ret; -} - -bool ARMExToModule::HasStackFrame(uintptr_t addr, size_t size) { - // Invariant: the range [addr,covered) is covered by existing stack - // frame entries. - uintptr_t covered = addr; - while (covered < addr + size) { - const Module::StackFrameEntry *old_entry = - module_->FindStackFrameEntryByAddress(covered); - if (!old_entry) { - return false; - } - covered = old_entry->address + old_entry->size; - } - return true; -} - -void ARMExToModule::AddStackFrame(uintptr_t addr, size_t size) { - stack_frame_entry_ = new Module::StackFrameEntry; - stack_frame_entry_->address = addr; - stack_frame_entry_->size = size; - stack_frame_entry_->initial_rules[".cfa"] = "sp"; - vsp_ = "sp"; -} - -int ARMExToModule::ImproveStackFrame(const struct extab_data* edata) { - return TranslateCmd(edata, stack_frame_entry_, vsp_) ; -} - -void ARMExToModule::DeleteStackFrame() { - delete stack_frame_entry_; -} - -void ARMExToModule::SubmitStackFrame() { - // return address always winds up in pc - stack_frame_entry_->initial_rules[".ra"] - = stack_frame_entry_->initial_rules["pc"]; - // the final value of vsp is the new value of sp - stack_frame_entry_->initial_rules["sp"] = vsp_; - module_->AddStackFrameEntry(stack_frame_entry_); -} - -} // namespace arm_ex_to_module diff --git a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.h deleted file mode 100644 index f413a16a9..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/arm_ex_to_module.h +++ /dev/null @@ -1,119 +0,0 @@ -/* libunwind - a platform-independent unwind library - Copyright 2011 Linaro Limited - -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. */ - -// 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. - - -// Derived from libunwind, with extensive modifications. - -#ifndef COMMON_ARM_EX_TO_MODULE__ -#define COMMON_ARM_EX_TO_MODULE__ - -#include "common/module.h" - -#include <string.h> - -namespace arm_ex_to_module { - -using google_breakpad::Module; - -typedef enum extab_cmd { - ARM_EXIDX_CMD_FINISH, - ARM_EXIDX_CMD_SUB_FROM_VSP, - ARM_EXIDX_CMD_ADD_TO_VSP, - ARM_EXIDX_CMD_REG_POP, - ARM_EXIDX_CMD_REG_TO_SP, - ARM_EXIDX_CMD_VFP_POP, - ARM_EXIDX_CMD_WREG_POP, - ARM_EXIDX_CMD_WCGR_POP, - ARM_EXIDX_CMD_RESERVED, - ARM_EXIDX_CMD_REFUSED, -} extab_cmd_t; - -struct exidx_entry { - uint32_t addr; - uint32_t data; -}; - -struct extab_data { - extab_cmd_t cmd; - uint32_t data; -}; - -enum extab_cmd_flags { - ARM_EXIDX_VFP_SHIFT_16 = 1 << 16, - ARM_EXIDX_VFP_FSTMD = 1 << 17, // distinguishes FSTMxxD from FSTMxxX -}; - -// Receives information from arm_ex_reader::ExceptionTableInfo -// and adds it to the Module object -class ARMExToModule { - public: - ARMExToModule(Module* module) - : module_(module) { } - ~ARMExToModule() { } - bool HasStackFrame(uintptr_t addr, size_t size); - void AddStackFrame(uintptr_t addr, size_t size); - int ImproveStackFrame(const struct extab_data* edata); - void DeleteStackFrame(); - void SubmitStackFrame(); - private: - Module* module_; - Module::StackFrameEntry* stack_frame_entry_; - string vsp_; - int TranslateCmd(const struct extab_data* edata, - Module::StackFrameEntry* entry, - string& vsp); -}; - -} // namespace arm_ex_to_module - -#endif // COMMON_ARM_EX_TO_MODULE__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/basictypes.h b/toolkit/crashreporter/google-breakpad/src/common/basictypes.h deleted file mode 100644 index 9426c1f6c..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/basictypes.h +++ /dev/null @@ -1,58 +0,0 @@ -// 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. - -#ifndef COMMON_BASICTYPES_H_ -#define COMMON_BASICTYPES_H_ - -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#ifndef DISALLOW_COPY_AND_ASSIGN -#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) -#endif // DISALLOW_COPY_AND_ASSIGN - -namespace google_breakpad { - -// Used to explicitly mark the return value of a function as unused. If you are -// really sure you don't want to do anything with the return value of a function -// that has been marked with __attribute__((warn_unused_result)), wrap it with -// this. Example: -// -// scoped_ptr<MyType> my_var = ...; -// if (TakeOwnership(my_var.get()) == SUCCESS) -// ignore_result(my_var.release()); -// -template<typename T> -inline void ignore_result(const T&) { -} - -} // namespace google_breakpad - -#endif // COMMON_BASICTYPES_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/byte_cursor.h b/toolkit/crashreporter/google-breakpad/src/common/byte_cursor.h deleted file mode 100644 index accd54e0a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/byte_cursor.h +++ /dev/null @@ -1,265 +0,0 @@ -// -*- mode: c++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// byte_cursor.h: Classes for parsing values from a buffer of bytes. -// The ByteCursor class provides a convenient interface for reading -// fixed-size integers of arbitrary endianness, being thorough about -// checking for buffer overruns. - -#ifndef COMMON_BYTE_CURSOR_H_ -#define COMMON_BYTE_CURSOR_H_ - -#include <assert.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include <string> - -#include "common/using_std_string.h" - -namespace google_breakpad { - -// A buffer holding a series of bytes. -struct ByteBuffer { - ByteBuffer() : start(0), end(0) { } - ByteBuffer(const uint8_t *set_start, size_t set_size) - : start(set_start), end(set_start + set_size) { } - ~ByteBuffer() { }; - - // Equality operators. Useful in unit tests, and when we're using - // ByteBuffers to refer to regions of a larger buffer. - bool operator==(const ByteBuffer &that) const { - return start == that.start && end == that.end; - } - bool operator!=(const ByteBuffer &that) const { - return start != that.start || end != that.end; - } - - // Not C++ style guide compliant, but this definitely belongs here. - size_t Size() const { - assert(start <= end); - return end - start; - } - - const uint8_t *start, *end; -}; - -// A cursor pointing into a ByteBuffer that can parse numbers of various -// widths and representations, strings, and data blocks, advancing through -// the buffer as it goes. All ByteCursor operations check that accesses -// haven't gone beyond the end of the enclosing ByteBuffer. -class ByteCursor { - public: - // Create a cursor reading bytes from the start of BUFFER. By default, the - // cursor reads multi-byte values in little-endian form. - ByteCursor(const ByteBuffer *buffer, bool big_endian = false) - : buffer_(buffer), here_(buffer->start), - big_endian_(big_endian), complete_(true) { } - - // Accessor and setter for this cursor's endianness flag. - bool big_endian() const { return big_endian_; } - void set_big_endian(bool big_endian) { big_endian_ = big_endian; } - - // Accessor and setter for this cursor's current position. The setter - // returns a reference to this cursor. - const uint8_t *here() const { return here_; } - ByteCursor &set_here(const uint8_t *here) { - assert(buffer_->start <= here && here <= buffer_->end); - here_ = here; - return *this; - } - - // Return the number of bytes available to read at the cursor. - size_t Available() const { return size_t(buffer_->end - here_); } - - // Return true if this cursor is at the end of its buffer. - bool AtEnd() const { return Available() == 0; } - - // When used as a boolean value this cursor converts to true if all - // prior reads have been completed, or false if we ran off the end - // of the buffer. - operator bool() const { return complete_; } - - // Read a SIZE-byte integer at this cursor, signed if IS_SIGNED is true, - // unsigned otherwise, using the cursor's established endianness, and set - // *RESULT to the number. If we read off the end of our buffer, clear - // this cursor's complete_ flag, and store a dummy value in *RESULT. - // Return a reference to this cursor. - template<typename T> - ByteCursor &Read(size_t size, bool is_signed, T *result) { - if (CheckAvailable(size)) { - T v = 0; - if (big_endian_) { - for (size_t i = 0; i < size; i++) - v = (v << 8) + here_[i]; - } else { - // This loop condition looks weird, but size_t is unsigned, so - // decrementing i after it is zero yields the largest size_t value. - for (size_t i = size - 1; i < size; i--) - v = (v << 8) + here_[i]; - } - if (is_signed && size < sizeof(T)) { - size_t sign_bit = (T)1 << (size * 8 - 1); - v = (v ^ sign_bit) - sign_bit; - } - here_ += size; - *result = v; - } else { - *result = (T) 0xdeadbeef; - } - return *this; - } - - // Read an integer, using the cursor's established endianness and - // *RESULT's size and signedness, and set *RESULT to the number. If we - // read off the end of our buffer, clear this cursor's complete_ flag. - // Return a reference to this cursor. - template<typename T> - ByteCursor &operator>>(T &result) { - bool T_is_signed = (T)-1 < 0; - return Read(sizeof(T), T_is_signed, &result); - } - - // Copy the SIZE bytes at the cursor to BUFFER, and advance this - // cursor to the end of them. If we read off the end of our buffer, - // clear this cursor's complete_ flag, and set *POINTER to NULL. - // Return a reference to this cursor. - ByteCursor &Read(uint8_t *buffer, size_t size) { - if (CheckAvailable(size)) { - memcpy(buffer, here_, size); - here_ += size; - } - return *this; - } - - // Set STR to a copy of the '\0'-terminated string at the cursor. If the - // byte buffer does not contain a terminating zero, clear this cursor's - // complete_ flag, and set STR to the empty string. Return a reference to - // this cursor. - ByteCursor &CString(string *str) { - const uint8_t *end - = static_cast<const uint8_t *>(memchr(here_, '\0', Available())); - if (end) { - str->assign(reinterpret_cast<const char *>(here_), end - here_); - here_ = end + 1; - } else { - str->clear(); - here_ = buffer_->end; - complete_ = false; - } - return *this; - } - - // Like CString(STR), but extract the string from a fixed-width buffer - // LIMIT bytes long, which may or may not contain a terminating '\0' - // byte. Specifically: - // - // - If there are not LIMIT bytes available at the cursor, clear the - // cursor's complete_ flag and set STR to the empty string. - // - // - Otherwise, if the LIMIT bytes at the cursor contain any '\0' - // characters, set *STR to a copy of the bytes before the first '\0', - // and advance the cursor by LIMIT bytes. - // - // - Otherwise, set *STR to a copy of those LIMIT bytes, and advance the - // cursor by LIMIT bytes. - ByteCursor &CString(string *str, size_t limit) { - if (CheckAvailable(limit)) { - const uint8_t *end - = static_cast<const uint8_t *>(memchr(here_, '\0', limit)); - if (end) - str->assign(reinterpret_cast<const char *>(here_), end - here_); - else - str->assign(reinterpret_cast<const char *>(here_), limit); - here_ += limit; - } else { - str->clear(); - } - return *this; - } - - // Set *POINTER to point to the SIZE bytes at the cursor, and advance - // this cursor to the end of them. If SIZE is omitted, don't move the - // cursor. If we read off the end of our buffer, clear this cursor's - // complete_ flag, and set *POINTER to NULL. Return a reference to this - // cursor. - ByteCursor &PointTo(const uint8_t **pointer, size_t size = 0) { - if (CheckAvailable(size)) { - *pointer = here_; - here_ += size; - } else { - *pointer = NULL; - } - return *this; - } - - // Skip SIZE bytes at the cursor. If doing so would advance us off - // the end of our buffer, clear this cursor's complete_ flag, and - // set *POINTER to NULL. Return a reference to this cursor. - ByteCursor &Skip(size_t size) { - if (CheckAvailable(size)) - here_ += size; - return *this; - } - - private: - // If there are at least SIZE bytes available to read from the buffer, - // return true. Otherwise, set here_ to the end of the buffer, set - // complete_ to false, and return false. - bool CheckAvailable(size_t size) { - if (Available() >= size) { - return true; - } else { - here_ = buffer_->end; - complete_ = false; - return false; - } - } - - // The buffer we're reading bytes from. - const ByteBuffer *buffer_; - - // The next byte within buffer_ that we'll read. - const uint8_t *here_; - - // True if we should read numbers in big-endian form; false if we - // should read in little-endian form. - bool big_endian_; - - // True if we've been able to read all we've been asked to. - bool complete_; -}; - -} // namespace google_breakpad - -#endif // COMMON_BYTE_CURSOR_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/byte_cursor_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/byte_cursor_unittest.cc deleted file mode 100644 index 06bfd89d7..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/byte_cursor_unittest.cc +++ /dev/null @@ -1,776 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// byte_cursor_unittest.cc: Unit tests for google_breakpad::ByteBuffer -// and google_breakpad::ByteCursor. - -#include <string> - -#include <string.h> - -#include "breakpad_googletest_includes.h" -#include "common/byte_cursor.h" -#include "common/using_std_string.h" - -using google_breakpad::ByteBuffer; -using google_breakpad::ByteCursor; - -TEST(Buffer, SizeOfNothing) { - uint8_t data[1]; - ByteBuffer buffer(data, 0); - EXPECT_EQ(0U, buffer.Size()); -} - -TEST(Buffer, SizeOfSomething) { - uint8_t data[10]; - ByteBuffer buffer(data, sizeof(data)); - EXPECT_EQ(10U, buffer.Size()); -} - -TEST(Extent, AvailableEmpty) { - uint8_t data[1]; - ByteBuffer buffer(data, 0); - ByteCursor cursor(&buffer); - EXPECT_EQ(0U, cursor.Available()); -} - -TEST(Extent, AtEndEmpty) { - uint8_t data[1]; - ByteBuffer buffer(data, 0); - ByteCursor cursor(&buffer); - EXPECT_TRUE(cursor.AtEnd()); -} - -TEST(Extent, AsBoolEmpty) { - uint8_t data[1]; - ByteBuffer buffer(data, 0); - ByteCursor cursor(&buffer); - EXPECT_TRUE(cursor); -} - -TEST(Extent, AvailableSome) { - uint8_t data[10]; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - EXPECT_EQ(10U, cursor.Available()); -} - -TEST(Extent, AtEndSome) { - uint8_t data[10]; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - EXPECT_FALSE(cursor.AtEnd()); - EXPECT_TRUE(cursor.Skip(sizeof(data)).AtEnd()); -} - -TEST(Extent, AsBoolSome) { - uint8_t data[10]; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - EXPECT_TRUE(cursor); - EXPECT_TRUE(cursor.Skip(sizeof(data))); - EXPECT_FALSE(cursor.Skip(1)); -} - -TEST(Extent, Cursor) { - uint8_t data[] = { 0xf7, - 0x9f, 0xbe, - 0x67, 0xfb, 0xd3, 0x58, - 0x6f, 0x36, 0xde, 0xd1, - 0x2a, 0x2a, 0x2a }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - - uint8_t a; - uint16_t b; - uint32_t c; - uint32_t d; - uint8_t stars[3]; - - EXPECT_EQ(data + 0U, cursor.here()); - - EXPECT_TRUE(cursor >> a); - EXPECT_EQ(data + 1U, cursor.here()); - - EXPECT_TRUE(cursor >> b); - EXPECT_EQ(data + 3U, cursor.here()); - - EXPECT_TRUE(cursor >> c); - EXPECT_EQ(data + 7U, cursor.here()); - - EXPECT_TRUE(cursor.Skip(4)); - EXPECT_EQ(data + 11U, cursor.here()); - - EXPECT_TRUE(cursor.Read(stars, 3)); - EXPECT_EQ(data + 14U, cursor.here()); - - EXPECT_FALSE(cursor >> d); - EXPECT_EQ(data + 14U, cursor.here()); -} - -TEST(Extent, SetOffset) { - uint8_t data[] = { 0x5c, 0x79, 0x8c, 0xd5 }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - - uint8_t a, b, c, d, e; - EXPECT_TRUE(cursor >> a); - EXPECT_EQ(0x5cU, a); - EXPECT_EQ(data + 1U, cursor.here()); - EXPECT_TRUE(((cursor >> b).set_here(data + 3) >> c).set_here(data + 1) - >> d >> e); - EXPECT_EQ(0x79U, b); - EXPECT_EQ(0xd5U, c); - EXPECT_EQ(0x79U, d); - EXPECT_EQ(0x8cU, e); - EXPECT_EQ(data + 3U, cursor.here()); -} - -TEST(BigEndian, Signed1) { - uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - cursor.set_big_endian(true); - int a, b, c, d, e; - ASSERT_TRUE(cursor - .Read(1, true, &a) - .Read(1, true, &b) - .Read(1, true, &c) - .Read(1, true, &d)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x7f, b); - EXPECT_EQ(-0x80, c); - EXPECT_EQ(-1, d); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(1, true, &e)); -} - -TEST(BigEndian, Signed2) { - uint8_t data[] = { 0x00, 0x00, 0x00, 0x80, 0x7f, 0xff, - 0x80, 0x00, 0x80, 0x80, 0xff, 0xff, - 0x39, 0xf1, 0x8a, 0xbc, 0x5a, 0xec }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer, true); - int a, b, c, d, e, f, g, h, i, j; - ASSERT_TRUE(cursor - .Read(2, true, &a) - .Read(2, true, &b) - .Read(2, true, &c) - .Read(2, true, &d) - .Read(2, true, &e) - .Read(2, true, &f) - .Read(2, true, &g) - .Read(2, true, &h) - .Read(2, true, &i)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x80, b); - EXPECT_EQ(0x7fff, c); - EXPECT_EQ(-0x8000, d); - EXPECT_EQ(-0x7f80, e); - EXPECT_EQ(-1, f); - EXPECT_EQ(0x39f1, g); - EXPECT_EQ(-0x7544, h); - EXPECT_EQ(0x5aec, i); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(2, true, &j)); -} - -TEST(BigEndian, Signed4) { - uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, - 0x7f, 0xff, 0xff, 0xff, - 0x80, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, - 0xb6, 0xb1, 0xff, 0xef, - 0x19, 0x6a, 0xca, 0x46 }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - cursor.set_big_endian(true); - int64_t a, b, c, d, e, f, g; - ASSERT_TRUE(cursor - .Read(4, true, &a) - .Read(4, true, &b) - .Read(4, true, &c) - .Read(4, true, &d) - .Read(4, true, &e) - .Read(4, true, &f)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x7fffffff, b); - EXPECT_EQ(-0x80000000LL, c); - EXPECT_EQ(-1, d); - EXPECT_EQ((int32_t) 0xb6b1ffef, e); - EXPECT_EQ(0x196aca46, f); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(4, true, &g)); -} - -TEST(BigEndian, Signed8) { - uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x93, 0x20, 0xd5, 0xe9, 0xd2, 0xd5, 0x87, 0x9c, - 0x4e, 0x42, 0x49, 0xd2, 0x7f, 0x84, 0x14, 0xa4 }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer, true); - int64_t a, b, c, d, e, f, g; - ASSERT_TRUE(cursor - .Read(8, true, &a) - .Read(8, true, &b) - .Read(8, true, &c) - .Read(8, true, &d) - .Read(8, true, &e) - .Read(8, true, &f)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x7fffffffffffffffLL, b); - EXPECT_EQ(-0x7fffffffffffffffLL - 1, c); - EXPECT_EQ(-1, d); - EXPECT_EQ((int64_t) 0x9320d5e9d2d5879cULL, e); - EXPECT_EQ(0x4e4249d27f8414a4LL, f); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(8, true, &g)); -} - -TEST(BigEndian, Unsigned1) { - uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - cursor.set_big_endian(true); - int32_t a, b, c, d, e; - ASSERT_TRUE(cursor - .Read(1, false, &a) - .Read(1, false, &b) - .Read(1, false, &c) - .Read(1, false, &d)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x7f, b); - EXPECT_EQ(0x80, c); - EXPECT_EQ(0xff, d); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(1, false, &e)); -} - -TEST(BigEndian, Unsigned2) { - uint8_t data[] = { 0x00, 0x00, 0x00, 0x80, 0x7f, 0xff, - 0x80, 0x00, 0x80, 0x80, 0xff, 0xff, - 0x39, 0xf1, 0x8a, 0xbc, 0x5a, 0xec }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer, true); - int64_t a, b, c, d, e, f, g, h, i, j; - ASSERT_TRUE(cursor - .Read(2, false, &a) - .Read(2, false, &b) - .Read(2, false, &c) - .Read(2, false, &d) - .Read(2, false, &e) - .Read(2, false, &f) - .Read(2, false, &g) - .Read(2, false, &h) - .Read(2, false, &i)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x80, b); - EXPECT_EQ(0x7fff, c); - EXPECT_EQ(0x8000, d); - EXPECT_EQ(0x8080, e); - EXPECT_EQ(0xffff, f); - EXPECT_EQ(0x39f1, g); - EXPECT_EQ(0x8abc, h); - EXPECT_EQ(0x5aec, i); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(2, false, &j)); -} - -TEST(BigEndian, Unsigned4) { - uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, - 0x7f, 0xff, 0xff, 0xff, - 0x80, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, - 0xb6, 0xb1, 0xff, 0xef, - 0x19, 0x6a, 0xca, 0x46 }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - cursor.set_big_endian(true); - int64_t a, b, c, d, e, f, g; - ASSERT_TRUE(cursor - .Read(4, false, &a) - .Read(4, false, &b) - .Read(4, false, &c) - .Read(4, false, &d) - .Read(4, false, &e) - .Read(4, false, &f)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x7fffffff, b); - EXPECT_EQ(0x80000000, c); - EXPECT_EQ(0xffffffff, d); - EXPECT_EQ(0xb6b1ffef, e); - EXPECT_EQ(0x196aca46, f); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(4, false, &g)); -} - -TEST(BigEndian, Unsigned8) { - uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x93, 0x20, 0xd5, 0xe9, 0xd2, 0xd5, 0x87, 0x9c, - 0x4e, 0x42, 0x49, 0xd2, 0x7f, 0x84, 0x14, 0xa4 }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer, true); - uint64_t a, b, c, d, e, f, g; - ASSERT_TRUE(cursor - .Read(8, false, &a) - .Read(8, false, &b) - .Read(8, false, &c) - .Read(8, false, &d) - .Read(8, false, &e) - .Read(8, false, &f)); - EXPECT_EQ(0U, a); - EXPECT_EQ(0x7fffffffffffffffULL, b); - EXPECT_EQ(0x8000000000000000ULL, c); - EXPECT_EQ(0xffffffffffffffffULL, d); - EXPECT_EQ(0x9320d5e9d2d5879cULL, e); - EXPECT_EQ(0x4e4249d27f8414a4ULL, f); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(8, false, &g)); -} - -TEST(LittleEndian, Signed1) { - uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - int32_t a, b, c, d, e; - ASSERT_TRUE(cursor - .Read(1, true, &a) - .Read(1, true, &b) - .Read(1, true, &c) - .Read(1, true, &d)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x7f, b); - EXPECT_EQ(-0x80, c); - EXPECT_EQ(-1, d); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(1, true, &e)); -} - -TEST(LittleEndian, Signed2) { - uint8_t data[] = { 0x00, 0x00, 0x80, 0x00, 0xff, 0x7f, - 0x00, 0x80, 0x80, 0x80, 0xff, 0xff, - 0xf1, 0x39, 0xbc, 0x8a, 0xec, 0x5a }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer, false); - int32_t a, b, c, d, e, f, g, h, i, j; - ASSERT_TRUE(cursor - .Read(2, true, &a) - .Read(2, true, &b) - .Read(2, true, &c) - .Read(2, true, &d) - .Read(2, true, &e) - .Read(2, true, &f) - .Read(2, true, &g) - .Read(2, true, &h) - .Read(2, true, &i)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x80, b); - EXPECT_EQ(0x7fff, c); - EXPECT_EQ(-0x8000, d); - EXPECT_EQ(-0x7f80, e); - EXPECT_EQ(-1, f); - EXPECT_EQ(0x39f1, g); - EXPECT_EQ(-0x7544, h); - EXPECT_EQ(0x5aec, i); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(2, true, &j)); -} - -TEST(LittleEndian, Signed4) { - uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0x7f, - 0x00, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xb1, 0xb6, - 0x46, 0xca, 0x6a, 0x19 }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - int64_t a, b, c, d, e, f, g; - ASSERT_TRUE(cursor - .Read(4, true, &a) - .Read(4, true, &b) - .Read(4, true, &c) - .Read(4, true, &d) - .Read(4, true, &e) - .Read(4, true, &f)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x7fffffff, b); - EXPECT_EQ(-0x80000000LL, c); - EXPECT_EQ(-1, d); - EXPECT_EQ((int32_t) 0xb6b1ffef, e); - EXPECT_EQ(0x196aca46, f); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(4, true, &g)); -} - -TEST(LittleEndian, Signed8) { - uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x9c, 0x87, 0xd5, 0xd2, 0xe9, 0xd5, 0x20, 0x93, - 0xa4, 0x14, 0x84, 0x7f, 0xd2, 0x49, 0x42, 0x4e }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer, false); - int64_t a, b, c, d, e, f, g; - ASSERT_TRUE(cursor - .Read(8, true, &a) - .Read(8, true, &b) - .Read(8, true, &c) - .Read(8, true, &d) - .Read(8, true, &e) - .Read(8, true, &f)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x7fffffffffffffffLL, b); - EXPECT_EQ(-0x7fffffffffffffffLL - 1, c); - EXPECT_EQ(-1, d); - EXPECT_EQ((int64_t) 0x9320d5e9d2d5879cULL, e); - EXPECT_EQ(0x4e4249d27f8414a4LL, f); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(8, true, &g)); -} - -TEST(LittleEndian, Unsigned1) { - uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - int32_t a, b, c, d, e; - ASSERT_TRUE(cursor - .Read(1, false, &a) - .Read(1, false, &b) - .Read(1, false, &c) - .Read(1, false, &d)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x7f, b); - EXPECT_EQ(0x80, c); - EXPECT_EQ(0xff, d); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(1, false, &e)); -} - -TEST(LittleEndian, Unsigned2) { - uint8_t data[] = { 0x00, 0x00, 0x80, 0x00, 0xff, 0x7f, - 0x00, 0x80, 0x80, 0x80, 0xff, 0xff, - 0xf1, 0x39, 0xbc, 0x8a, 0xec, 0x5a }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - int32_t a, b, c, d, e, f, g, h, i, j; - ASSERT_TRUE(cursor - .Read(2, false, &a) - .Read(2, false, &b) - .Read(2, false, &c) - .Read(2, false, &d) - .Read(2, false, &e) - .Read(2, false, &f) - .Read(2, false, &g) - .Read(2, false, &h) - .Read(2, false, &i)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x80, b); - EXPECT_EQ(0x7fff, c); - EXPECT_EQ(0x8000, d); - EXPECT_EQ(0x8080, e); - EXPECT_EQ(0xffff, f); - EXPECT_EQ(0x39f1, g); - EXPECT_EQ(0x8abc, h); - EXPECT_EQ(0x5aec, i); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(2, false, &j)); -} - -TEST(LittleEndian, Unsigned4) { - uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0x7f, - 0x00, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, - 0xef, 0xff, 0xb1, 0xb6, - 0x46, 0xca, 0x6a, 0x19 }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - int64_t a, b, c, d, e, f, g; - ASSERT_TRUE(cursor - .Read(4, false, &a) - .Read(4, false, &b) - .Read(4, false, &c) - .Read(4, false, &d) - .Read(4, false, &e) - .Read(4, false, &f)); - EXPECT_EQ(0, a); - EXPECT_EQ(0x7fffffff, b); - EXPECT_EQ(0x80000000, c); - EXPECT_EQ(0xffffffff, d); - EXPECT_EQ(0xb6b1ffef, e); - EXPECT_EQ(0x196aca46, f); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(4, false, &g)); -} - -TEST(LittleEndian, Unsigned8) { - uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x9c, 0x87, 0xd5, 0xd2, 0xe9, 0xd5, 0x20, 0x93, - 0xa4, 0x14, 0x84, 0x7f, 0xd2, 0x49, 0x42, 0x4e }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - uint64_t a, b, c, d, e, f, g; - ASSERT_TRUE(cursor - .Read(8, false, &a) - .Read(8, false, &b) - .Read(8, false, &c) - .Read(8, false, &d) - .Read(8, false, &e) - .Read(8, false, &f)); - EXPECT_EQ(0U, a); - EXPECT_EQ(0x7fffffffffffffffULL, b); - EXPECT_EQ(0x8000000000000000ULL, c); - EXPECT_EQ(0xffffffffffffffffULL, d); - EXPECT_EQ(0x9320d5e9d2d5879cULL, e); - EXPECT_EQ(0x4e4249d27f8414a4ULL, f); - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor.Read(8, false, &g)); -} - -TEST(Extractor, Signed1) { - uint8_t data[] = { 0xfd }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - int8_t a; - EXPECT_TRUE(cursor >> a); - EXPECT_EQ(-3, a); - EXPECT_FALSE(cursor >> a); -} - -TEST(Extractor, Signed2) { - uint8_t data[] = { 0x13, 0xcd }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - int16_t a; - EXPECT_TRUE(cursor >> a); - EXPECT_EQ(-13037, a); - EXPECT_FALSE(cursor >> a); -} - -TEST(Extractor, Signed4) { - uint8_t data[] = { 0xd2, 0xe4, 0x53, 0xe9 }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - int32_t a; - // For some reason, G++ 4.4.1 complains: - // warning: array subscript is above array bounds - // in ByteCursor::Read(size_t, bool, T *) as it inlines this call, but - // I'm not able to see how such a reference would occur. - EXPECT_TRUE(cursor >> a); - EXPECT_EQ(-380377902, a); - EXPECT_FALSE(cursor >> a); -} - -TEST(Extractor, Unsigned1) { - uint8_t data[] = { 0xfd }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - uint8_t a; - EXPECT_TRUE(cursor >> a); - EXPECT_EQ(0xfd, a); - EXPECT_FALSE(cursor >> a); -} - -TEST(Extractor, Unsigned2) { - uint8_t data[] = { 0x13, 0xcd }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - uint16_t a; - EXPECT_TRUE(cursor >> a); - EXPECT_EQ(0xcd13, a); - EXPECT_FALSE(cursor >> a); -} - -TEST(Extractor, Unsigned4) { - uint8_t data[] = { 0xd2, 0xe4, 0x53, 0xe9 }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - uint32_t a; - // For some reason, G++ 4.4.1 complains: - // warning: array subscript is above array bounds - // in ByteCursor::Read(size_t, bool, T *) as it inlines this call, but - // I'm not able to see how such a reference would occur. - EXPECT_TRUE(cursor >> a); - EXPECT_EQ(0xe953e4d2, a); - EXPECT_FALSE(cursor >> a); - EXPECT_FALSE(cursor >> a); -} - -TEST(Extractor, Mixed) { - uint8_t data[] = { 0x42, - 0x25, 0x0b, - 0x3d, 0x25, 0xed, 0x2a, - 0xec, 0x16, 0x9e, 0x14, 0x61, 0x5b, 0x2c, 0xcf, - 0xd8, - 0x22, 0xa5, - 0x3a, 0x02, 0x6a, 0xd7, - 0x93, 0x2a, 0x2d, 0x8d, 0xb4, 0x95, 0xe0, 0xc6 }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - cursor.set_big_endian(true); - - uint8_t a; - uint16_t b; - uint32_t c; - uint64_t d; - int8_t e; - int16_t f; - int32_t g; - int64_t h; - int z; - EXPECT_FALSE(cursor.AtEnd()); - EXPECT_TRUE(cursor >> a >> b >> c >> d >> e >> f >> g >> h); - EXPECT_EQ(0x42U, a); - EXPECT_EQ(0x250bU, b); - EXPECT_EQ(0x3d25ed2aU, c); - EXPECT_EQ(0xec169e14615b2ccfULL, d); - EXPECT_EQ(-40, e); - EXPECT_EQ(0x22a5, f); - EXPECT_EQ(0x3a026ad7, g); - EXPECT_EQ(-7842405714468937530LL, h); - - EXPECT_TRUE(cursor.AtEnd()); - EXPECT_FALSE(cursor >> z); -} - -TEST(Strings, Zero) { - uint8_t data[] = { 0xa6 }; - ByteBuffer buffer(data, 0); - ByteCursor cursor(&buffer); - - uint8_t received[1]; - received[0] = 0xc2; - EXPECT_TRUE(cursor.Read(received, 0)); - EXPECT_EQ(0xc2U, received[0]); -} - -TEST(Strings, Some) { - uint8_t data[] = { 0x5d, 0x31, 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xbb }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - - uint8_t received[7] = { 0xa7, 0xf7, 0x43, 0x0c, 0x27, 0xea, 0xed }; - EXPECT_TRUE(cursor.Skip(2).Read(received, 5)); - uint8_t expected[7] = { 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xea, 0xed }; - EXPECT_TRUE(memcmp(received, expected, 7) == 0); -} - -TEST(Strings, TooMuch) { - uint8_t data[] = { 0x5d, 0x31, 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xbb }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - - uint8_t received1[3]; - uint8_t received2[3]; - uint8_t received3[3]; - EXPECT_FALSE(cursor - .Read(received1, 3) - .Read(received2, 3) - .Read(received3, 3)); - uint8_t expected1[3] = { 0x5d, 0x31, 0x09 }; - uint8_t expected2[3] = { 0xa6, 0x2e, 0x2c }; - - EXPECT_TRUE(memcmp(received1, expected1, 3) == 0); - EXPECT_TRUE(memcmp(received2, expected2, 3) == 0); -} - -TEST(Strings, PointTo) { - uint8_t data[] = { 0x83, 0x80, 0xb4, 0x38, 0x00, 0x2c, 0x0a, 0x27 }; - ByteBuffer buffer(data, sizeof(data)); - ByteCursor cursor(&buffer); - - const uint8_t *received1; - const uint8_t *received2; - const uint8_t *received3; - const uint8_t *received4; - EXPECT_FALSE(cursor - .PointTo(&received1, 3) - .PointTo(&received2, 3) - .PointTo(&received3) - .PointTo(&received4, 3)); - EXPECT_EQ(data + 0, received1); - EXPECT_EQ(data + 3, received2); - EXPECT_EQ(data + 6, received3); - EXPECT_EQ(NULL, received4); -} - -TEST(Strings, CString) { - uint8_t data[] = "abc\0\0foo"; - ByteBuffer buffer(data, sizeof(data) - 1); // don't include terminating '\0' - ByteCursor cursor(&buffer); - - string a, b, c; - EXPECT_TRUE(cursor.CString(&a).CString(&b)); - EXPECT_EQ("abc", a); - EXPECT_EQ("", b); - EXPECT_FALSE(cursor.CString(&c)); - EXPECT_EQ("", c); - EXPECT_TRUE(cursor.AtEnd()); -} - -TEST(Strings, CStringLimit) { - uint8_t data[] = "abcdef\0\0foobar"; - ByteBuffer buffer(data, sizeof(data) - 1); // don't include terminating '\0' - ByteCursor cursor(&buffer); - - string a, b, c, d, e; - - EXPECT_TRUE(cursor.CString(&a, 3)); - EXPECT_EQ("abc", a); - - EXPECT_TRUE(cursor.CString(&b, 0)); - EXPECT_EQ("", b); - - EXPECT_TRUE(cursor.CString(&c, 6)); - EXPECT_EQ("def", c); - - EXPECT_TRUE(cursor.CString(&d, 4)); - EXPECT_EQ("ooba", d); - - EXPECT_FALSE(cursor.CString(&e, 4)); - EXPECT_EQ("", e); - - EXPECT_TRUE(cursor.AtEnd()); -} - -// uint8_t data[] = { 0xa6, 0x54, 0xdf, 0x67, 0x51, 0x43, 0xac, 0xf1 }; -// ByteBuffer buffer(data, sizeof(data)); diff --git a/toolkit/crashreporter/google-breakpad/src/common/common.gyp b/toolkit/crashreporter/google-breakpad/src/common/common.gyp deleted file mode 100644 index 08772bf75..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/common.gyp +++ /dev/null @@ -1,250 +0,0 @@ -# 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. - -{ - 'target_defaults': { - 'target_conditions': [ - ['OS=="mac"', { - 'defines': ['HAVE_MACH_O_NLIST_H'], - }], - ['OS=="linux"', { - 'defines': ['HAVE_A_OUT_H'], - }], - ['OS!="android"', {'sources/': [['exclude', '(^|/)android/']]}], - ['OS!="linux"', {'sources/': [['exclude', '(^|/)linux/']]}], - ['OS!="mac"', {'sources/': [['exclude', '(^|/)mac/']]}], - ['OS!="solaris"', {'sources/': [['exclude', '(^|/)solaris/']]}], - ['OS!="win"', {'sources/': [['exclude', '(^|/)windows/']]}], - ], - }, - 'targets': [ - { - 'target_name': 'common', - 'type': 'static_library', - 'sources': [ - 'android/breakpad_getcontext.S', - 'android/include/elf.h', - 'android/include/link.h', - 'android/include/sgidefs.h', - 'android/include/stab.h', - 'android/include/sys/procfs.h', - 'android/include/sys/signal.h', - 'android/include/sys/user.h', - 'android/include/ucontext.h', - 'android/testing/include/wchar.h', - 'android/testing/mkdtemp.h', - 'android/testing/pthread_fixes.h', - 'android/ucontext_constants.h', - 'basictypes.h', - 'byte_cursor.h', - 'convert_UTF.c', - 'convert_UTF.h', - 'dwarf/bytereader-inl.h', - 'dwarf/bytereader.cc', - 'dwarf/bytereader.h', - 'dwarf/cfi_assembler.cc', - 'dwarf/cfi_assembler.h', - 'dwarf/dwarf2diehandler.cc', - 'dwarf/dwarf2diehandler.h', - 'dwarf/dwarf2enums.h', - 'dwarf/dwarf2reader.cc', - 'dwarf/dwarf2reader.h', - 'dwarf/dwarf2reader_test_common.h', - 'dwarf/elf_reader.cc', - 'dwarf/elf_reader.h', - 'dwarf/functioninfo.cc', - 'dwarf/functioninfo.h', - 'dwarf/line_state_machine.h', - 'dwarf/types.h', - 'dwarf_cfi_to_module.cc', - 'dwarf_cfi_to_module.h', - 'dwarf_cu_to_module.cc', - 'dwarf_cu_to_module.h', - 'dwarf_line_to_module.cc', - 'dwarf_line_to_module.h', - 'language.cc', - 'language.h', - 'linux/crc32.cc', - 'linux/crc32.h', - 'linux/dump_symbols.cc', - 'linux/dump_symbols.h', - 'linux/eintr_wrapper.h', - 'linux/elf_core_dump.cc', - 'linux/elf_core_dump.h', - 'linux/elf_gnu_compat.h', - 'linux/elf_symbols_to_module.cc', - 'linux/elf_symbols_to_module.h', - 'linux/elfutils-inl.h', - 'linux/elfutils.cc', - 'linux/elfutils.h', - 'linux/file_id.cc', - 'linux/file_id.h', - 'linux/google_crashdump_uploader.cc', - 'linux/google_crashdump_uploader.h', - 'linux/guid_creator.cc', - 'linux/guid_creator.h', - 'linux/http_upload.cc', - 'linux/http_upload.h', - 'linux/ignore_ret.h', - 'linux/libcurl_wrapper.cc', - 'linux/libcurl_wrapper.h', - 'linux/linux_libc_support.cc', - 'linux/linux_libc_support.h', - 'linux/memory_mapped_file.cc', - 'linux/memory_mapped_file.h', - 'linux/safe_readlink.cc', - 'linux/safe_readlink.h', - 'linux/synth_elf.cc', - 'linux/synth_elf.h', - 'mac/arch_utilities.cc', - 'mac/arch_utilities.h', - 'mac/bootstrap_compat.cc', - 'mac/bootstrap_compat.h', - 'mac/byteswap.h', - 'mac/dump_syms.h', - 'mac/dump_syms.cc', - 'mac/file_id.cc', - 'mac/file_id.h', - 'mac/GTMDefines.h', - 'mac/GTMLogger.h', - 'mac/GTMLogger.m', - 'mac/HTTPMultipartUpload.h', - 'mac/HTTPMultipartUpload.m', - 'mac/MachIPC.h', - 'mac/MachIPC.mm', - 'mac/macho_id.cc', - 'mac/macho_id.h', - 'mac/macho_reader.cc', - 'mac/macho_reader.h', - 'mac/macho_utilities.cc', - 'mac/macho_utilities.h', - 'mac/macho_walker.cc', - 'mac/macho_walker.h', - 'mac/scoped_task_suspend-inl.h', - 'mac/string_utilities.cc', - 'mac/string_utilities.h', - 'mac/super_fat_arch.h', - 'md5.cc', - 'md5.h', - 'memory.h', - 'memory_range.h', - 'module.cc', - 'module.h', - 'scoped_ptr.h', - 'simple_string_dictionary.cc', - 'simple_string_dictionary.h', - 'solaris/dump_symbols.cc', - 'solaris/dump_symbols.h', - 'solaris/file_id.cc', - 'solaris/file_id.h', - 'solaris/guid_creator.cc', - 'solaris/guid_creator.h', - 'solaris/message_output.h', - 'stabs_reader.cc', - 'stabs_reader.h', - 'stabs_to_module.cc', - 'stabs_to_module.h', - 'string_conversion.cc', - 'string_conversion.h', - 'symbol_data.h', - 'test_assembler.cc', - 'test_assembler.h', - 'unordered.h', - 'using_std_string.h', - 'windows/common_windows.gyp', - 'windows/dia_util.cc', - 'windows/dia_util.h', - 'windows/guid_string.cc', - 'windows/guid_string.h', - 'windows/http_upload.cc', - 'windows/http_upload.h', - 'windows/omap.cc', - 'windows/omap.h', - 'windows/omap_internal.h', - 'windows/pdb_source_line_writer.cc', - 'windows/pdb_source_line_writer.h', - 'windows/string_utils-inl.h', - 'windows/string_utils.cc', - ], - 'include_dirs': [ - '..', - ], - }, - { - 'target_name': 'common_unittests', - 'type': 'executable', - 'sources': [ - 'android/breakpad_getcontext_unittest.cc', - 'byte_cursor_unittest.cc', - 'dwarf/bytereader_unittest.cc', - 'dwarf/dwarf2diehandler_unittest.cc', - 'dwarf/dwarf2reader_cfi_unittest.cc', - 'dwarf/dwarf2reader_die_unittest.cc', - 'dwarf_cfi_to_module_unittest.cc', - 'dwarf_cu_to_module_unittest.cc', - 'dwarf_line_to_module_unittest.cc', - 'linux/dump_symbols_unittest.cc', - 'linux/elf_core_dump_unittest.cc', - 'linux/elf_symbols_to_module_unittest.cc', - 'linux/file_id_unittest.cc', - 'linux/google_crashdump_uploader_test.cc', - 'linux/linux_libc_support_unittest.cc', - 'linux/memory_mapped_file_unittest.cc', - 'linux/safe_readlink_unittest.cc', - 'linux/synth_elf_unittest.cc', - 'linux/tests/auto_testfile.h', - 'linux/tests/crash_generator.cc', - 'linux/tests/crash_generator.h', - 'mac/macho_reader_unittest.cc', - 'memory_range_unittest.cc', - 'memory_unittest.cc', - 'module_unittest.cc', - 'simple_string_dictionary_unittest.cc', - 'stabs_reader_unittest.cc', - 'stabs_to_module_unittest.cc', - 'test_assembler_unittest.cc', - 'tests/auto_tempdir.h', - 'tests/file_utils.cc', - 'tests/file_utils.h', - 'windows/omap_unittest.cc', - ], - 'include_dirs': [ - '..', - ], - 'dependencies': [ - 'common', - '../build/testing.gypi:gmock_main', - '../build/testing.gypi:gmock', - '../build/testing.gypi:gtest', - ], - 'libraries': [ - '-ldl', - ], - }, - ], -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/convert_UTF.c b/toolkit/crashreporter/google-breakpad/src/common/convert_UTF.c deleted file mode 100644 index 12a3c8917..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/convert_UTF.c +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright © 1991-2015 Unicode, Inc. All rights reserved. - * Distributed under the Terms of Use in - * http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of the Unicode data files and any associated documentation - * (the "Data Files") or Unicode software and any associated documentation - * (the "Software") to deal in the Data Files or Software - * without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, and/or sell copies of - * the Data Files or Software, and to permit persons to whom the Data Files - * or Software are furnished to do so, provided that - * (a) this copyright and permission notice appear with all copies - * of the Data Files or Software, - * (b) this copyright and permission notice appear in associated - * documentation, and - * (c) there is clear notice in each modified Data File or in the Software - * as well as in the documentation associated with the Data File(s) or - * Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS - * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL - * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder - * shall not be used in advertising or otherwise to promote the sale, - * use or other dealings in these Data Files or Software without prior - * written authorization of the copyright holder. - */ - -/* --------------------------------------------------------------------- - -Conversions between UTF32, UTF-16, and UTF-8. Source code file. -Author: Mark E. Davis, 1994. -Rev History: Rick McGowan, fixes & updates May 2001. -Sept 2001: fixed const & error conditions per -mods suggested by S. Parent & A. Lillich. -June 2002: Tim Dodd added detection and handling of incomplete -source sequences, enhanced error detection, added casts -to eliminate compiler warnings. -July 2003: slight mods to back out aggressive FFFE detection. -Jan 2004: updated switches in from-UTF8 conversions. -Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. - -See the header file "ConvertUTF.h" for complete documentation. - ------------------------------------------------------------------------- */ - - -#include "convert_UTF.h" -#ifdef CVTUTF_DEBUG -#include <stdio.h> -#endif - -static const int halfShift = 10; /* used for shifting by 10 bits */ - -static const UTF32 halfBase = 0x0010000UL; -static const UTF32 halfMask = 0x3FFUL; - -#define UNI_SUR_HIGH_START (UTF32)0xD800 -#define UNI_SUR_HIGH_END (UTF32)0xDBFF -#define UNI_SUR_LOW_START (UTF32)0xDC00 -#define UNI_SUR_LOW_END (UTF32)0xDFFF - -#ifndef false -#define false 0 -#endif -#ifndef true -#define true 1 -#endif - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF32* source = *sourceStart; - UTF16* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - if (target >= targetEnd) { - result = targetExhausted; break; - } - ch = *source++; - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = (UTF16)ch; /* normal case */ - } - } else if (ch > UNI_MAX_LEGAL_UTF32) { - if (flags == strictConversion) { - result = sourceIllegal; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - --source; /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); - } - } -*sourceStart = source; -*targetStart = target; -return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF16* source = *sourceStart; - UTF32* target = *targetStart; - UTF32 ch, ch2; - while (source < sourceEnd) { - const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { - ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else { /* We don't have the 16 bits following the high surrogate. */ - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - if (target >= targetEnd) { - source = oldSource; /* Back up source pointer! */ - result = targetExhausted; break; - } - *target++ = ch; - } - *sourceStart = source; - *targetStart = target; -#ifdef CVTUTF_DEBUG - if (result == sourceIllegal) { - fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); - fflush(stderr); - } -#endif - return result; -} - -/* --------------------------------------------------------------------- */ - -/* - * Index into the table below with the first byte of a UTF-8 sequence to - * get the number of trailing bytes that are supposed to follow it. - * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is - * left as-is for anyone who may want to do such conversion, which was - * allowed in earlier algorithms. - */ -static const char trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 -}; - -/* - * Magic values subtracted from a buffer value during UTF8 conversion. - * This table contains as many values as there might be trailing bytes - * in a UTF-8 sequence. - */ -static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; - -/* - * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed - * into the first byte, depending on how many bytes follow. There are - * as many entries in this table as there are UTF-8 sequence types. - * (I.e., one byte sequence, two byte... etc.). Remember that sequencs - * for *legal* UTF-8 will be 4 or fewer bytes total. - */ -static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - -/* --------------------------------------------------------------------- */ - -/* The interface converts a whole buffer to avoid function-call overhead. -* Constants have been gathered. Loops & conditionals have been removed as -* much as possible for efficiency, in favor of drop-through switches. -* (See "Note A" at the bottom of the file for equivalent code.) -* If your compiler supports it, the "isLegalUTF8" call can be turned -* into an inline function. -*/ - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF16* source = *sourceStart; - UTF8* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - unsigned short bytesToWrite = 0; - const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; - const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { - UTF32 ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else { /* We don't have the 16 bits following the high surrogate. */ - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* Figure out how many bytes the result will require */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - } - - target += bytesToWrite; - if (target > targetEnd) { - source = oldSource; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } -*sourceStart = source; -*targetStart = target; -return result; -} - -/* --------------------------------------------------------------------- */ - -/* - * Utility routine to tell whether a sequence of bytes is legal UTF-8. - * This must be called with the length pre-determined by the first byte. - * If not calling this from ConvertUTF8to*, then the length can be set by: - * length = trailingBytesForUTF8[*source]+1; - * and the sequence is illegal right away if there aren't that many bytes - * available. - * If presented with a length > 4, this returns false. The Unicode - * definition of UTF-8 goes up to 4-byte sequences. - */ - -static Boolean isLegalUTF8(const UTF8 *source, int length) { - UTF8 a; - const UTF8 *srcptr = source+length; - switch (length) { - default: return false; - /* Everything else falls through when "true"... */ - case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 2: if ((a = (*--srcptr)) > 0xBF) return false; - - switch (*source) { - /* no fall-through in this inner switch */ - case 0xE0: if (a < 0xA0) return false; break; - case 0xED: if (a > 0x9F) return false; break; - case 0xF0: if (a < 0x90) return false; break; - case 0xF4: if (a > 0x8F) return false; break; - default: if (a < 0x80) return false; - } - - case 1: if (*source >= 0x80 && *source < 0xC2) return false; - } - if (*source > 0xF4) return false; - return true; -} - -/* --------------------------------------------------------------------- */ - -/* - * Exported function to return whether a UTF-8 sequence is legal or not. - * This is not used here; it's just exported. - */ -Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { - int length = trailingBytesForUTF8[*source]+1; - if (source+length > sourceEnd) { - return false; - } - return isLegalUTF8(source, length); -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF8* source = *sourceStart; - UTF16* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = (UTF16)ch; /* normal case */ - } - } else if (ch > UNI_MAX_UTF16) { - if (flags == strictConversion) { - result = sourceIllegal; - source -= (extraBytesToRead+1); /* return to the start */ - break; /* Bail out; shouldn't continue */ - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); - } - } -*sourceStart = source; -*targetStart = target; -return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF32* source = *sourceStart; - UTF8* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - unsigned short bytesToWrite = 0; - const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; - ch = *source++; - if (flags == strictConversion ) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* - * Figure out how many bytes the result will require. Turn any - * illegally large UTF32 things (> Plane 17) into replacement chars. - */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - result = sourceIllegal; - } - - target += bytesToWrite; - if (target > targetEnd) { - --source; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } -*sourceStart = source; -*targetStart = target; -return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF8* source = *sourceStart; - UTF32* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; - case 4: ch += *source++; ch <<= 6; - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up the source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_LEGAL_UTF32) { - /* - * UTF-16 surrogate values are illegal in UTF-32, and anything - * over Plane 17 (> 0x10FFFF) is illegal. - */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = ch; - } - } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ - result = sourceIllegal; - *target++ = UNI_REPLACEMENT_CHAR; - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- - -Note A. -The fall-through switches in UTF-8 reading code save a -temp variable, some decrements & conditionals. The switches -are equivalent to the following loop: -{ - int tmpBytesToRead = extraBytesToRead+1; - do { - ch += *source++; - --tmpBytesToRead; - if (tmpBytesToRead) ch <<= 6; - } while (tmpBytesToRead > 0); -} -In UTF-8 writing code, the switches on "bytesToWrite" are -similarly unrolled loops. - ---------------------------------------------------------------------- */ diff --git a/toolkit/crashreporter/google-breakpad/src/common/convert_UTF.h b/toolkit/crashreporter/google-breakpad/src/common/convert_UTF.h deleted file mode 100644 index 644d09950..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/convert_UTF.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright © 1991-2015 Unicode, Inc. All rights reserved. - * Distributed under the Terms of Use in - * http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of the Unicode data files and any associated documentation - * (the "Data Files") or Unicode software and any associated documentation - * (the "Software") to deal in the Data Files or Software - * without restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, and/or sell copies of - * the Data Files or Software, and to permit persons to whom the Data Files - * or Software are furnished to do so, provided that - * (a) this copyright and permission notice appear with all copies - * of the Data Files or Software, - * (b) this copyright and permission notice appear in associated - * documentation, and - * (c) there is clear notice in each modified Data File or in the Software - * as well as in the documentation associated with the Data File(s) or - * Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE 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 OF THIRD PARTY RIGHTS. - * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS - * NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL - * DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder - * shall not be used in advertising or otherwise to promote the sale, - * use or other dealings in these Data Files or Software without prior - * written authorization of the copyright holder. - */ - -#ifndef COMMON_CONVERT_UTF_H_ -#define COMMON_CONVERT_UTF_H_ - -/* --------------------------------------------------------------------- - -Conversions between UTF32, UTF-16, and UTF-8. Header file. - -Several funtions are included here, forming a complete set of -conversions between the three formats. UTF-7 is not included -here, but is handled in a separate source file. - -Each of these routines takes pointers to input buffers and output -buffers. The input buffers are const. - -Each routine converts the text between *sourceStart and sourceEnd, -putting the result into the buffer between *targetStart and -targetEnd. Note: the end pointers are *after* the last item: e.g. -*(sourceEnd - 1) is the last item. - -The return result indicates whether the conversion was successful, -and if not, whether the problem was in the source or target buffers. -(Only the first encountered problem is indicated.) - -After the conversion, *sourceStart and *targetStart are both -updated to point to the end of last text successfully converted in -the respective buffers. - -Input parameters: -sourceStart - pointer to a pointer to the source buffer. -The contents of this are modified on return so that -it points at the next thing to be converted. -targetStart - similarly, pointer to pointer to the target buffer. -sourceEnd, targetEnd - respectively pointers to the ends of the -two buffers, for overflow checking only. - -These conversion functions take a ConversionFlags argument. When this -flag is set to strict, both irregular sequences and isolated surrogates -will cause an error. When the flag is set to lenient, both irregular -sequences and isolated surrogates are converted. - -Whether the flag is strict or lenient, all illegal sequences will cause -an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>, -or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code -must check for illegal sequences. - -When the flag is set to lenient, characters over 0x10FFFF are converted -to the replacement character; otherwise (when the flag is set to strict) -they constitute an error. - -Output parameters: -The value "sourceIllegal" is returned from some routines if the input -sequence is malformed. When "sourceIllegal" is returned, the source -value will point to the illegal value that caused the problem. E.g., -in UTF-8 when a sequence is malformed, it points to the start of the -malformed sequence. - -Author: Mark E. Davis, 1994. -Rev History: Rick McGowan, fixes & updates May 2001. -Fixes & updates, Sept 2001. - ------------------------------------------------------------------------- */ - -/* --------------------------------------------------------------------- -The following 4 definitions are compiler-specific. -The C standard does not guarantee that wchar_t has at least -16 bits, so wchar_t is no less portable than unsigned short! -All should be unsigned values to avoid sign extension during -bit mask & shift operations. ------------------------------------------------------------------------- */ - -typedef unsigned long UTF32; /* at least 32 bits */ -typedef unsigned short UTF16; /* at least 16 bits */ -typedef unsigned char UTF8; /* typically 8 bits */ -typedef unsigned char Boolean; /* 0 or 1 */ - -/* Some fundamental constants */ -#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD -#define UNI_MAX_BMP (UTF32)0x0000FFFF -#define UNI_MAX_UTF16 (UTF32)0x0010FFFF -#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF -#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF - -typedef enum { - conversionOK, /* conversion successful */ - sourceExhausted, /* partial character in source, but hit end */ - targetExhausted, /* insuff. room in target for conversion */ - sourceIllegal /* source sequence is illegal/malformed */ -} ConversionResult; - -typedef enum { - strictConversion = 0, - lenientConversion -} ConversionFlags; - -/* This is for C++ and does no harm in C */ -#ifdef __cplusplus -extern "C" { -#endif - -ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); - -Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); - -#ifdef __cplusplus -} -#endif - -/* --------------------------------------------------------------------- */ - -#endif // COMMON_CONVERT_UTF_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader-inl.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader-inl.h deleted file mode 100644 index 42c92f943..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader-inl.h +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 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 UTIL_DEBUGINFO_BYTEREADER_INL_H__ -#define UTIL_DEBUGINFO_BYTEREADER_INL_H__ - -#include "common/dwarf/bytereader.h" - -#include <assert.h> -#include <stdint.h> - -namespace dwarf2reader { - -inline uint8 ByteReader::ReadOneByte(const uint8_t *buffer) const { - return buffer[0]; -} - -inline uint16 ByteReader::ReadTwoBytes(const uint8_t *buffer) const { - const uint16 buffer0 = buffer[0]; - const uint16 buffer1 = buffer[1]; - if (endian_ == ENDIANNESS_LITTLE) { - return buffer0 | buffer1 << 8; - } else { - return buffer1 | buffer0 << 8; - } -} - -inline uint64 ByteReader::ReadFourBytes(const uint8_t *buffer) const { - const uint32 buffer0 = buffer[0]; - const uint32 buffer1 = buffer[1]; - const uint32 buffer2 = buffer[2]; - const uint32 buffer3 = buffer[3]; - if (endian_ == ENDIANNESS_LITTLE) { - return buffer0 | buffer1 << 8 | buffer2 << 16 | buffer3 << 24; - } else { - return buffer3 | buffer2 << 8 | buffer1 << 16 | buffer0 << 24; - } -} - -inline uint64 ByteReader::ReadEightBytes(const uint8_t *buffer) const { - const uint64 buffer0 = buffer[0]; - const uint64 buffer1 = buffer[1]; - const uint64 buffer2 = buffer[2]; - const uint64 buffer3 = buffer[3]; - const uint64 buffer4 = buffer[4]; - const uint64 buffer5 = buffer[5]; - const uint64 buffer6 = buffer[6]; - const uint64 buffer7 = buffer[7]; - if (endian_ == ENDIANNESS_LITTLE) { - return buffer0 | buffer1 << 8 | buffer2 << 16 | buffer3 << 24 | - buffer4 << 32 | buffer5 << 40 | buffer6 << 48 | buffer7 << 56; - } else { - return buffer7 | buffer6 << 8 | buffer5 << 16 | buffer4 << 24 | - buffer3 << 32 | buffer2 << 40 | buffer1 << 48 | buffer0 << 56; - } -} - -// Read an unsigned LEB128 number. Each byte contains 7 bits of -// information, plus one bit saying whether the number continues or -// not. - -inline uint64 ByteReader::ReadUnsignedLEB128(const uint8_t *buffer, - size_t* len) const { - uint64 result = 0; - size_t num_read = 0; - unsigned int shift = 0; - uint8_t byte; - - do { - byte = *buffer++; - num_read++; - - result |= (static_cast<uint64>(byte & 0x7f)) << shift; - - shift += 7; - - } while (byte & 0x80); - - *len = num_read; - - return result; -} - -// Read a signed LEB128 number. These are like regular LEB128 -// numbers, except the last byte may have a sign bit set. - -inline int64 ByteReader::ReadSignedLEB128(const uint8_t *buffer, - size_t* len) const { - int64 result = 0; - unsigned int shift = 0; - size_t num_read = 0; - uint8_t byte; - - do { - byte = *buffer++; - num_read++; - result |= (static_cast<uint64>(byte & 0x7f) << shift); - shift += 7; - } while (byte & 0x80); - - if ((shift < 8 * sizeof (result)) && (byte & 0x40)) - result |= -((static_cast<int64>(1)) << shift); - *len = num_read; - return result; -} - -inline uint64 ByteReader::ReadOffset(const uint8_t *buffer) const { - assert(this->offset_reader_); - return (this->*offset_reader_)(buffer); -} - -inline uint64 ByteReader::ReadAddress(const uint8_t *buffer) const { - assert(this->address_reader_); - return (this->*address_reader_)(buffer); -} - -inline void ByteReader::SetCFIDataBase(uint64 section_base, - const uint8_t *buffer_base) { - section_base_ = section_base; - buffer_base_ = buffer_base; - have_section_base_ = true; -} - -inline void ByteReader::SetTextBase(uint64 text_base) { - text_base_ = text_base; - have_text_base_ = true; -} - -inline void ByteReader::SetDataBase(uint64 data_base) { - data_base_ = data_base; - have_data_base_ = true; -} - -inline void ByteReader::SetFunctionBase(uint64 function_base) { - function_base_ = function_base; - have_function_base_ = true; -} - -inline void ByteReader::ClearFunctionBase() { - have_function_base_ = false; -} - -} // namespace dwarf2reader - -#endif // UTIL_DEBUGINFO_BYTEREADER_INL_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.cc deleted file mode 100644 index 14b43adb8..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.cc +++ /dev/null @@ -1,250 +0,0 @@ -// 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. - -#include <assert.h> -#include <stdint.h> -#include <stdlib.h> - -#include "common/dwarf/bytereader-inl.h" -#include "common/dwarf/bytereader.h" - -namespace dwarf2reader { - -ByteReader::ByteReader(enum Endianness endian) - :offset_reader_(NULL), address_reader_(NULL), endian_(endian), - address_size_(0), offset_size_(0), - have_section_base_(), have_text_base_(), have_data_base_(), - have_function_base_() { } - -ByteReader::~ByteReader() { } - -void ByteReader::SetOffsetSize(uint8 size) { - offset_size_ = size; - assert(size == 4 || size == 8); - if (size == 4) { - this->offset_reader_ = &ByteReader::ReadFourBytes; - } else { - this->offset_reader_ = &ByteReader::ReadEightBytes; - } -} - -void ByteReader::SetAddressSize(uint8 size) { - address_size_ = size; - assert(size == 4 || size == 8); - if (size == 4) { - this->address_reader_ = &ByteReader::ReadFourBytes; - } else { - this->address_reader_ = &ByteReader::ReadEightBytes; - } -} - -uint64 ByteReader::ReadInitialLength(const uint8_t *start, size_t* len) { - const uint64 initial_length = ReadFourBytes(start); - start += 4; - - // In DWARF2/3, if the initial length is all 1 bits, then the offset - // size is 8 and we need to read the next 8 bytes for the real length. - if (initial_length == 0xffffffff) { - SetOffsetSize(8); - *len = 12; - return ReadOffset(start); - } else { - SetOffsetSize(4); - *len = 4; - } - return initial_length; -} - -bool ByteReader::ValidEncoding(DwarfPointerEncoding encoding) const { - if (encoding == DW_EH_PE_omit) return true; - if (encoding == DW_EH_PE_aligned) return true; - if ((encoding & 0x7) > DW_EH_PE_udata8) - return false; - if ((encoding & 0x70) > DW_EH_PE_funcrel) - return false; - return true; -} - -bool ByteReader::UsableEncoding(DwarfPointerEncoding encoding) const { - switch (encoding & 0x70) { - case DW_EH_PE_absptr: return true; - case DW_EH_PE_pcrel: return have_section_base_; - case DW_EH_PE_textrel: return have_text_base_; - case DW_EH_PE_datarel: return have_data_base_; - case DW_EH_PE_funcrel: return have_function_base_; - default: return false; - } -} - -uint64 ByteReader::ReadEncodedPointer(const uint8_t *buffer, - DwarfPointerEncoding encoding, - size_t *len) const { - // UsableEncoding doesn't approve of DW_EH_PE_omit, so we shouldn't - // see it here. - assert(encoding != DW_EH_PE_omit); - - // The Linux Standards Base 4.0 does not make this clear, but the - // GNU tools (gcc/unwind-pe.h; readelf/dwarf.c; gdb/dwarf2-frame.c) - // agree that aligned pointers are always absolute, machine-sized, - // machine-signed pointers. - if (encoding == DW_EH_PE_aligned) { - assert(have_section_base_); - - // We don't need to align BUFFER in *our* address space. Rather, we - // need to find the next position in our buffer that would be aligned - // when the .eh_frame section the buffer contains is loaded into the - // program's memory. So align assuming that buffer_base_ gets loaded at - // address section_base_, where section_base_ itself may or may not be - // aligned. - - // First, find the offset to START from the closest prior aligned - // address. - uint64 skew = section_base_ & (AddressSize() - 1); - // Now find the offset from that aligned address to buffer. - uint64 offset = skew + (buffer - buffer_base_); - // Round up to the next boundary. - uint64 aligned = (offset + AddressSize() - 1) & -AddressSize(); - // Convert back to a pointer. - const uint8_t *aligned_buffer = buffer_base_ + (aligned - skew); - // Finally, store the length and actually fetch the pointer. - *len = aligned_buffer - buffer + AddressSize(); - return ReadAddress(aligned_buffer); - } - - // Extract the value first, ignoring whether it's a pointer or an - // offset relative to some base. - uint64 offset; - switch (encoding & 0x0f) { - case DW_EH_PE_absptr: - // DW_EH_PE_absptr is weird, as it is used as a meaningful value for - // both the high and low nybble of encoding bytes. When it appears in - // the high nybble, it means that the pointer is absolute, not an - // offset from some base address. When it appears in the low nybble, - // as here, it means that the pointer is stored as a normal - // machine-sized and machine-signed address. A low nybble of - // DW_EH_PE_absptr does not imply that the pointer is absolute; it is - // correct for us to treat the value as an offset from a base address - // if the upper nybble is not DW_EH_PE_absptr. - offset = ReadAddress(buffer); - *len = AddressSize(); - break; - - case DW_EH_PE_uleb128: - offset = ReadUnsignedLEB128(buffer, len); - break; - - case DW_EH_PE_udata2: - offset = ReadTwoBytes(buffer); - *len = 2; - break; - - case DW_EH_PE_udata4: - offset = ReadFourBytes(buffer); - *len = 4; - break; - - case DW_EH_PE_udata8: - offset = ReadEightBytes(buffer); - *len = 8; - break; - - case DW_EH_PE_sleb128: - offset = ReadSignedLEB128(buffer, len); - break; - - case DW_EH_PE_sdata2: - offset = ReadTwoBytes(buffer); - // Sign-extend from 16 bits. - offset = (offset ^ 0x8000) - 0x8000; - *len = 2; - break; - - case DW_EH_PE_sdata4: - offset = ReadFourBytes(buffer); - // Sign-extend from 32 bits. - offset = (offset ^ 0x80000000ULL) - 0x80000000ULL; - *len = 4; - break; - - case DW_EH_PE_sdata8: - // No need to sign-extend; this is the full width of our type. - offset = ReadEightBytes(buffer); - *len = 8; - break; - - default: - abort(); - } - - // Find the appropriate base address. - uint64 base; - switch (encoding & 0x70) { - case DW_EH_PE_absptr: - base = 0; - break; - - case DW_EH_PE_pcrel: - assert(have_section_base_); - base = section_base_ + (buffer - buffer_base_); - break; - - case DW_EH_PE_textrel: - assert(have_text_base_); - base = text_base_; - break; - - case DW_EH_PE_datarel: - assert(have_data_base_); - base = data_base_; - break; - - case DW_EH_PE_funcrel: - assert(have_function_base_); - base = function_base_; - break; - - default: - abort(); - } - - uint64 pointer = base + offset; - - // Remove inappropriate upper bits. - if (AddressSize() == 4) - pointer = pointer & 0xffffffff; - else - assert(AddressSize() == sizeof(uint64)); - - return pointer; -} - -Endianness ByteReader::GetEndianness() const { - return endian_; -} - -} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.h deleted file mode 100644 index 59d430348..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader.h +++ /dev/null @@ -1,315 +0,0 @@ -// -*- mode: C++ -*- - -// 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_DWARF_BYTEREADER_H__ -#define COMMON_DWARF_BYTEREADER_H__ - -#include <stdint.h> - -#include <string> - -#include "common/dwarf/types.h" -#include "common/dwarf/dwarf2enums.h" - -namespace dwarf2reader { - -// We can't use the obvious name of LITTLE_ENDIAN and BIG_ENDIAN -// because it conflicts with a macro -enum Endianness { - ENDIANNESS_BIG, - ENDIANNESS_LITTLE -}; - -// A ByteReader knows how to read single- and multi-byte values of -// various endiannesses, sizes, and encodings, as used in DWARF -// debugging information and Linux C++ exception handling data. -class ByteReader { - public: - // Construct a ByteReader capable of reading one-, two-, four-, and - // eight-byte values according to ENDIANNESS, absolute machine-sized - // addresses, DWARF-style "initial length" values, signed and - // unsigned LEB128 numbers, and Linux C++ exception handling data's - // encoded pointers. - explicit ByteReader(enum Endianness endianness); - virtual ~ByteReader(); - - // Read a single byte from BUFFER and return it as an unsigned 8 bit - // number. - uint8 ReadOneByte(const uint8_t *buffer) const; - - // Read two bytes from BUFFER and return them as an unsigned 16 bit - // number, using this ByteReader's endianness. - uint16 ReadTwoBytes(const uint8_t *buffer) const; - - // Read four bytes from BUFFER and return them as an unsigned 32 bit - // number, using this ByteReader's endianness. This function returns - // a uint64 so that it is compatible with ReadAddress and - // ReadOffset. The number it returns will never be outside the range - // of an unsigned 32 bit integer. - uint64 ReadFourBytes(const uint8_t *buffer) const; - - // Read eight bytes from BUFFER and return them as an unsigned 64 - // bit number, using this ByteReader's endianness. - uint64 ReadEightBytes(const uint8_t *buffer) const; - - // Read an unsigned LEB128 (Little Endian Base 128) number from - // BUFFER and return it as an unsigned 64 bit integer. Set LEN to - // the number of bytes read. - // - // The unsigned LEB128 representation of an integer N is a variable - // number of bytes: - // - // - If N is between 0 and 0x7f, then its unsigned LEB128 - // representation is a single byte whose value is N. - // - // - Otherwise, its unsigned LEB128 representation is (N & 0x7f) | - // 0x80, followed by the unsigned LEB128 representation of N / - // 128, rounded towards negative infinity. - // - // In other words, we break VALUE into groups of seven bits, put - // them in little-endian order, and then write them as eight-bit - // bytes with the high bit on all but the last. - uint64 ReadUnsignedLEB128(const uint8_t *buffer, size_t *len) const; - - // Read a signed LEB128 number from BUFFER and return it as an - // signed 64 bit integer. Set LEN to the number of bytes read. - // - // The signed LEB128 representation of an integer N is a variable - // number of bytes: - // - // - If N is between -0x40 and 0x3f, then its signed LEB128 - // representation is a single byte whose value is N in two's - // complement. - // - // - Otherwise, its signed LEB128 representation is (N & 0x7f) | - // 0x80, followed by the signed LEB128 representation of N / 128, - // rounded towards negative infinity. - // - // In other words, we break VALUE into groups of seven bits, put - // them in little-endian order, and then write them as eight-bit - // bytes with the high bit on all but the last. - int64 ReadSignedLEB128(const uint8_t *buffer, size_t *len) const; - - // Indicate that addresses on this architecture are SIZE bytes long. SIZE - // must be either 4 or 8. (DWARF allows addresses to be any number of - // bytes in length from 1 to 255, but we only support 32- and 64-bit - // addresses at the moment.) You must call this before using the - // ReadAddress member function. - // - // For data in a .debug_info section, or something that .debug_info - // refers to like line number or macro data, the compilation unit - // header's address_size field indicates the address size to use. Call - // frame information doesn't indicate its address size (a shortcoming of - // the spec); you must supply the appropriate size based on the - // architecture of the target machine. - void SetAddressSize(uint8 size); - - // Return the current address size, in bytes. This is either 4, - // indicating 32-bit addresses, or 8, indicating 64-bit addresses. - uint8 AddressSize() const { return address_size_; } - - // Read an address from BUFFER and return it as an unsigned 64 bit - // integer, respecting this ByteReader's endianness and address size. You - // must call SetAddressSize before calling this function. - uint64 ReadAddress(const uint8_t *buffer) const; - - // DWARF actually defines two slightly different formats: 32-bit DWARF - // and 64-bit DWARF. This is *not* related to the size of registers or - // addresses on the target machine; it refers only to the size of section - // offsets and data lengths appearing in the DWARF data. One only needs - // 64-bit DWARF when the debugging data itself is larger than 4GiB. - // 32-bit DWARF can handle x86_64 or PPC64 code just fine, unless the - // debugging data itself is very large. - // - // DWARF information identifies itself as 32-bit or 64-bit DWARF: each - // compilation unit and call frame information entry begins with an - // "initial length" field, which, in addition to giving the length of the - // data, also indicates the size of section offsets and lengths appearing - // in that data. The ReadInitialLength member function, below, reads an - // initial length and sets the ByteReader's offset size as a side effect. - // Thus, in the normal process of reading DWARF data, the appropriate - // offset size is set automatically. So, you should only need to call - // SetOffsetSize if you are using the same ByteReader to jump from the - // midst of one block of DWARF data into another. - - // Read a DWARF "initial length" field from START, and return it as - // an unsigned 64 bit integer, respecting this ByteReader's - // endianness. Set *LEN to the length of the initial length in - // bytes, either four or twelve. As a side effect, set this - // ByteReader's offset size to either 4 (if we see a 32-bit DWARF - // initial length) or 8 (if we see a 64-bit DWARF initial length). - // - // A DWARF initial length is either: - // - // - a byte count stored as an unsigned 32-bit value less than - // 0xffffff00, indicating that the data whose length is being - // measured uses the 32-bit DWARF format, or - // - // - The 32-bit value 0xffffffff, followed by a 64-bit byte count, - // indicating that the data whose length is being measured uses - // the 64-bit DWARF format. - uint64 ReadInitialLength(const uint8_t *start, size_t *len); - - // Read an offset from BUFFER and return it as an unsigned 64 bit - // integer, respecting the ByteReader's endianness. In 32-bit DWARF, the - // offset is 4 bytes long; in 64-bit DWARF, the offset is eight bytes - // long. You must call ReadInitialLength or SetOffsetSize before calling - // this function; see the comments above for details. - uint64 ReadOffset(const uint8_t *buffer) const; - - // Return the current offset size, in bytes. - // A return value of 4 indicates that we are reading 32-bit DWARF. - // A return value of 8 indicates that we are reading 64-bit DWARF. - uint8 OffsetSize() const { return offset_size_; } - - // Indicate that section offsets and lengths are SIZE bytes long. SIZE - // must be either 4 (meaning 32-bit DWARF) or 8 (meaning 64-bit DWARF). - // Usually, you should not call this function yourself; instead, let a - // call to ReadInitialLength establish the data's offset size - // automatically. - void SetOffsetSize(uint8 size); - - // The Linux C++ ABI uses a variant of DWARF call frame information - // for exception handling. This data is included in the program's - // address space as the ".eh_frame" section, and intepreted at - // runtime to walk the stack, find exception handlers, and run - // cleanup code. The format is mostly the same as DWARF CFI, with - // some adjustments made to provide the additional - // exception-handling data, and to make the data easier to work with - // in memory --- for example, to allow it to be placed in read-only - // memory even when describing position-independent code. - // - // In particular, exception handling data can select a number of - // different encodings for pointers that appear in the data, as - // described by the DwarfPointerEncoding enum. There are actually - // four axes(!) to the encoding: - // - // - The pointer size: pointers can be 2, 4, or 8 bytes long, or use - // the DWARF LEB128 encoding. - // - // - The pointer's signedness: pointers can be signed or unsigned. - // - // - The pointer's base address: the data stored in the exception - // handling data can be the actual address (that is, an absolute - // pointer), or relative to one of a number of different base - // addreses --- including that of the encoded pointer itself, for - // a form of "pc-relative" addressing. - // - // - The pointer may be indirect: it may be the address where the - // true pointer is stored. (This is used to refer to things via - // global offset table entries, program linkage table entries, or - // other tricks used in position-independent code.) - // - // There are also two options that fall outside that matrix - // altogether: the pointer may be omitted, or it may have padding to - // align it on an appropriate address boundary. (That last option - // may seem like it should be just another axis, but it is not.) - - // Indicate that the exception handling data is loaded starting at - // SECTION_BASE, and that the start of its buffer in our own memory - // is BUFFER_BASE. This allows us to find the address that a given - // byte in our buffer would have when loaded into the program the - // data describes. We need this to resolve DW_EH_PE_pcrel pointers. - void SetCFIDataBase(uint64 section_base, const uint8_t *buffer_base); - - // Indicate that the base address of the program's ".text" section - // is TEXT_BASE. We need this to resolve DW_EH_PE_textrel pointers. - void SetTextBase(uint64 text_base); - - // Indicate that the base address for DW_EH_PE_datarel pointers is - // DATA_BASE. The proper value depends on the ABI; it is usually the - // address of the global offset table, held in a designated register in - // position-independent code. You will need to look at the startup code - // for the target system to be sure. I tried; my eyes bled. - void SetDataBase(uint64 data_base); - - // Indicate that the base address for the FDE we are processing is - // FUNCTION_BASE. This is the start address of DW_EH_PE_funcrel - // pointers. (This encoding does not seem to be used by the GNU - // toolchain.) - void SetFunctionBase(uint64 function_base); - - // Indicate that we are no longer processing any FDE, so any use of - // a DW_EH_PE_funcrel encoding is an error. - void ClearFunctionBase(); - - // Return true if ENCODING is a valid pointer encoding. - bool ValidEncoding(DwarfPointerEncoding encoding) const; - - // Return true if we have all the information we need to read a - // pointer that uses ENCODING. This checks that the appropriate - // SetFooBase function for ENCODING has been called. - bool UsableEncoding(DwarfPointerEncoding encoding) const; - - // Read an encoded pointer from BUFFER using ENCODING; return the - // absolute address it represents, and set *LEN to the pointer's - // length in bytes, including any padding for aligned pointers. - // - // This function calls 'abort' if ENCODING is invalid or refers to a - // base address this reader hasn't been given, so you should check - // with ValidEncoding and UsableEncoding first if you would rather - // die in a more helpful way. - uint64 ReadEncodedPointer(const uint8_t *buffer, - DwarfPointerEncoding encoding, - size_t *len) const; - - Endianness GetEndianness() const; - private: - - // Function pointer type for our address and offset readers. - typedef uint64 (ByteReader::*AddressReader)(const uint8_t *) const; - - // Read an offset from BUFFER and return it as an unsigned 64 bit - // integer. DWARF2/3 define offsets as either 4 or 8 bytes, - // generally depending on the amount of DWARF2/3 info present. - // This function pointer gets set by SetOffsetSize. - AddressReader offset_reader_; - - // Read an address from BUFFER and return it as an unsigned 64 bit - // integer. DWARF2/3 allow addresses to be any size from 0-255 - // bytes currently. Internally we support 4 and 8 byte addresses, - // and will CHECK on anything else. - // This function pointer gets set by SetAddressSize. - AddressReader address_reader_; - - Endianness endian_; - uint8 address_size_; - uint8 offset_size_; - - // Base addresses for Linux C++ exception handling data's encoded pointers. - bool have_section_base_, have_text_base_, have_data_base_; - bool have_function_base_; - uint64 section_base_, text_base_, data_base_, function_base_; - const uint8_t *buffer_base_; -}; - -} // namespace dwarf2reader - -#endif // COMMON_DWARF_BYTEREADER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader_unittest.cc deleted file mode 100644 index e66062d1f..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/bytereader_unittest.cc +++ /dev/null @@ -1,707 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// bytereader_unittest.cc: Unit tests for dwarf2reader::ByteReader - -#include <stdint.h> - -#include <string> - -#include "breakpad_googletest_includes.h" -#include "common/dwarf/bytereader.h" -#include "common/dwarf/bytereader-inl.h" -#include "common/dwarf/cfi_assembler.h" -#include "common/using_std_string.h" - -using dwarf2reader::ByteReader; -using dwarf2reader::DwarfPointerEncoding; -using dwarf2reader::ENDIANNESS_BIG; -using dwarf2reader::ENDIANNESS_LITTLE; -using google_breakpad::CFISection; -using google_breakpad::test_assembler::Label; -using google_breakpad::test_assembler::kBigEndian; -using google_breakpad::test_assembler::kLittleEndian; -using google_breakpad::test_assembler::Section; -using testing::Test; - -struct ReaderFixture { - string contents; - size_t pointer_size; -}; - -class Reader: public ReaderFixture, public Test { }; -class ReaderDeathTest: public ReaderFixture, public Test { }; - -TEST_F(Reader, SimpleConstructor) { - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(4); - CFISection section(kBigEndian, 4); - section - .D8(0xc0) - .D16(0xcf0d) - .D32(0x96fdd219) - .D64(0xbbf55fef0825f117ULL) - .ULEB128(0xa0927048ba8121afULL) - .LEB128(-0x4f337badf4483f83LL) - .D32(0xfec319c9); - ASSERT_TRUE(section.GetContents(&contents)); - const uint8_t *data = reinterpret_cast<const uint8_t *>(contents.data()); - EXPECT_EQ(0xc0U, reader.ReadOneByte(data)); - EXPECT_EQ(0xcf0dU, reader.ReadTwoBytes(data + 1)); - EXPECT_EQ(0x96fdd219U, reader.ReadFourBytes(data + 3)); - EXPECT_EQ(0xbbf55fef0825f117ULL, reader.ReadEightBytes(data + 7)); - size_t leb128_size; - EXPECT_EQ(0xa0927048ba8121afULL, - reader.ReadUnsignedLEB128(data + 15, &leb128_size)); - EXPECT_EQ(10U, leb128_size); - EXPECT_EQ(-0x4f337badf4483f83LL, - reader.ReadSignedLEB128(data + 25, &leb128_size)); - EXPECT_EQ(10U, leb128_size); - EXPECT_EQ(0xfec319c9, reader.ReadAddress(data + 35)); -} - -TEST_F(Reader, ValidEncodings) { - ByteReader reader(ENDIANNESS_LITTLE); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_omit))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_aligned))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_pcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_textrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_datarel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_absptr | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_uleb128 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata2 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata4 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_udata8 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sleb128 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata2 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata4 | - dwarf2reader::DW_EH_PE_funcrel))); - EXPECT_TRUE(reader.ValidEncoding( - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect | - dwarf2reader::DW_EH_PE_sdata8 | - dwarf2reader::DW_EH_PE_funcrel))); - - EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x05))); - EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x07))); - EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x0d))); - EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x0f))); - EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x51))); - EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x60))); - EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x70))); - EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0xf0))); - EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0xd0))); -} - -TEST_F(ReaderDeathTest, DW_EH_PE_omit) { - static const uint8_t data[] = { 42 }; - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(4); - EXPECT_DEATH(reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_omit, - &pointer_size), - "encoding != DW_EH_PE_omit"); -} - -TEST_F(Reader, DW_EH_PE_absptr4) { - static const uint8_t data[] = { 0x27, 0x57, 0xea, 0x40 }; - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(4); - EXPECT_EQ(0x40ea5727U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_absptr, - &pointer_size)); - EXPECT_EQ(4U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_absptr8) { - static const uint8_t data[] = { - 0x60, 0x27, 0x57, 0xea, 0x40, 0xc2, 0x98, 0x05, 0x01, 0x50 - }; - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(8); - EXPECT_EQ(0x010598c240ea5727ULL, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_absptr, - &pointer_size)); - EXPECT_EQ(8U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_uleb128) { - static const uint8_t data[] = { 0x81, 0x84, 0x4c }; - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(4); - EXPECT_EQ(0x130201U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_uleb128, - &pointer_size)); - EXPECT_EQ(3U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_udata2) { - static const uint8_t data[] = { 0xf4, 0x8d }; - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(4); - EXPECT_EQ(0xf48dU, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_udata2, - &pointer_size)); - EXPECT_EQ(2U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_udata4) { - static const uint8_t data[] = { 0xb2, 0x68, 0xa5, 0x62, 0x8f, 0x8b }; - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(8); - EXPECT_EQ(0xa5628f8b, - reader.ReadEncodedPointer(data + 2, dwarf2reader::DW_EH_PE_udata4, - &pointer_size)); - EXPECT_EQ(4U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_udata8Addr8) { - static const uint8_t data[] = { - 0x27, 0x04, 0x73, 0x04, 0x69, 0x9f, 0x19, 0xed, 0x8f, 0xfe - }; - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(8); - EXPECT_EQ(0x8fed199f69047304ULL, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_udata8, - &pointer_size)); - EXPECT_EQ(8U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_udata8Addr4) { - static const uint8_t data[] = { - 0x27, 0x04, 0x73, 0x04, 0x69, 0x9f, 0x19, 0xed, 0x8f, 0xfe - }; - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(4); - EXPECT_EQ(0x69047304ULL, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_udata8, - &pointer_size)); - EXPECT_EQ(8U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_sleb128) { - static const uint8_t data[] = { 0x42, 0xff, 0xfb, 0x73 }; - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(4); - EXPECT_EQ(-0x030201U & 0xffffffff, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_sleb128, - &pointer_size)); - EXPECT_EQ(3U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_sdata2) { - static const uint8_t data[] = { 0xb9, 0xbf }; - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(8); - EXPECT_EQ(0xffffffffffffbfb9ULL, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_sdata2, - &pointer_size)); - EXPECT_EQ(2U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_sdata4) { - static const uint8_t data[] = { 0xa0, 0xca, 0xf2, 0xb8, 0xc2, 0xad }; - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(8); - EXPECT_EQ(0xffffffffadc2b8f2ULL, - reader.ReadEncodedPointer(data + 2, dwarf2reader::DW_EH_PE_sdata4, - &pointer_size)); - EXPECT_EQ(4U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_sdata8) { - static const uint8_t data[] = { - 0xf6, 0x66, 0x57, 0x79, 0xe0, 0x0c, 0x9b, 0x26, 0x87 - }; - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(8); - EXPECT_EQ(0x87269b0ce0795766ULL, - reader.ReadEncodedPointer(data + 1, dwarf2reader::DW_EH_PE_sdata8, - &pointer_size)); - EXPECT_EQ(8U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_pcrel) { - static const uint8_t data[] = { - 0x4a, 0x8b, 0x1b, 0x14, 0xc8, 0xc4, 0x02, 0xce - }; - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(4); - DwarfPointerEncoding encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_pcrel - | dwarf2reader::DW_EH_PE_absptr); - reader.SetCFIDataBase(0x89951377, data); - EXPECT_EQ(0x89951377 + 3 + 0x14c8c402, - reader.ReadEncodedPointer(data + 3, encoding, &pointer_size)); - EXPECT_EQ(4U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_textrel) { - static const uint8_t data[] = { - 0xd9, 0x0d, 0x05, 0x17, 0xc9, 0x7a, 0x42, 0x1e - }; - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(4); - reader.SetTextBase(0xb91beaf0); - DwarfPointerEncoding encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel - | dwarf2reader::DW_EH_PE_sdata2); - EXPECT_EQ((0xb91beaf0 + 0xffffc917) & 0xffffffff, - reader.ReadEncodedPointer(data + 3, encoding, &pointer_size)); - EXPECT_EQ(2U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_datarel) { - static const uint8_t data[] = { - 0x16, 0xf2, 0xbb, 0x82, 0x68, 0xa7, 0xbc, 0x39 - }; - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(8); - reader.SetDataBase(0xbef308bd25ce74f0ULL); - DwarfPointerEncoding encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel - | dwarf2reader::DW_EH_PE_sleb128); - EXPECT_EQ(0xbef308bd25ce74f0ULL + 0xfffffffffffa013bULL, - reader.ReadEncodedPointer(data + 2, encoding, &pointer_size)); - EXPECT_EQ(3U, pointer_size); -} - -TEST_F(Reader, DW_EH_PE_funcrel) { - static const uint8_t data[] = { - 0x84, 0xf8, 0x14, 0x01, 0x61, 0xd1, 0x48, 0xc9 - }; - ByteReader reader(ENDIANNESS_BIG); - reader.SetAddressSize(4); - reader.SetFunctionBase(0x823c3520); - DwarfPointerEncoding encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel - | dwarf2reader::DW_EH_PE_udata2); - EXPECT_EQ(0x823c3520 + 0xd148, - reader.ReadEncodedPointer(data + 5, encoding, &pointer_size)); - EXPECT_EQ(2U, pointer_size); -} - -TEST(UsableBase, CFI) { - static const uint8_t data[] = { 0x42 }; - ByteReader reader(ENDIANNESS_BIG); - reader.SetCFIDataBase(0xb31cbd20, data); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); - EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); -} - -TEST(UsableBase, Text) { - ByteReader reader(ENDIANNESS_BIG); - reader.SetTextBase(0xa899ccb9); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); - EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); -} - -TEST(UsableBase, Data) { - ByteReader reader(ENDIANNESS_BIG); - reader.SetDataBase(0xf7b10bcd); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); - EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); -} - -TEST(UsableBase, Function) { - ByteReader reader(ENDIANNESS_BIG); - reader.SetFunctionBase(0xc2c0ed81); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); - EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); -} - -TEST(UsableBase, ClearFunction) { - ByteReader reader(ENDIANNESS_BIG); - reader.SetFunctionBase(0xc2c0ed81); - reader.ClearFunctionBase(); - EXPECT_TRUE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_absptr)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_pcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_textrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_datarel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_funcrel)); - EXPECT_FALSE(reader.UsableEncoding(dwarf2reader::DW_EH_PE_omit)); - EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60))); -} - -struct AlignedFixture { - AlignedFixture() : reader(ENDIANNESS_BIG) { reader.SetAddressSize(4); } - static const uint8_t data[10]; - ByteReader reader; - size_t pointer_size; -}; - -const uint8_t AlignedFixture::data[10] = { - 0xfe, 0x6e, 0x93, 0xd8, 0x34, 0xd5, 0x1c, 0xd3, 0xac, 0x2b -}; - -class Aligned: public AlignedFixture, public Test { }; - -TEST_F(Aligned, DW_EH_PE_aligned0) { - reader.SetCFIDataBase(0xb440305c, data); - EXPECT_EQ(0xfe6e93d8U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, - &pointer_size)); - EXPECT_EQ(4U, pointer_size); -} - -TEST_F(Aligned, DW_EH_PE_aligned1) { - reader.SetCFIDataBase(0xb440305d, data); - EXPECT_EQ(0xd834d51cU, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, - &pointer_size)); - EXPECT_EQ(7U, pointer_size); -} - -TEST_F(Aligned, DW_EH_PE_aligned2) { - reader.SetCFIDataBase(0xb440305e, data); - EXPECT_EQ(0x93d834d5U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, - &pointer_size)); - EXPECT_EQ(6U, pointer_size); -} - -TEST_F(Aligned, DW_EH_PE_aligned3) { - reader.SetCFIDataBase(0xb440305f, data); - EXPECT_EQ(0x6e93d834U, - reader.ReadEncodedPointer(data, dwarf2reader::DW_EH_PE_aligned, - &pointer_size)); - EXPECT_EQ(5U, pointer_size); -} - -TEST_F(Aligned, DW_EH_PE_aligned11) { - reader.SetCFIDataBase(0xb4403061, data); - EXPECT_EQ(0xd834d51cU, - reader.ReadEncodedPointer(data + 1, - dwarf2reader::DW_EH_PE_aligned, - &pointer_size)); - EXPECT_EQ(6U, pointer_size); -} - -TEST_F(Aligned, DW_EH_PE_aligned30) { - reader.SetCFIDataBase(0xb4403063, data); - EXPECT_EQ(0x6e93d834U, - reader.ReadEncodedPointer(data + 1, - dwarf2reader::DW_EH_PE_aligned, - &pointer_size)); - EXPECT_EQ(4U, pointer_size); -} - -TEST_F(Aligned, DW_EH_PE_aligned23) { - reader.SetCFIDataBase(0xb4403062, data); - EXPECT_EQ(0x1cd3ac2bU, - reader.ReadEncodedPointer(data + 3, - dwarf2reader::DW_EH_PE_aligned, - &pointer_size)); - EXPECT_EQ(7U, pointer_size); -} - -TEST_F(Aligned, DW_EH_PE_aligned03) { - reader.SetCFIDataBase(0xb4403064, data); - EXPECT_EQ(0x34d51cd3U, - reader.ReadEncodedPointer(data + 3, - dwarf2reader::DW_EH_PE_aligned, - &pointer_size)); - EXPECT_EQ(5U, pointer_size); -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.cc deleted file mode 100644 index dbc2efae6..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.cc +++ /dev/null @@ -1,198 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// cfi_assembler.cc: Implementation of google_breakpad::CFISection class. -// See cfi_assembler.h for details. - -#include "common/dwarf/cfi_assembler.h" - -#include <assert.h> -#include <stdlib.h> - -namespace google_breakpad { - -using dwarf2reader::DwarfPointerEncoding; - -CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor, - int data_alignment_factor, - unsigned return_address_register, - uint8_t version, - const string &augmentation, - bool dwarf64) { - assert(!entry_length_); - entry_length_ = new PendingLength(); - in_fde_ = false; - - if (dwarf64) { - D32(kDwarf64InitialLengthMarker); - D64(entry_length_->length); - entry_length_->start = Here(); - D64(eh_frame_ ? kEHFrame64CIEIdentifier : kDwarf64CIEIdentifier); - } else { - D32(entry_length_->length); - entry_length_->start = Here(); - D32(eh_frame_ ? kEHFrame32CIEIdentifier : kDwarf32CIEIdentifier); - } - D8(version); - AppendCString(augmentation); - ULEB128(code_alignment_factor); - LEB128(data_alignment_factor); - if (version == 1) - D8(return_address_register); - else - ULEB128(return_address_register); - return *this; -} - -CFISection &CFISection::FDEHeader(Label cie_pointer, - uint64_t initial_location, - uint64_t address_range, - bool dwarf64) { - assert(!entry_length_); - entry_length_ = new PendingLength(); - in_fde_ = true; - fde_start_address_ = initial_location; - - if (dwarf64) { - D32(0xffffffff); - D64(entry_length_->length); - entry_length_->start = Here(); - if (eh_frame_) - D64(Here() - cie_pointer); - else - D64(cie_pointer); - } else { - D32(entry_length_->length); - entry_length_->start = Here(); - if (eh_frame_) - D32(Here() - cie_pointer); - else - D32(cie_pointer); - } - EncodedPointer(initial_location); - // The FDE length in an .eh_frame section uses the same encoding as the - // initial location, but ignores the base address (selected by the upper - // nybble of the encoding), as it's a length, not an address that can be - // made relative. - EncodedPointer(address_range, - DwarfPointerEncoding(pointer_encoding_ & 0x0f)); - return *this; -} - -CFISection &CFISection::FinishEntry() { - assert(entry_length_); - Align(address_size_, dwarf2reader::DW_CFA_nop); - entry_length_->length = Here() - entry_length_->start; - delete entry_length_; - entry_length_ = NULL; - in_fde_ = false; - return *this; -} - -CFISection &CFISection::EncodedPointer(uint64_t address, - DwarfPointerEncoding encoding, - const EncodedPointerBases &bases) { - // Omitted data is extremely easy to emit. - if (encoding == dwarf2reader::DW_EH_PE_omit) - return *this; - - // If (encoding & dwarf2reader::DW_EH_PE_indirect) != 0, then we assume - // that ADDRESS is the address at which the pointer is stored --- in - // other words, that bit has no effect on how we write the pointer. - encoding = DwarfPointerEncoding(encoding & ~dwarf2reader::DW_EH_PE_indirect); - - // Find the base address to which this pointer is relative. The upper - // nybble of the encoding specifies this. - uint64_t base; - switch (encoding & 0xf0) { - case dwarf2reader::DW_EH_PE_absptr: base = 0; break; - case dwarf2reader::DW_EH_PE_pcrel: base = bases.cfi + Size(); break; - case dwarf2reader::DW_EH_PE_textrel: base = bases.text; break; - case dwarf2reader::DW_EH_PE_datarel: base = bases.data; break; - case dwarf2reader::DW_EH_PE_funcrel: base = fde_start_address_; break; - case dwarf2reader::DW_EH_PE_aligned: base = 0; break; - default: abort(); - }; - - // Make ADDRESS relative. Yes, this is appropriate even for "absptr" - // values; see gcc/unwind-pe.h. - address -= base; - - // Align the pointer, if required. - if ((encoding & 0xf0) == dwarf2reader::DW_EH_PE_aligned) - Align(AddressSize()); - - // Append ADDRESS to this section in the appropriate form. For the - // fixed-width forms, we don't need to differentiate between signed and - // unsigned encodings, because ADDRESS has already been extended to 64 - // bits before it was passed to us. - switch (encoding & 0x0f) { - case dwarf2reader::DW_EH_PE_absptr: - Address(address); - break; - - case dwarf2reader::DW_EH_PE_uleb128: - ULEB128(address); - break; - - case dwarf2reader::DW_EH_PE_sleb128: - LEB128(address); - break; - - case dwarf2reader::DW_EH_PE_udata2: - case dwarf2reader::DW_EH_PE_sdata2: - D16(address); - break; - - case dwarf2reader::DW_EH_PE_udata4: - case dwarf2reader::DW_EH_PE_sdata4: - D32(address); - break; - - case dwarf2reader::DW_EH_PE_udata8: - case dwarf2reader::DW_EH_PE_sdata8: - D64(address); - break; - - default: - abort(); - } - - return *this; -}; - -const uint32_t CFISection::kDwarf64InitialLengthMarker; -const uint32_t CFISection::kDwarf32CIEIdentifier; -const uint64_t CFISection::kDwarf64CIEIdentifier; -const uint32_t CFISection::kEHFrame32CIEIdentifier; -const uint64_t CFISection::kEHFrame64CIEIdentifier; - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.h deleted file mode 100644 index 227812b58..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/cfi_assembler.h +++ /dev/null @@ -1,269 +0,0 @@ -// -*- mode: C++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// cfi_assembler.h: Define CFISection, a class for creating properly -// (and improperly) formatted DWARF CFI data for unit tests. - -#ifndef PROCESSOR_CFI_ASSEMBLER_H_ -#define PROCESSOR_CFI_ASSEMBLER_H_ - -#include <string> - -#include "common/dwarf/dwarf2enums.h" -#include "common/test_assembler.h" -#include "common/using_std_string.h" -#include "google_breakpad/common/breakpad_types.h" - -namespace google_breakpad { - -using dwarf2reader::DwarfPointerEncoding; -using google_breakpad::test_assembler::Endianness; -using google_breakpad::test_assembler::Label; -using google_breakpad::test_assembler::Section; - -class CFISection: public Section { - public: - - // CFI augmentation strings beginning with 'z', defined by the - // Linux/IA-64 C++ ABI, can specify interesting encodings for - // addresses appearing in FDE headers and call frame instructions (and - // for additional fields whose presence the augmentation string - // specifies). In particular, pointers can be specified to be relative - // to various base address: the start of the .text section, the - // location holding the address itself, and so on. These allow the - // frame data to be position-independent even when they live in - // write-protected pages. These variants are specified at the - // following two URLs: - // - // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html - // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html - // - // CFISection leaves the production of well-formed 'z'-augmented CIEs and - // FDEs to the user, but does provide EncodedPointer, to emit - // properly-encoded addresses for a given pointer encoding. - // EncodedPointer uses an instance of this structure to find the base - // addresses it should use; you can establish a default for all encoded - // pointers appended to this section with SetEncodedPointerBases. - struct EncodedPointerBases { - EncodedPointerBases() : cfi(), text(), data() { } - - // The starting address of this CFI section in memory, for - // DW_EH_PE_pcrel. DW_EH_PE_pcrel pointers may only be used in data - // that has is loaded into the program's address space. - uint64_t cfi; - - // The starting address of this file's .text section, for DW_EH_PE_textrel. - uint64_t text; - - // The starting address of this file's .got or .eh_frame_hdr section, - // for DW_EH_PE_datarel. - uint64_t data; - }; - - // Create a CFISection whose endianness is ENDIANNESS, and where - // machine addresses are ADDRESS_SIZE bytes long. If EH_FRAME is - // true, use the .eh_frame format, as described by the Linux - // Standards Base Core Specification, instead of the DWARF CFI - // format. - CFISection(Endianness endianness, size_t address_size, - bool eh_frame = false) - : Section(endianness), address_size_(address_size), eh_frame_(eh_frame), - pointer_encoding_(dwarf2reader::DW_EH_PE_absptr), - encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) { - // The 'start', 'Here', and 'Mark' members of a CFISection all refer - // to section offsets. - start() = 0; - } - - // Return this CFISection's address size. - size_t AddressSize() const { return address_size_; } - - // Return true if this CFISection uses the .eh_frame format, or - // false if it contains ordinary DWARF CFI data. - bool ContainsEHFrame() const { return eh_frame_; } - - // Use ENCODING for pointers in calls to FDEHeader and EncodedPointer. - void SetPointerEncoding(DwarfPointerEncoding encoding) { - pointer_encoding_ = encoding; - } - - // Use the addresses in BASES as the base addresses for encoded - // pointers in subsequent calls to FDEHeader or EncodedPointer. - // This function makes a copy of BASES. - void SetEncodedPointerBases(const EncodedPointerBases &bases) { - encoded_pointer_bases_ = bases; - } - - // Append a Common Information Entry header to this section with the - // given values. If dwarf64 is true, use the 64-bit DWARF initial - // length format for the CIE's initial length. Return a reference to - // this section. You should call FinishEntry after writing the last - // instruction for the CIE. - // - // Before calling this function, you will typically want to use Mark - // or Here to make a label to pass to FDEHeader that refers to this - // CIE's position in the section. - CFISection &CIEHeader(uint64_t code_alignment_factor, - int data_alignment_factor, - unsigned return_address_register, - uint8_t version = 3, - const string &augmentation = "", - bool dwarf64 = false); - - // Append a Frame Description Entry header to this section with the - // given values. If dwarf64 is true, use the 64-bit DWARF initial - // length format for the CIE's initial length. Return a reference to - // this section. You should call FinishEntry after writing the last - // instruction for the CIE. - // - // This function doesn't support entries that are longer than - // 0xffffff00 bytes. (The "initial length" is always a 32-bit - // value.) Nor does it support .debug_frame sections longer than - // 0xffffff00 bytes. - CFISection &FDEHeader(Label cie_pointer, - uint64_t initial_location, - uint64_t address_range, - bool dwarf64 = false); - - // Note the current position as the end of the last CIE or FDE we - // started, after padding with DW_CFA_nops for alignment. This - // defines the label representing the entry's length, cited in the - // entry's header. Return a reference to this section. - CFISection &FinishEntry(); - - // Append the contents of BLOCK as a DW_FORM_block value: an - // unsigned LEB128 length, followed by that many bytes of data. - CFISection &Block(const string &block) { - ULEB128(block.size()); - Append(block); - return *this; - } - - // Append ADDRESS to this section, in the appropriate size and - // endianness. Return a reference to this section. - CFISection &Address(uint64_t address) { - Section::Append(endianness(), address_size_, address); - return *this; - } - CFISection &Address(Label address) { - Section::Append(endianness(), address_size_, address); - return *this; - } - - // Append ADDRESS to this section, using ENCODING and BASES. ENCODING - // defaults to this section's default encoding, established by - // SetPointerEncoding. BASES defaults to this section's bases, set by - // SetEncodedPointerBases. If the DW_EH_PE_indirect bit is set in the - // encoding, assume that ADDRESS is where the true address is stored. - // Return a reference to this section. - // - // (C++ doesn't let me use default arguments here, because I want to - // refer to members of *this in the default argument expression.) - CFISection &EncodedPointer(uint64_t address) { - return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_); - } - CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) { - return EncodedPointer(address, encoding, encoded_pointer_bases_); - } - CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding, - const EncodedPointerBases &bases); - - // Restate some member functions, to keep chaining working nicely. - CFISection &Mark(Label *label) { Section::Mark(label); return *this; } - CFISection &D8(uint8_t v) { Section::D8(v); return *this; } - CFISection &D16(uint16_t v) { Section::D16(v); return *this; } - CFISection &D16(Label v) { Section::D16(v); return *this; } - CFISection &D32(uint32_t v) { Section::D32(v); return *this; } - CFISection &D32(const Label &v) { Section::D32(v); return *this; } - CFISection &D64(uint64_t v) { Section::D64(v); return *this; } - CFISection &D64(const Label &v) { Section::D64(v); return *this; } - CFISection &LEB128(long long v) { Section::LEB128(v); return *this; } - CFISection &ULEB128(uint64_t v) { Section::ULEB128(v); return *this; } - - private: - // A length value that we've appended to the section, but is not yet - // known. LENGTH is the appended value; START is a label referring - // to the start of the data whose length was cited. - struct PendingLength { - Label length; - Label start; - }; - - // Constants used in CFI/.eh_frame data: - - // If the first four bytes of an "initial length" are this constant, then - // the data uses the 64-bit DWARF format, and the length itself is the - // subsequent eight bytes. - static const uint32_t kDwarf64InitialLengthMarker = 0xffffffffU; - - // The CIE identifier for 32- and 64-bit DWARF CFI and .eh_frame data. - static const uint32_t kDwarf32CIEIdentifier = ~(uint32_t)0; - static const uint64_t kDwarf64CIEIdentifier = ~(uint64_t)0; - static const uint32_t kEHFrame32CIEIdentifier = 0; - static const uint64_t kEHFrame64CIEIdentifier = 0; - - // The size of a machine address for the data in this section. - size_t address_size_; - - // If true, we are generating a Linux .eh_frame section, instead of - // a standard DWARF .debug_frame section. - bool eh_frame_; - - // The encoding to use for FDE pointers. - DwarfPointerEncoding pointer_encoding_; - - // The base addresses to use when emitting encoded pointers. - EncodedPointerBases encoded_pointer_bases_; - - // The length value for the current entry. - // - // Oddly, this must be dynamically allocated. Labels never get new - // values; they only acquire constraints on the value they already - // have, or assert if you assign them something incompatible. So - // each header needs truly fresh Label objects to cite in their - // headers and track their positions. The alternative is explicit - // destructor invocation and a placement new. Ick. - PendingLength *entry_length_; - - // True if we are currently emitting an FDE --- that is, we have - // called FDEHeader but have not yet called FinishEntry. - bool in_fde_; - - // If in_fde_ is true, this is its starting address. We use this for - // emitting DW_EH_PE_funcrel pointers. - uint64_t fde_start_address_; -}; - -} // namespace google_breakpad - -#endif // PROCESSOR_CFI_ASSEMBLER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.cc deleted file mode 100644 index 94542b5ea..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.cc +++ /dev/null @@ -1,199 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class. -// See dwarf2diehandler.h for details. - -#include <assert.h> -#include <stdint.h> - -#include <string> - -#include "common/dwarf/dwarf2diehandler.h" -#include "common/using_std_string.h" - -namespace dwarf2reader { - -DIEDispatcher::~DIEDispatcher() { - while (!die_handlers_.empty()) { - HandlerStack &entry = die_handlers_.top(); - if (entry.handler_ != root_handler_) - delete entry.handler_; - die_handlers_.pop(); - } -} - -bool DIEDispatcher::StartCompilationUnit(uint64 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version) { - return root_handler_->StartCompilationUnit(offset, address_size, - offset_size, cu_length, - dwarf_version); -} - -bool DIEDispatcher::StartDIE(uint64 offset, enum DwarfTag tag) { - // The stack entry for the parent of this DIE, if there is one. - HandlerStack *parent = die_handlers_.empty() ? NULL : &die_handlers_.top(); - - // Does this call indicate that we're done receiving the parent's - // attributes' values? If so, call its EndAttributes member function. - if (parent && parent->handler_ && !parent->reported_attributes_end_) { - parent->reported_attributes_end_ = true; - if (!parent->handler_->EndAttributes()) { - // Finish off this handler now. and edit *PARENT to indicate that - // we don't want to visit any of the children. - parent->handler_->Finish(); - if (parent->handler_ != root_handler_) - delete parent->handler_; - parent->handler_ = NULL; - return false; - } - } - - // Find a handler for this DIE. - DIEHandler *handler; - if (parent) { - if (parent->handler_) - // Ask the parent to find a handler. - handler = parent->handler_->FindChildHandler(offset, tag); - else - // No parent handler means we're not interested in any of our - // children. - handler = NULL; - } else { - // This is the root DIE. For a non-root DIE, the parent's handler - // decides whether to visit it, but the root DIE has no parent - // handler, so we have a special method on the root DIE handler - // itself to decide. - if (root_handler_->StartRootDIE(offset, tag)) - handler = root_handler_; - else - handler = NULL; - } - - // Push a handler stack entry for this new handler. As an - // optimization, we don't push NULL-handler entries on top of other - // NULL-handler entries; we just let the oldest such entry stand for - // the whole subtree. - if (handler || !parent || parent->handler_) { - HandlerStack entry; - entry.offset_ = offset; - entry.handler_ = handler; - entry.reported_attributes_end_ = false; - die_handlers_.push(entry); - } - - return handler != NULL; -} - -void DIEDispatcher::EndDIE(uint64 offset) { - assert(!die_handlers_.empty()); - HandlerStack *entry = &die_handlers_.top(); - if (entry->handler_) { - // This entry had better be the handler for this DIE. - assert(entry->offset_ == offset); - // If a DIE has no children, this EndDIE call indicates that we're - // done receiving its attributes' values. - if (!entry->reported_attributes_end_) - entry->handler_->EndAttributes(); // Ignore return value: no children. - entry->handler_->Finish(); - if (entry->handler_ != root_handler_) - delete entry->handler_; - } else { - // If this DIE is within a tree we're ignoring, then don't pop the - // handler stack: that entry stands for the whole tree. - if (entry->offset_ != offset) - return; - } - die_handlers_.pop(); -} - -void DIEDispatcher::ProcessAttributeUnsigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - HandlerStack ¤t = die_handlers_.top(); - // This had better be an attribute of the DIE we were meant to handle. - assert(offset == current.offset_); - current.handler_->ProcessAttributeUnsigned(attr, form, data); -} - -void DIEDispatcher::ProcessAttributeSigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { - HandlerStack ¤t = die_handlers_.top(); - // This had better be an attribute of the DIE we were meant to handle. - assert(offset == current.offset_); - current.handler_->ProcessAttributeSigned(attr, form, data); -} - -void DIEDispatcher::ProcessAttributeReference(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - HandlerStack ¤t = die_handlers_.top(); - // This had better be an attribute of the DIE we were meant to handle. - assert(offset == current.offset_); - current.handler_->ProcessAttributeReference(attr, form, data); -} - -void DIEDispatcher::ProcessAttributeBuffer(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const uint8_t *data, - uint64 len) { - HandlerStack ¤t = die_handlers_.top(); - // This had better be an attribute of the DIE we were meant to handle. - assert(offset == current.offset_); - current.handler_->ProcessAttributeBuffer(attr, form, data, len); -} - -void DIEDispatcher::ProcessAttributeString(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const string& data) { - HandlerStack ¤t = die_handlers_.top(); - // This had better be an attribute of the DIE we were meant to handle. - assert(offset == current.offset_); - current.handler_->ProcessAttributeString(attr, form, data); -} - -void DIEDispatcher::ProcessAttributeSignature(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 signature) { - HandlerStack ¤t = die_handlers_.top(); - // This had better be an attribute of the DIE we were meant to handle. - assert(offset == current.offset_); - current.handler_->ProcessAttributeSignature(attr, form, signature); -} - -} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.h deleted file mode 100644 index a1e589a86..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler.h +++ /dev/null @@ -1,365 +0,0 @@ -// -*- mode: c++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf2reader::CompilationUnit is a simple and direct parser for -// DWARF data, but its handler interface is not convenient to use. In -// particular: -// -// - CompilationUnit calls Dwarf2Handler's member functions to report -// every attribute's value, regardless of what sort of DIE it is. -// As a result, the ProcessAttributeX functions end up looking like -// this: -// -// switch (parent_die_tag) { -// case DW_TAG_x: -// switch (attribute_name) { -// case DW_AT_y: -// handle attribute y of DIE type x -// ... -// } break; -// ... -// } -// -// In C++ it's much nicer to use virtual function dispatch to find -// the right code for a given case than to switch on the DIE tag -// like this. -// -// - Processing different kinds of DIEs requires different sets of -// data: lexical block DIEs have start and end addresses, but struct -// type DIEs don't. It would be nice to be able to have separate -// handler classes for separate kinds of DIEs, each with the members -// appropriate to its role, instead of having one handler class that -// needs to hold data for every DIE type. -// -// - There should be a separate instance of the appropriate handler -// class for each DIE, instead of a single object with tables -// tracking all the dies in the compilation unit. -// -// - It's not convenient to take some action after all a DIE's -// attributes have been seen, but before visiting any of its -// children. The only indication you have that a DIE's attribute -// list is complete is that you get either a StartDIE or an EndDIE -// call. -// -// - It's not convenient to make use of the tree structure of the -// DIEs. Skipping all the children of a given die requires -// maintaining state and returning false from StartDIE until we get -// an EndDIE call with the appropriate offset. -// -// This interface tries to take care of all that. (You're shocked, I'm sure.) -// -// Using the classes here, you provide an initial handler for the root -// DIE of the compilation unit. Each handler receives its DIE's -// attributes, and provides fresh handler objects for children of -// interest, if any. The three classes are: -// -// - DIEHandler: the base class for your DIE-type-specific handler -// classes. -// -// - RootDIEHandler: derived from DIEHandler, the base class for your -// root DIE handler class. -// -// - DIEDispatcher: derived from Dwarf2Handler, an instance of this -// invokes your DIE-type-specific handler objects. -// -// In detail: -// -// - Define handler classes specialized for the DIE types you're -// interested in. These handler classes must inherit from -// DIEHandler. Thus: -// -// class My_DW_TAG_X_Handler: public DIEHandler { ... }; -// class My_DW_TAG_Y_Handler: public DIEHandler { ... }; -// -// DIEHandler subclasses needn't correspond exactly to single DIE -// types, as shown here; the point is that you can have several -// different classes appropriate to different kinds of DIEs. -// -// - In particular, define a handler class for the compilation -// unit's root DIE, that inherits from RootDIEHandler: -// -// class My_DW_TAG_compile_unit_Handler: public RootDIEHandler { ... }; -// -// RootDIEHandler inherits from DIEHandler, adding a few additional -// member functions for examining the compilation unit as a whole, -// and other quirks of rootness. -// -// - Then, create a DIEDispatcher instance, passing it an instance of -// your root DIE handler class, and use that DIEDispatcher as the -// dwarf2reader::CompilationUnit's handler: -// -// My_DW_TAG_compile_unit_Handler root_die_handler(...); -// DIEDispatcher die_dispatcher(&root_die_handler); -// CompilationUnit reader(sections, offset, bytereader, &die_dispatcher); -// -// Here, 'die_dispatcher' acts as a shim between 'reader' and the -// various DIE-specific handlers you have defined. -// -// - When you call reader.Start(), die_dispatcher behaves as follows, -// starting with your root die handler and the compilation unit's -// root DIE: -// -// - It calls the handler's ProcessAttributeX member functions for -// each of the DIE's attributes. -// -// - It calls the handler's EndAttributes member function. This -// should return true if any of the DIE's children should be -// visited, in which case: -// -// - For each of the DIE's children, die_dispatcher calls the -// DIE's handler's FindChildHandler member function. If that -// returns a pointer to a DIEHandler instance, then -// die_dispatcher uses that handler to process the child, using -// this procedure recursively. Alternatively, if -// FindChildHandler returns NULL, die_dispatcher ignores that -// child and its descendants. -// -// - When die_dispatcher has finished processing all the DIE's -// children, it invokes the handler's Finish() member function, -// and destroys the handler. (As a special case, it doesn't -// destroy the root DIE handler.) -// -// This allows the code for handling a particular kind of DIE to be -// gathered together in a single class, makes it easy to skip all the -// children or individual children of a particular DIE, and provides -// appropriate parental context for each die. - -#ifndef COMMON_DWARF_DWARF2DIEHANDLER_H__ -#define COMMON_DWARF_DWARF2DIEHANDLER_H__ - -#include <stdint.h> - -#include <stack> -#include <string> - -#include "common/dwarf/types.h" -#include "common/dwarf/dwarf2enums.h" -#include "common/dwarf/dwarf2reader.h" -#include "common/using_std_string.h" - -namespace dwarf2reader { - -// A base class for handlers for specific DIE types. The series of -// calls made on a DIE handler is as follows: -// -// - for each attribute of the DIE: -// - ProcessAttributeX() -// - EndAttributes() -// - if that returned true, then for each child: -// - FindChildHandler() -// - if that returns a non-NULL pointer to a new handler: -// - recurse, with the new handler and the child die -// - Finish() -// - destruction -class DIEHandler { - public: - DIEHandler() { } - virtual ~DIEHandler() { } - - // When we visit a DIE, we first use these member functions to - // report the DIE's attributes and their values. These have the - // same restrictions as the corresponding member functions of - // dwarf2reader::Dwarf2Handler. - // - // Since DWARF does not specify in what order attributes must - // appear, avoid making decisions in these functions that would be - // affected by the presence of other attributes. The EndAttributes - // function is a more appropriate place for such work, as all the - // DIE's attributes have been seen at that point. - // - // The default definitions ignore the values they are passed. - virtual void ProcessAttributeUnsigned(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { } - virtual void ProcessAttributeSigned(enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { } - virtual void ProcessAttributeReference(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { } - virtual void ProcessAttributeBuffer(enum DwarfAttribute attr, - enum DwarfForm form, - const uint8_t *data, - uint64 len) { } - virtual void ProcessAttributeString(enum DwarfAttribute attr, - enum DwarfForm form, - const string& data) { } - virtual void ProcessAttributeSignature(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 signture) { } - - // Once we have reported all the DIE's attributes' values, we call - // this member function. If it returns false, we skip all the DIE's - // children. If it returns true, we call FindChildHandler on each - // child. If that returns a handler object, we use that to visit - // the child; otherwise, we skip the child. - // - // This is a good place to make decisions that depend on more than - // one attribute. DWARF does not specify in what order attributes - // must appear, so only when the EndAttributes function is called - // does the handler have a complete picture of the DIE's attributes. - // - // The default definition elects to ignore the DIE's children. - // You'll need to override this if you override FindChildHandler, - // but at least the default behavior isn't to pass the children to - // FindChildHandler, which then ignores them all. - virtual bool EndAttributes() { return false; } - - // If EndAttributes returns true to indicate that some of the DIE's - // children might be of interest, then we apply this function to - // each of the DIE's children. If it returns a handler object, then - // we use that to visit the child DIE. If it returns NULL, we skip - // that child DIE (and all its descendants). - // - // OFFSET is the offset of the child; TAG indicates what kind of DIE - // it is. - // - // The default definition skips all children. - virtual DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag) { - return NULL; - } - - // When we are done processing a DIE, we call this member function. - // This happens after the EndAttributes call, all FindChildHandler - // calls (if any), and all operations on the children themselves (if - // any). We call Finish on every handler --- even if EndAttributes - // returns false. - virtual void Finish() { }; -}; - -// A subclass of DIEHandler, with additional kludges for handling the -// compilation unit's root die. -class RootDIEHandler: public DIEHandler { - public: - RootDIEHandler() { } - virtual ~RootDIEHandler() { } - - // We pass the values reported via Dwarf2Handler::StartCompilationUnit - // to this member function, and skip the entire compilation unit if it - // returns false. So the root DIE handler is actually also - // responsible for handling the compilation unit metadata. - // The default definition always visits the compilation unit. - virtual bool StartCompilationUnit(uint64 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version) { return true; } - - // For the root DIE handler only, we pass the offset, tag and - // attributes of the compilation unit's root DIE. This is the only - // way the root DIE handler can find the root DIE's tag. If this - // function returns true, we will visit the root DIE using the usual - // DIEHandler methods; otherwise, we skip the entire compilation - // unit. - // - // The default definition elects to visit the root DIE. - virtual bool StartRootDIE(uint64 offset, enum DwarfTag tag) { return true; } -}; - -class DIEDispatcher: public Dwarf2Handler { - public: - // Create a Dwarf2Handler which uses ROOT_HANDLER as the handler for - // the compilation unit's root die, as described for the DIEHandler - // class. - DIEDispatcher(RootDIEHandler *root_handler) : root_handler_(root_handler) { } - // Destroying a DIEDispatcher destroys all active handler objects - // except the root handler. - ~DIEDispatcher(); - bool StartCompilationUnit(uint64 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version); - bool StartDIE(uint64 offset, enum DwarfTag tag); - void ProcessAttributeUnsigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - void ProcessAttributeSigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data); - void ProcessAttributeReference(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - void ProcessAttributeBuffer(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const uint8_t *data, - uint64 len); - void ProcessAttributeString(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const string &data); - void ProcessAttributeSignature(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 signature); - void EndDIE(uint64 offset); - - private: - - // The type of a handler stack entry. This includes some fields - // which don't really need to be on the stack --- they could just be - // single data members of DIEDispatcher --- but putting them here - // makes it easier to see that the code is correct. - struct HandlerStack { - // The offset of the DIE for this handler stack entry. - uint64 offset_; - - // The handler object interested in this DIE's attributes and - // children. If NULL, we're not interested in either. - DIEHandler *handler_; - - // Have we reported the end of this DIE's attributes to the handler? - bool reported_attributes_end_; - }; - - // Stack of DIE attribute handlers. At StartDIE(D), the top of the - // stack is the handler of D's parent, whom we may ask for a handler - // for D itself. At EndDIE(D), the top of the stack is D's handler. - // Special cases: - // - // - Before we've seen the compilation unit's root DIE, the stack is - // empty; we'll call root_handler_'s special member functions, and - // perhaps push root_handler_ on the stack to look at the root's - // immediate children. - // - // - When we decide to ignore a subtree, we only push an entry on - // the stack for the root of the tree being ignored, rather than - // pushing lots of stack entries with handler_ set to NULL. - std::stack<HandlerStack> die_handlers_; - - // The root handler. We don't push it on die_handlers_ until we - // actually get the StartDIE call for the root. - RootDIEHandler *root_handler_; -}; - -} // namespace dwarf2reader -#endif // COMMON_DWARF_DWARF2DIEHANDLER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc deleted file mode 100644 index db70eb31b..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc +++ /dev/null @@ -1,527 +0,0 @@ -// -*- mode: c++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher. - -#include <stdint.h> - -#include <string> -#include <utility> - -#include "breakpad_googletest_includes.h" - -#include "common/dwarf/dwarf2diehandler.h" -#include "common/using_std_string.h" - -using std::make_pair; - -using ::testing::_; -using ::testing::ContainerEq; -using ::testing::ElementsAreArray; -using ::testing::Eq; -using ::testing::InSequence; -using ::testing::Return; -using ::testing::Sequence; -using ::testing::StrEq; - -using dwarf2reader::DIEDispatcher; -using dwarf2reader::DIEHandler; -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfTag; -using dwarf2reader::RootDIEHandler; - -class MockDIEHandler: public DIEHandler { - public: - MOCK_METHOD3(ProcessAttributeUnsigned, - void(DwarfAttribute, DwarfForm, uint64)); - MOCK_METHOD3(ProcessAttributeSigned, - void(DwarfAttribute, DwarfForm, int64)); - MOCK_METHOD3(ProcessAttributeReference, - void(DwarfAttribute, DwarfForm, uint64)); - MOCK_METHOD4(ProcessAttributeBuffer, - void(DwarfAttribute, DwarfForm, const uint8_t *, uint64)); - MOCK_METHOD3(ProcessAttributeString, - void(DwarfAttribute, DwarfForm, const string &)); - MOCK_METHOD3(ProcessAttributeSignature, - void(DwarfAttribute, DwarfForm, uint64)); - MOCK_METHOD0(EndAttributes, bool()); - MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag)); - MOCK_METHOD0(Finish, void()); -}; - -class MockRootDIEHandler: public RootDIEHandler { - public: - MOCK_METHOD3(ProcessAttributeUnsigned, - void(DwarfAttribute, DwarfForm, uint64)); - MOCK_METHOD3(ProcessAttributeSigned, - void(DwarfAttribute, DwarfForm, int64)); - MOCK_METHOD3(ProcessAttributeReference, - void(DwarfAttribute, DwarfForm, uint64)); - MOCK_METHOD4(ProcessAttributeBuffer, - void(DwarfAttribute, DwarfForm, const uint8_t *, uint64)); - MOCK_METHOD3(ProcessAttributeString, - void(DwarfAttribute, DwarfForm, const string &)); - MOCK_METHOD3(ProcessAttributeSignature, - void(DwarfAttribute, DwarfForm, uint64)); - MOCK_METHOD0(EndAttributes, bool()); - MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag)); - MOCK_METHOD0(Finish, void()); - MOCK_METHOD5(StartCompilationUnit, bool(uint64, uint8, uint8, uint64, uint8)); - MOCK_METHOD2(StartRootDIE, bool(uint64, DwarfTag)); -}; - -// If the handler elects to skip the compilation unit, the dispatcher -// should tell the reader so. -TEST(Dwarf2DIEHandler, SkipCompilationUnit) { - Sequence s; - MockRootDIEHandler mock_root_handler; - DIEDispatcher die_dispatcher(&mock_root_handler); - - EXPECT_CALL(mock_root_handler, - StartCompilationUnit(0x8d42aed77cfccf3eLL, - 0x89, 0xdc, - 0x2ecb4dc778a80f21LL, - 0x66)) - .InSequence(s) - .WillOnce(Return(false)); - - EXPECT_FALSE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL, - 0x89, 0xdc, - 0x2ecb4dc778a80f21LL, - 0x66)); -} - -// If the handler elects to skip the root DIE, the dispatcher should -// tell the reader so. -TEST(Dwarf2DIEHandler, SkipRootDIE) { - Sequence s; - MockRootDIEHandler mock_root_handler; - DIEDispatcher die_dispatcher(&mock_root_handler); - - EXPECT_CALL(mock_root_handler, - StartCompilationUnit(0xde8994029fc8b999LL, 0xf4, 0x02, - 0xb00febffa76e2b2bLL, 0x5c)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(mock_root_handler, - StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6)) - .InSequence(s) - .WillOnce(Return(false)); - - EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0xde8994029fc8b999LL, - 0xf4, 0x02, - 0xb00febffa76e2b2bLL, 0x5c)); - EXPECT_FALSE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL, - (DwarfTag) 0xb4f98da6)); - die_dispatcher.EndDIE(0x7d08242b4b510cf2LL); -} - -// If the handler elects to skip the root DIE's children, the -// dispatcher should tell the reader so --- and avoid deleting the -// root handler. -TEST(Dwarf2DIEHandler, SkipRootDIEChildren) { - MockRootDIEHandler mock_root_handler; - DIEDispatcher die_dispatcher(&mock_root_handler); - - { - InSequence s; - - EXPECT_CALL(mock_root_handler, - StartCompilationUnit(0x15d6897480cc65a7LL, 0x26, 0xa0, - 0x09f8bf0767f91675LL, 0xdb)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_root_handler, - StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6)) - .WillOnce(Return(true)); - // Please don't tell me about my children. - EXPECT_CALL(mock_root_handler, EndAttributes()) - .WillOnce(Return(false)); - EXPECT_CALL(mock_root_handler, Finish()) - .WillOnce(Return()); - } - - EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x15d6897480cc65a7LL, - 0x26, 0xa0, - 0x09f8bf0767f91675LL, 0xdb)); - EXPECT_TRUE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL, - (DwarfTag) 0xb4f98da6)); - EXPECT_FALSE(die_dispatcher.StartDIE(0x435150ceedccda18LL, - (DwarfTag) 0xc3a17bba)); - die_dispatcher.EndDIE(0x435150ceedccda18LL); - die_dispatcher.EndDIE(0x7d08242b4b510cf2LL); -} - -// The dispatcher should pass attribute values through to the die -// handler accurately. -TEST(Dwarf2DIEHandler, PassAttributeValues) { - MockRootDIEHandler mock_root_handler; - DIEDispatcher die_dispatcher(&mock_root_handler); - - const uint8_t buffer[10] = { - 0x24, 0x24, 0x35, 0x9a, 0xca, 0xcf, 0xa8, 0x84, 0xa7, 0x18 - }; - string str = "\xc8\x26\x2e\x0d\xa4\x9c\x37\xd6\xfb\x1d"; - - // Set expectations. - { - InSequence s; - - // We'll like the compilation unit header. - EXPECT_CALL(mock_root_handler, - StartCompilationUnit(0x8d42aed77cfccf3eLL, 0x89, 0xdc, - 0x2ecb4dc778a80f21LL, 0x66)) - .WillOnce(Return(true)); - - // We'll like the root DIE. - EXPECT_CALL(mock_root_handler, - StartRootDIE(0xe2222da01e29f2a9LL, (DwarfTag) 0x9829445c)) - .WillOnce(Return(true)); - - // Expect some attribute values. - EXPECT_CALL(mock_root_handler, - ProcessAttributeUnsigned((DwarfAttribute) 0x1cc0bfed, - (DwarfForm) 0x424f1468, - 0xa592571997facda1ULL)) - .WillOnce(Return()); - EXPECT_CALL(mock_root_handler, - ProcessAttributeSigned((DwarfAttribute) 0x43694dc9, - (DwarfForm) 0xf6f78901L, - 0x92602a4e3bf1f446LL)) - .WillOnce(Return()); - EXPECT_CALL(mock_root_handler, - ProcessAttributeReference((DwarfAttribute) 0x4033e8cL, - (DwarfForm) 0xf66fbe0bL, - 0x50fddef44734fdecULL)) - .WillOnce(Return()); - EXPECT_CALL(mock_root_handler, - ProcessAttributeBuffer((DwarfAttribute) 0x25d7e0af, - (DwarfForm) 0xe99a539a, - buffer, sizeof(buffer))) - .WillOnce(Return()); - EXPECT_CALL(mock_root_handler, - ProcessAttributeString((DwarfAttribute) 0x310ed065, - (DwarfForm) 0x15762fec, - StrEq(str))) - .WillOnce(Return()); - EXPECT_CALL(mock_root_handler, - ProcessAttributeSignature((DwarfAttribute) 0x58790d72, - (DwarfForm) 0x4159f138, - 0x94682463613e6a5fULL)) - .WillOnce(Return()); - EXPECT_CALL(mock_root_handler, EndAttributes()) - .WillOnce(Return(true)); - EXPECT_CALL(mock_root_handler, FindChildHandler(_, _)) - .Times(0); - EXPECT_CALL(mock_root_handler, Finish()) - .WillOnce(Return()); - } - - // Drive the dispatcher. - - // Report the CU header. - EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL, - 0x89, 0xdc, - 0x2ecb4dc778a80f21LL, - 0x66)); - // Report the root DIE. - EXPECT_TRUE(die_dispatcher.StartDIE(0xe2222da01e29f2a9LL, - (DwarfTag) 0x9829445c)); - - // Report some attribute values. - die_dispatcher.ProcessAttributeUnsigned(0xe2222da01e29f2a9LL, - (DwarfAttribute) 0x1cc0bfed, - (DwarfForm) 0x424f1468, - 0xa592571997facda1ULL); - die_dispatcher.ProcessAttributeSigned(0xe2222da01e29f2a9LL, - (DwarfAttribute) 0x43694dc9, - (DwarfForm) 0xf6f78901, - 0x92602a4e3bf1f446LL); - die_dispatcher.ProcessAttributeReference(0xe2222da01e29f2a9LL, - (DwarfAttribute) 0x4033e8c, - (DwarfForm) 0xf66fbe0b, - 0x50fddef44734fdecULL); - die_dispatcher.ProcessAttributeBuffer(0xe2222da01e29f2a9LL, - (DwarfAttribute) 0x25d7e0af, - (DwarfForm) 0xe99a539a, - buffer, sizeof(buffer)); - die_dispatcher.ProcessAttributeString(0xe2222da01e29f2a9LL, - (DwarfAttribute) 0x310ed065, - (DwarfForm) 0x15762fec, - str); - die_dispatcher.ProcessAttributeSignature(0xe2222da01e29f2a9LL, - (DwarfAttribute) 0x58790d72, - (DwarfForm) 0x4159f138, - 0x94682463613e6a5fULL); - - // Finish the root DIE (and thus the CU). - die_dispatcher.EndDIE(0xe2222da01e29f2a9LL); -} - -TEST(Dwarf2DIEHandler, FindAndSkipChildren) { - MockRootDIEHandler mock_root_handler; - MockDIEHandler *mock_child1_handler = new(MockDIEHandler); - MockDIEHandler *mock_child3_handler = new(MockDIEHandler); - DIEDispatcher die_dispatcher(&mock_root_handler); - - { - InSequence s; - - // We'll like the compilation unit header. - EXPECT_CALL(mock_root_handler, - StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21, - 0x47dd3c764275a216LL, 0xa5)) - .WillOnce(Return(true)); - - // Root DIE. - { - EXPECT_CALL(mock_root_handler, - StartRootDIE(0x15f0e06bdfe3c372LL, (DwarfTag) 0xf5d60c59)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_root_handler, - ProcessAttributeSigned((DwarfAttribute) 0xf779a642, - (DwarfForm) 0x2cb63027, - 0x18e744661769d08fLL)) - .WillOnce(Return()); - EXPECT_CALL(mock_root_handler, EndAttributes()) - .WillOnce(Return(true)); - - // First child DIE. - EXPECT_CALL(mock_root_handler, - FindChildHandler(0x149f644f8116fe8cLL, - (DwarfTag) 0xac2cbd8c)) - .WillOnce(Return(mock_child1_handler)); - { - EXPECT_CALL(*mock_child1_handler, - ProcessAttributeSigned((DwarfAttribute) 0xa6fd6f65, - (DwarfForm) 0xe4f64c41, - 0x1b04e5444a55fe67LL)) - .WillOnce(Return()); - EXPECT_CALL(*mock_child1_handler, EndAttributes()) - .WillOnce(Return(false)); - // Skip first grandchild DIE and first great-grandchild DIE. - EXPECT_CALL(*mock_child1_handler, Finish()) - .WillOnce(Return()); - } - - // Second child DIE. Root handler will decline to return a handler - // for this child. - EXPECT_CALL(mock_root_handler, - FindChildHandler(0x97412be24875de9dLL, - (DwarfTag) 0x505a068b)) - .WillOnce(Return((DIEHandler *) NULL)); - - // Third child DIE. - EXPECT_CALL(mock_root_handler, - FindChildHandler(0x753c964c8ab538aeLL, - (DwarfTag) 0x8c22970e)) - .WillOnce(Return(mock_child3_handler)); - { - EXPECT_CALL(*mock_child3_handler, - ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb, - (DwarfForm) 0x610b7ae1, - 0x3ea5c609d7d7560fLL)) - .WillOnce(Return()); - EXPECT_CALL(*mock_child3_handler, EndAttributes()) - .WillOnce(Return(true)); - EXPECT_CALL(*mock_child3_handler, Finish()) - .WillOnce(Return()); - } - - EXPECT_CALL(mock_root_handler, Finish()) - .WillOnce(Return()); - } - } - - - // Drive the dispatcher. - - // Report the CU header. - EXPECT_TRUE(die_dispatcher - .StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21, - 0x47dd3c764275a216LL, 0xa5)); - // Report the root DIE. - { - EXPECT_TRUE(die_dispatcher.StartDIE(0x15f0e06bdfe3c372LL, - (DwarfTag) 0xf5d60c59)); - die_dispatcher.ProcessAttributeSigned(0x15f0e06bdfe3c372LL, - (DwarfAttribute) 0xf779a642, - (DwarfForm) 0x2cb63027, - 0x18e744661769d08fLL); - - // First child DIE. - { - EXPECT_TRUE(die_dispatcher.StartDIE(0x149f644f8116fe8cLL, - (DwarfTag) 0xac2cbd8c)); - die_dispatcher.ProcessAttributeSigned(0x149f644f8116fe8cLL, - (DwarfAttribute) 0xa6fd6f65, - (DwarfForm) 0xe4f64c41, - 0x1b04e5444a55fe67LL); - - // First grandchild DIE. Will be skipped. - { - EXPECT_FALSE(die_dispatcher.StartDIE(0xd68de1ee0bd29419LL, - (DwarfTag) 0x22f05a15)); - // First great-grandchild DIE. Will be skipped without being - // mentioned to any handler. - { - EXPECT_FALSE(die_dispatcher - .StartDIE(0xb3076285d25cac25LL, - (DwarfTag) 0xcff4061b)); - die_dispatcher.EndDIE(0xb3076285d25cac25LL); - } - die_dispatcher.EndDIE(0xd68de1ee0bd29419LL); - } - die_dispatcher.EndDIE(0x149f644f8116fe8cLL); - } - - // Second child DIE. Root handler will decline to find a handler for it. - { - EXPECT_FALSE(die_dispatcher.StartDIE(0x97412be24875de9dLL, - (DwarfTag) 0x505a068b)); - die_dispatcher.EndDIE(0x97412be24875de9dLL); - } - - // Third child DIE. - { - EXPECT_TRUE(die_dispatcher.StartDIE(0x753c964c8ab538aeLL, - (DwarfTag) 0x8c22970e)); - die_dispatcher.ProcessAttributeSigned(0x753c964c8ab538aeLL, - (DwarfAttribute) 0x4e2b7cfb, - (DwarfForm) 0x610b7ae1, - 0x3ea5c609d7d7560fLL); - die_dispatcher.EndDIE(0x753c964c8ab538aeLL); - } - - // Finish the root DIE (and thus the CU). - die_dispatcher.EndDIE(0x15f0e06bdfe3c372LL); - } -} - -// The DIEDispatcher destructor is supposed to delete all handlers on -// the stack, except for the root. -TEST(Dwarf2DIEHandler, FreeHandlersOnStack) { - MockRootDIEHandler mock_root_handler; - MockDIEHandler *mock_child_handler = new(MockDIEHandler); - MockDIEHandler *mock_grandchild_handler = new(MockDIEHandler); - - { - InSequence s; - - // We'll like the compilation unit header. - EXPECT_CALL(mock_root_handler, - StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89, - 0x76d392ff393ddda2LL, 0xbf)) - .WillOnce(Return(true)); - - // Root DIE. - { - EXPECT_CALL(mock_root_handler, - StartRootDIE(0xbf13b761691ddc91LL, (DwarfTag) 0x98980361)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_root_handler, EndAttributes()) - .WillOnce(Return(true)); - - // Child DIE. - EXPECT_CALL(mock_root_handler, - FindChildHandler(0x058f09240c5fc8c9LL, - (DwarfTag) 0x898bf0d0)) - .WillOnce(Return(mock_child_handler)); - { - EXPECT_CALL(*mock_child_handler, EndAttributes()) - .WillOnce(Return(true)); - - // Grandchild DIE. - EXPECT_CALL(*mock_child_handler, - FindChildHandler(0x32dc00c9945dc0c8LL, - (DwarfTag) 0x2802d007)) - .WillOnce(Return(mock_grandchild_handler)); - { - EXPECT_CALL(*mock_grandchild_handler, - ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb, - (DwarfForm) 0x610b7ae1, - 0x3ea5c609d7d7560fLL)) - .WillOnce(Return()); - - // At this point, we abandon the traversal, so none of the - // usual stuff should get called. - EXPECT_CALL(*mock_grandchild_handler, EndAttributes()) - .Times(0); - EXPECT_CALL(*mock_grandchild_handler, Finish()) - .Times(0); - } - - EXPECT_CALL(*mock_child_handler, Finish()) - .Times(0); - } - - EXPECT_CALL(mock_root_handler, Finish()) - .Times(0); - } - } - - // The dispatcher. - DIEDispatcher die_dispatcher(&mock_root_handler); - - // Report the CU header. - EXPECT_TRUE(die_dispatcher - .StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89, - 0x76d392ff393ddda2LL, 0xbf)); - // Report the root DIE. - { - EXPECT_TRUE(die_dispatcher.StartDIE(0xbf13b761691ddc91LL, - (DwarfTag) 0x98980361)); - - // Child DIE. - { - EXPECT_TRUE(die_dispatcher.StartDIE(0x058f09240c5fc8c9LL, - (DwarfTag) 0x898bf0d0)); - - // Grandchild DIE. - { - EXPECT_TRUE(die_dispatcher.StartDIE(0x32dc00c9945dc0c8LL, - (DwarfTag) 0x2802d007)); - die_dispatcher.ProcessAttributeSigned(0x32dc00c9945dc0c8LL, - (DwarfAttribute) 0x4e2b7cfb, - (DwarfForm) 0x610b7ae1, - 0x3ea5c609d7d7560fLL); - - // Stop the traversal abruptly, so that there will still be - // handlers on the stack when the dispatcher is destructed. - - // No EndDIE call... - } - // No EndDIE call... - } - // No EndDIE call... - } -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2enums.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2enums.h deleted file mode 100644 index 6b8a72459..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2enums.h +++ /dev/null @@ -1,675 +0,0 @@ -// -*- mode: c++ -*- - -// 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_DWARF_DWARF2ENUMS_H__ -#define COMMON_DWARF_DWARF2ENUMS_H__ - -namespace dwarf2reader { - -// These enums do not follow the google3 style only because they are -// known universally (specs, other implementations) by the names in -// exactly this capitalization. -// Tag names and codes. -enum DwarfTag { - DW_TAG_padding = 0x00, - DW_TAG_array_type = 0x01, - DW_TAG_class_type = 0x02, - DW_TAG_entry_point = 0x03, - DW_TAG_enumeration_type = 0x04, - DW_TAG_formal_parameter = 0x05, - DW_TAG_imported_declaration = 0x08, - DW_TAG_label = 0x0a, - DW_TAG_lexical_block = 0x0b, - DW_TAG_member = 0x0d, - DW_TAG_pointer_type = 0x0f, - DW_TAG_reference_type = 0x10, - DW_TAG_compile_unit = 0x11, - DW_TAG_string_type = 0x12, - DW_TAG_structure_type = 0x13, - DW_TAG_subroutine_type = 0x15, - DW_TAG_typedef = 0x16, - DW_TAG_union_type = 0x17, - DW_TAG_unspecified_parameters = 0x18, - DW_TAG_variant = 0x19, - DW_TAG_common_block = 0x1a, - DW_TAG_common_inclusion = 0x1b, - DW_TAG_inheritance = 0x1c, - DW_TAG_inlined_subroutine = 0x1d, - DW_TAG_module = 0x1e, - DW_TAG_ptr_to_member_type = 0x1f, - DW_TAG_set_type = 0x20, - DW_TAG_subrange_type = 0x21, - DW_TAG_with_stmt = 0x22, - DW_TAG_access_declaration = 0x23, - DW_TAG_base_type = 0x24, - DW_TAG_catch_block = 0x25, - DW_TAG_const_type = 0x26, - DW_TAG_constant = 0x27, - DW_TAG_enumerator = 0x28, - DW_TAG_file_type = 0x29, - DW_TAG_friend = 0x2a, - DW_TAG_namelist = 0x2b, - DW_TAG_namelist_item = 0x2c, - DW_TAG_packed_type = 0x2d, - DW_TAG_subprogram = 0x2e, - DW_TAG_template_type_param = 0x2f, - DW_TAG_template_value_param = 0x30, - DW_TAG_thrown_type = 0x31, - DW_TAG_try_block = 0x32, - DW_TAG_variant_part = 0x33, - DW_TAG_variable = 0x34, - DW_TAG_volatile_type = 0x35, - // DWARF 3. - DW_TAG_dwarf_procedure = 0x36, - DW_TAG_restrict_type = 0x37, - DW_TAG_interface_type = 0x38, - DW_TAG_namespace = 0x39, - DW_TAG_imported_module = 0x3a, - DW_TAG_unspecified_type = 0x3b, - DW_TAG_partial_unit = 0x3c, - DW_TAG_imported_unit = 0x3d, - // SGI/MIPS Extensions. - DW_TAG_MIPS_loop = 0x4081, - // HP extensions. See: - // ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz - DW_TAG_HP_array_descriptor = 0x4090, - // GNU extensions. - DW_TAG_format_label = 0x4101, // For FORTRAN 77 and Fortran 90. - DW_TAG_function_template = 0x4102, // For C++. - DW_TAG_class_template = 0x4103, // For C++. - DW_TAG_GNU_BINCL = 0x4104, - DW_TAG_GNU_EINCL = 0x4105, - // Extensions for UPC. See: http://upc.gwu.edu/~upc. - DW_TAG_upc_shared_type = 0x8765, - DW_TAG_upc_strict_type = 0x8766, - DW_TAG_upc_relaxed_type = 0x8767, - // PGI (STMicroelectronics) extensions. No documentation available. - DW_TAG_PGI_kanji_type = 0xA000, - DW_TAG_PGI_interface_block = 0xA020 -}; - - -enum DwarfHasChild { - DW_children_no = 0, - DW_children_yes = 1 -}; - -// Form names and codes. -enum DwarfForm { - DW_FORM_addr = 0x01, - DW_FORM_block2 = 0x03, - DW_FORM_block4 = 0x04, - DW_FORM_data2 = 0x05, - DW_FORM_data4 = 0x06, - DW_FORM_data8 = 0x07, - DW_FORM_string = 0x08, - DW_FORM_block = 0x09, - DW_FORM_block1 = 0x0a, - DW_FORM_data1 = 0x0b, - DW_FORM_flag = 0x0c, - DW_FORM_sdata = 0x0d, - DW_FORM_strp = 0x0e, - DW_FORM_udata = 0x0f, - DW_FORM_ref_addr = 0x10, - DW_FORM_ref1 = 0x11, - DW_FORM_ref2 = 0x12, - DW_FORM_ref4 = 0x13, - DW_FORM_ref8 = 0x14, - DW_FORM_ref_udata = 0x15, - DW_FORM_indirect = 0x16, - - // Added in DWARF 4: - DW_FORM_sec_offset = 0x17, - DW_FORM_exprloc = 0x18, - DW_FORM_flag_present = 0x19, - DW_FORM_ref_sig8 = 0x20, - // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. - DW_FORM_GNU_addr_index = 0x1f01, - DW_FORM_GNU_str_index = 0x1f02 -}; - -// Attribute names and codes -enum DwarfAttribute { - DW_AT_sibling = 0x01, - DW_AT_location = 0x02, - DW_AT_name = 0x03, - DW_AT_ordering = 0x09, - DW_AT_subscr_data = 0x0a, - DW_AT_byte_size = 0x0b, - DW_AT_bit_offset = 0x0c, - DW_AT_bit_size = 0x0d, - DW_AT_element_list = 0x0f, - DW_AT_stmt_list = 0x10, - DW_AT_low_pc = 0x11, - DW_AT_high_pc = 0x12, - DW_AT_language = 0x13, - DW_AT_member = 0x14, - DW_AT_discr = 0x15, - DW_AT_discr_value = 0x16, - DW_AT_visibility = 0x17, - DW_AT_import = 0x18, - DW_AT_string_length = 0x19, - DW_AT_common_reference = 0x1a, - DW_AT_comp_dir = 0x1b, - DW_AT_const_value = 0x1c, - DW_AT_containing_type = 0x1d, - DW_AT_default_value = 0x1e, - DW_AT_inline = 0x20, - DW_AT_is_optional = 0x21, - DW_AT_lower_bound = 0x22, - DW_AT_producer = 0x25, - DW_AT_prototyped = 0x27, - DW_AT_return_addr = 0x2a, - DW_AT_start_scope = 0x2c, - DW_AT_stride_size = 0x2e, - DW_AT_upper_bound = 0x2f, - DW_AT_abstract_origin = 0x31, - DW_AT_accessibility = 0x32, - DW_AT_address_class = 0x33, - DW_AT_artificial = 0x34, - DW_AT_base_types = 0x35, - DW_AT_calling_convention = 0x36, - DW_AT_count = 0x37, - DW_AT_data_member_location = 0x38, - DW_AT_decl_column = 0x39, - DW_AT_decl_file = 0x3a, - DW_AT_decl_line = 0x3b, - DW_AT_declaration = 0x3c, - DW_AT_discr_list = 0x3d, - DW_AT_encoding = 0x3e, - DW_AT_external = 0x3f, - DW_AT_frame_base = 0x40, - DW_AT_friend = 0x41, - DW_AT_identifier_case = 0x42, - DW_AT_macro_info = 0x43, - DW_AT_namelist_items = 0x44, - DW_AT_priority = 0x45, - DW_AT_segment = 0x46, - DW_AT_specification = 0x47, - DW_AT_static_link = 0x48, - DW_AT_type = 0x49, - DW_AT_use_location = 0x4a, - DW_AT_variable_parameter = 0x4b, - DW_AT_virtuality = 0x4c, - DW_AT_vtable_elem_location = 0x4d, - // DWARF 3 values. - DW_AT_allocated = 0x4e, - DW_AT_associated = 0x4f, - DW_AT_data_location = 0x50, - DW_AT_stride = 0x51, - DW_AT_entry_pc = 0x52, - DW_AT_use_UTF8 = 0x53, - DW_AT_extension = 0x54, - DW_AT_ranges = 0x55, - DW_AT_trampoline = 0x56, - DW_AT_call_column = 0x57, - DW_AT_call_file = 0x58, - DW_AT_call_line = 0x59, - // SGI/MIPS extensions. - DW_AT_MIPS_fde = 0x2001, - DW_AT_MIPS_loop_begin = 0x2002, - DW_AT_MIPS_tail_loop_begin = 0x2003, - DW_AT_MIPS_epilog_begin = 0x2004, - DW_AT_MIPS_loop_unroll_factor = 0x2005, - DW_AT_MIPS_software_pipeline_depth = 0x2006, - DW_AT_MIPS_linkage_name = 0x2007, - DW_AT_MIPS_stride = 0x2008, - DW_AT_MIPS_abstract_name = 0x2009, - DW_AT_MIPS_clone_origin = 0x200a, - DW_AT_MIPS_has_inlines = 0x200b, - // HP extensions. - DW_AT_HP_block_index = 0x2000, - DW_AT_HP_unmodifiable = 0x2001, // Same as DW_AT_MIPS_fde. - DW_AT_HP_actuals_stmt_list = 0x2010, - DW_AT_HP_proc_per_section = 0x2011, - DW_AT_HP_raw_data_ptr = 0x2012, - DW_AT_HP_pass_by_reference = 0x2013, - DW_AT_HP_opt_level = 0x2014, - DW_AT_HP_prof_version_id = 0x2015, - DW_AT_HP_opt_flags = 0x2016, - DW_AT_HP_cold_region_low_pc = 0x2017, - DW_AT_HP_cold_region_high_pc = 0x2018, - DW_AT_HP_all_variables_modifiable = 0x2019, - DW_AT_HP_linkage_name = 0x201a, - DW_AT_HP_prof_flags = 0x201b, // In comp unit of procs_info for -g. - // GNU extensions. - DW_AT_sf_names = 0x2101, - DW_AT_src_info = 0x2102, - DW_AT_mac_info = 0x2103, - DW_AT_src_coords = 0x2104, - DW_AT_body_begin = 0x2105, - DW_AT_body_end = 0x2106, - DW_AT_GNU_vector = 0x2107, - // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. - DW_AT_GNU_dwo_name = 0x2130, - DW_AT_GNU_dwo_id = 0x2131, - DW_AT_GNU_ranges_base = 0x2132, - DW_AT_GNU_addr_base = 0x2133, - DW_AT_GNU_pubnames = 0x2134, - DW_AT_GNU_pubtypes = 0x2135, - // VMS extensions. - DW_AT_VMS_rtnbeg_pd_address = 0x2201, - // UPC extension. - DW_AT_upc_threads_scaled = 0x3210, - // PGI (STMicroelectronics) extensions. - DW_AT_PGI_lbase = 0x3a00, - DW_AT_PGI_soffset = 0x3a01, - DW_AT_PGI_lstride = 0x3a02 -}; - - -// Line number opcodes. -enum DwarfLineNumberOps { - DW_LNS_extended_op = 0, - DW_LNS_copy = 1, - DW_LNS_advance_pc = 2, - DW_LNS_advance_line = 3, - DW_LNS_set_file = 4, - DW_LNS_set_column = 5, - DW_LNS_negate_stmt = 6, - DW_LNS_set_basic_block = 7, - DW_LNS_const_add_pc = 8, - DW_LNS_fixed_advance_pc = 9, - // DWARF 3. - DW_LNS_set_prologue_end = 10, - DW_LNS_set_epilogue_begin = 11, - DW_LNS_set_isa = 12 -}; - -// Line number extended opcodes. -enum DwarfLineNumberExtendedOps { - DW_LNE_end_sequence = 1, - DW_LNE_set_address = 2, - DW_LNE_define_file = 3, - // HP extensions. - DW_LNE_HP_negate_is_UV_update = 0x11, - DW_LNE_HP_push_context = 0x12, - DW_LNE_HP_pop_context = 0x13, - DW_LNE_HP_set_file_line_column = 0x14, - DW_LNE_HP_set_routine_name = 0x15, - DW_LNE_HP_set_sequence = 0x16, - DW_LNE_HP_negate_post_semantics = 0x17, - DW_LNE_HP_negate_function_exit = 0x18, - DW_LNE_HP_negate_front_end_logical = 0x19, - DW_LNE_HP_define_proc = 0x20 -}; - -// Type encoding names and codes -enum DwarfEncoding { - DW_ATE_address =0x1, - DW_ATE_boolean =0x2, - DW_ATE_complex_float =0x3, - DW_ATE_float =0x4, - DW_ATE_signed =0x5, - DW_ATE_signed_char =0x6, - DW_ATE_unsigned =0x7, - DW_ATE_unsigned_char =0x8, - // DWARF3/DWARF3f - DW_ATE_imaginary_float =0x9, - DW_ATE_packed_decimal =0xa, - DW_ATE_numeric_string =0xb, - DW_ATE_edited =0xc, - DW_ATE_signed_fixed =0xd, - DW_ATE_unsigned_fixed =0xe, - DW_ATE_decimal_float =0xf, - DW_ATE_lo_user =0x80, - DW_ATE_hi_user =0xff -}; - -// Location virtual machine opcodes -enum DwarfOpcode { - DW_OP_addr =0x03, - DW_OP_deref =0x06, - DW_OP_const1u =0x08, - DW_OP_const1s =0x09, - DW_OP_const2u =0x0a, - DW_OP_const2s =0x0b, - DW_OP_const4u =0x0c, - DW_OP_const4s =0x0d, - DW_OP_const8u =0x0e, - DW_OP_const8s =0x0f, - DW_OP_constu =0x10, - DW_OP_consts =0x11, - DW_OP_dup =0x12, - DW_OP_drop =0x13, - DW_OP_over =0x14, - DW_OP_pick =0x15, - DW_OP_swap =0x16, - DW_OP_rot =0x17, - DW_OP_xderef =0x18, - DW_OP_abs =0x19, - DW_OP_and =0x1a, - DW_OP_div =0x1b, - DW_OP_minus =0x1c, - DW_OP_mod =0x1d, - DW_OP_mul =0x1e, - DW_OP_neg =0x1f, - DW_OP_not =0x20, - DW_OP_or =0x21, - DW_OP_plus =0x22, - DW_OP_plus_uconst =0x23, - DW_OP_shl =0x24, - DW_OP_shr =0x25, - DW_OP_shra =0x26, - DW_OP_xor =0x27, - DW_OP_bra =0x28, - DW_OP_eq =0x29, - DW_OP_ge =0x2a, - DW_OP_gt =0x2b, - DW_OP_le =0x2c, - DW_OP_lt =0x2d, - DW_OP_ne =0x2e, - DW_OP_skip =0x2f, - DW_OP_lit0 =0x30, - DW_OP_lit1 =0x31, - DW_OP_lit2 =0x32, - DW_OP_lit3 =0x33, - DW_OP_lit4 =0x34, - DW_OP_lit5 =0x35, - DW_OP_lit6 =0x36, - DW_OP_lit7 =0x37, - DW_OP_lit8 =0x38, - DW_OP_lit9 =0x39, - DW_OP_lit10 =0x3a, - DW_OP_lit11 =0x3b, - DW_OP_lit12 =0x3c, - DW_OP_lit13 =0x3d, - DW_OP_lit14 =0x3e, - DW_OP_lit15 =0x3f, - DW_OP_lit16 =0x40, - DW_OP_lit17 =0x41, - DW_OP_lit18 =0x42, - DW_OP_lit19 =0x43, - DW_OP_lit20 =0x44, - DW_OP_lit21 =0x45, - DW_OP_lit22 =0x46, - DW_OP_lit23 =0x47, - DW_OP_lit24 =0x48, - DW_OP_lit25 =0x49, - DW_OP_lit26 =0x4a, - DW_OP_lit27 =0x4b, - DW_OP_lit28 =0x4c, - DW_OP_lit29 =0x4d, - DW_OP_lit30 =0x4e, - DW_OP_lit31 =0x4f, - DW_OP_reg0 =0x50, - DW_OP_reg1 =0x51, - DW_OP_reg2 =0x52, - DW_OP_reg3 =0x53, - DW_OP_reg4 =0x54, - DW_OP_reg5 =0x55, - DW_OP_reg6 =0x56, - DW_OP_reg7 =0x57, - DW_OP_reg8 =0x58, - DW_OP_reg9 =0x59, - DW_OP_reg10 =0x5a, - DW_OP_reg11 =0x5b, - DW_OP_reg12 =0x5c, - DW_OP_reg13 =0x5d, - DW_OP_reg14 =0x5e, - DW_OP_reg15 =0x5f, - DW_OP_reg16 =0x60, - DW_OP_reg17 =0x61, - DW_OP_reg18 =0x62, - DW_OP_reg19 =0x63, - DW_OP_reg20 =0x64, - DW_OP_reg21 =0x65, - DW_OP_reg22 =0x66, - DW_OP_reg23 =0x67, - DW_OP_reg24 =0x68, - DW_OP_reg25 =0x69, - DW_OP_reg26 =0x6a, - DW_OP_reg27 =0x6b, - DW_OP_reg28 =0x6c, - DW_OP_reg29 =0x6d, - DW_OP_reg30 =0x6e, - DW_OP_reg31 =0x6f, - DW_OP_breg0 =0x70, - DW_OP_breg1 =0x71, - DW_OP_breg2 =0x72, - DW_OP_breg3 =0x73, - DW_OP_breg4 =0x74, - DW_OP_breg5 =0x75, - DW_OP_breg6 =0x76, - DW_OP_breg7 =0x77, - DW_OP_breg8 =0x78, - DW_OP_breg9 =0x79, - DW_OP_breg10 =0x7a, - DW_OP_breg11 =0x7b, - DW_OP_breg12 =0x7c, - DW_OP_breg13 =0x7d, - DW_OP_breg14 =0x7e, - DW_OP_breg15 =0x7f, - DW_OP_breg16 =0x80, - DW_OP_breg17 =0x81, - DW_OP_breg18 =0x82, - DW_OP_breg19 =0x83, - DW_OP_breg20 =0x84, - DW_OP_breg21 =0x85, - DW_OP_breg22 =0x86, - DW_OP_breg23 =0x87, - DW_OP_breg24 =0x88, - DW_OP_breg25 =0x89, - DW_OP_breg26 =0x8a, - DW_OP_breg27 =0x8b, - DW_OP_breg28 =0x8c, - DW_OP_breg29 =0x8d, - DW_OP_breg30 =0x8e, - DW_OP_breg31 =0x8f, - DW_OP_regX =0x90, - DW_OP_fbreg =0x91, - DW_OP_bregX =0x92, - DW_OP_piece =0x93, - DW_OP_deref_size =0x94, - DW_OP_xderef_size =0x95, - DW_OP_nop =0x96, - // DWARF3/DWARF3f - DW_OP_push_object_address =0x97, - DW_OP_call2 =0x98, - DW_OP_call4 =0x99, - DW_OP_call_ref =0x9a, - DW_OP_form_tls_address =0x9b, - DW_OP_call_frame_cfa =0x9c, - DW_OP_bit_piece =0x9d, - DW_OP_lo_user =0xe0, - DW_OP_hi_user =0xff, - // GNU extensions - DW_OP_GNU_push_tls_address =0xe0, - // Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. - DW_OP_GNU_addr_index =0xfb, - DW_OP_GNU_const_index =0xfc -}; - -// Section identifiers for DWP files -enum DwarfSectionId { - DW_SECT_INFO = 1, - DW_SECT_TYPES = 2, - DW_SECT_ABBREV = 3, - DW_SECT_LINE = 4, - DW_SECT_LOC = 5, - DW_SECT_STR_OFFSETS = 6, - DW_SECT_MACINFO = 7, - DW_SECT_MACRO = 8 -}; - -// Source languages. These are values for DW_AT_language. -enum DwarfLanguage - { - DW_LANG_none =0x0000, - DW_LANG_C89 =0x0001, - DW_LANG_C =0x0002, - DW_LANG_Ada83 =0x0003, - DW_LANG_C_plus_plus =0x0004, - DW_LANG_Cobol74 =0x0005, - DW_LANG_Cobol85 =0x0006, - DW_LANG_Fortran77 =0x0007, - DW_LANG_Fortran90 =0x0008, - DW_LANG_Pascal83 =0x0009, - DW_LANG_Modula2 =0x000a, - DW_LANG_Java =0x000b, - DW_LANG_C99 =0x000c, - DW_LANG_Ada95 =0x000d, - DW_LANG_Fortran95 =0x000e, - DW_LANG_PLI =0x000f, - DW_LANG_ObjC =0x0010, - DW_LANG_ObjC_plus_plus =0x0011, - DW_LANG_UPC =0x0012, - DW_LANG_D =0x0013, - // Implementation-defined language code range. - DW_LANG_lo_user = 0x8000, - DW_LANG_hi_user = 0xffff, - - // Extensions. - - // MIPS assembly language. The GNU toolchain uses this for all - // assembly languages, since there's no generic DW_LANG_ value for that. - // See include/dwarf2.h in the binutils, gdb, or gcc source trees. - DW_LANG_Mips_Assembler =0x8001, - DW_LANG_Upc =0x8765 // Unified Parallel C - }; - -// Inline codes. These are values for DW_AT_inline. -enum DwarfInline { - DW_INL_not_inlined =0x0, - DW_INL_inlined =0x1, - DW_INL_declared_not_inlined =0x2, - DW_INL_declared_inlined =0x3 -}; - -// Call Frame Info instructions. -enum DwarfCFI - { - DW_CFA_advance_loc = 0x40, - DW_CFA_offset = 0x80, - DW_CFA_restore = 0xc0, - DW_CFA_nop = 0x00, - DW_CFA_set_loc = 0x01, - DW_CFA_advance_loc1 = 0x02, - DW_CFA_advance_loc2 = 0x03, - DW_CFA_advance_loc4 = 0x04, - DW_CFA_offset_extended = 0x05, - DW_CFA_restore_extended = 0x06, - DW_CFA_undefined = 0x07, - DW_CFA_same_value = 0x08, - DW_CFA_register = 0x09, - DW_CFA_remember_state = 0x0a, - DW_CFA_restore_state = 0x0b, - DW_CFA_def_cfa = 0x0c, - DW_CFA_def_cfa_register = 0x0d, - DW_CFA_def_cfa_offset = 0x0e, - DW_CFA_def_cfa_expression = 0x0f, - DW_CFA_expression = 0x10, - DW_CFA_offset_extended_sf = 0x11, - DW_CFA_def_cfa_sf = 0x12, - DW_CFA_def_cfa_offset_sf = 0x13, - DW_CFA_val_offset = 0x14, - DW_CFA_val_offset_sf = 0x15, - DW_CFA_val_expression = 0x16, - - // Opcodes in this range are reserved for user extensions. - DW_CFA_lo_user = 0x1c, - DW_CFA_hi_user = 0x3f, - - // SGI/MIPS specific. - DW_CFA_MIPS_advance_loc8 = 0x1d, - - // GNU extensions. - DW_CFA_GNU_window_save = 0x2d, - DW_CFA_GNU_args_size = 0x2e, - DW_CFA_GNU_negative_offset_extended = 0x2f - }; - -// Exception handling 'z' augmentation letters. -enum DwarfZAugmentationCodes { - // If the CFI augmentation string begins with 'z', then the CIE and FDE - // have an augmentation data area just before the instructions, whose - // contents are determined by the subsequent augmentation letters. - DW_Z_augmentation_start = 'z', - - // If this letter is present in a 'z' augmentation string, the CIE - // augmentation data includes a pointer encoding, and the FDE - // augmentation data includes a language-specific data area pointer, - // represented using that encoding. - DW_Z_has_LSDA = 'L', - - // If this letter is present in a 'z' augmentation string, the CIE - // augmentation data includes a pointer encoding, followed by a pointer - // to a personality routine, represented using that encoding. - DW_Z_has_personality_routine = 'P', - - // If this letter is present in a 'z' augmentation string, the CIE - // augmentation data includes a pointer encoding describing how the FDE's - // initial location, address range, and DW_CFA_set_loc operands are - // encoded. - DW_Z_has_FDE_address_encoding = 'R', - - // If this letter is present in a 'z' augmentation string, then code - // addresses covered by FDEs that cite this CIE are signal delivery - // trampolines. Return addresses of frames in trampolines should not be - // adjusted as described in section 6.4.4 of the DWARF 3 spec. - DW_Z_is_signal_trampoline = 'S' -}; - -// Exception handling frame description pointer formats, as described -// by the Linux Standard Base Core Specification 4.0, section 11.5, -// DWARF Extensions. -enum DwarfPointerEncoding - { - DW_EH_PE_absptr = 0x00, - DW_EH_PE_omit = 0xff, - DW_EH_PE_uleb128 = 0x01, - DW_EH_PE_udata2 = 0x02, - DW_EH_PE_udata4 = 0x03, - DW_EH_PE_udata8 = 0x04, - DW_EH_PE_sleb128 = 0x09, - DW_EH_PE_sdata2 = 0x0A, - DW_EH_PE_sdata4 = 0x0B, - DW_EH_PE_sdata8 = 0x0C, - DW_EH_PE_pcrel = 0x10, - DW_EH_PE_textrel = 0x20, - DW_EH_PE_datarel = 0x30, - DW_EH_PE_funcrel = 0x40, - DW_EH_PE_aligned = 0x50, - - // The GNU toolchain sources define this enum value as well, - // simply to help classify the lower nybble values into signed and - // unsigned groups. - DW_EH_PE_signed = 0x08, - - // This is not documented in LSB 4.0, but it is used in both the - // Linux and OS X toolchains. It can be added to any other - // encoding (except DW_EH_PE_aligned), and indicates that the - // encoded value represents the address at which the true address - // is stored, not the true address itself. - DW_EH_PE_indirect = 0x80 - }; - -} // namespace dwarf2reader -#endif // COMMON_DWARF_DWARF2ENUMS_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.cc deleted file mode 100644 index a65b43c8a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.cc +++ /dev/null @@ -1,2734 +0,0 @@ -// 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. - -// CFI reader author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// Implementation of dwarf2reader::LineInfo, dwarf2reader::CompilationUnit, -// and dwarf2reader::CallFrameInfo. See dwarf2reader.h for details. - -#include "common/dwarf/dwarf2reader.h" - -#include <assert.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> - -#include <map> -#include <memory> -#include <stack> -#include <string> -#include <utility> - -#include <sys/stat.h> - -#include "common/dwarf/bytereader-inl.h" -#include "common/dwarf/bytereader.h" -#include "common/dwarf/line_state_machine.h" -#include "common/using_std_string.h" - -namespace dwarf2reader { - -CompilationUnit::CompilationUnit(const string& path, - const SectionMap& sections, uint64 offset, - ByteReader* reader, Dwarf2Handler* handler) - : path_(path), offset_from_section_start_(offset), reader_(reader), - sections_(sections), handler_(handler), abbrevs_(), - string_buffer_(NULL), string_buffer_length_(0), - str_offsets_buffer_(NULL), str_offsets_buffer_length_(0), - addr_buffer_(NULL), addr_buffer_length_(0), - is_split_dwarf_(false), dwo_id_(0), dwo_name_(), - skeleton_dwo_id_(0), ranges_base_(0), addr_base_(0), - have_checked_for_dwp_(false), dwp_path_(), - dwp_byte_reader_(), dwp_reader_() {} - -// Initialize a compilation unit from a .dwo or .dwp file. -// In this case, we need the .debug_addr section from the -// executable file that contains the corresponding skeleton -// compilation unit. We also inherit the Dwarf2Handler from -// the executable file, and call it as if we were still -// processing the original compilation unit. - -void CompilationUnit::SetSplitDwarf(const uint8_t* addr_buffer, - uint64 addr_buffer_length, - uint64 addr_base, - uint64 ranges_base, - uint64 dwo_id) { - is_split_dwarf_ = true; - addr_buffer_ = addr_buffer; - addr_buffer_length_ = addr_buffer_length; - addr_base_ = addr_base; - ranges_base_ = ranges_base; - skeleton_dwo_id_ = dwo_id; -} - -// Read a DWARF2/3 abbreviation section. -// Each abbrev consists of a abbreviation number, a tag, a byte -// specifying whether the tag has children, and a list of -// attribute/form pairs. -// The list of forms is terminated by a 0 for the attribute, and a -// zero for the form. The entire abbreviation section is terminated -// by a zero for the code. - -void CompilationUnit::ReadAbbrevs() { - if (abbrevs_) - return; - - // First get the debug_abbrev section. ".debug_abbrev" is the name - // recommended in the DWARF spec, and used on Linux; - // "__debug_abbrev" is the name used in Mac OS X Mach-O files. - SectionMap::const_iterator iter = sections_.find(".debug_abbrev"); - if (iter == sections_.end()) - iter = sections_.find("__debug_abbrev"); - assert(iter != sections_.end()); - - abbrevs_ = new std::vector<Abbrev>; - abbrevs_->resize(1); - - // The only way to check whether we are reading over the end of the - // buffer would be to first compute the size of the leb128 data by - // reading it, then go back and read it again. - const uint8_t *abbrev_start = iter->second.first + - header_.abbrev_offset; - const uint8_t *abbrevptr = abbrev_start; -#ifndef NDEBUG - const uint64 abbrev_length = iter->second.second - header_.abbrev_offset; -#endif - - while (1) { - CompilationUnit::Abbrev abbrev; - size_t len; - const uint64 number = reader_->ReadUnsignedLEB128(abbrevptr, &len); - - if (number == 0) - break; - abbrev.number = number; - abbrevptr += len; - - assert(abbrevptr < abbrev_start + abbrev_length); - const uint64 tag = reader_->ReadUnsignedLEB128(abbrevptr, &len); - abbrevptr += len; - abbrev.tag = static_cast<enum DwarfTag>(tag); - - assert(abbrevptr < abbrev_start + abbrev_length); - abbrev.has_children = reader_->ReadOneByte(abbrevptr); - abbrevptr += 1; - - assert(abbrevptr < abbrev_start + abbrev_length); - - while (1) { - const uint64 nametemp = reader_->ReadUnsignedLEB128(abbrevptr, &len); - abbrevptr += len; - - assert(abbrevptr < abbrev_start + abbrev_length); - const uint64 formtemp = reader_->ReadUnsignedLEB128(abbrevptr, &len); - abbrevptr += len; - if (nametemp == 0 && formtemp == 0) - break; - - const enum DwarfAttribute name = - static_cast<enum DwarfAttribute>(nametemp); - const enum DwarfForm form = static_cast<enum DwarfForm>(formtemp); - abbrev.attributes.push_back(std::make_pair(name, form)); - } - assert(abbrev.number == abbrevs_->size()); - abbrevs_->push_back(abbrev); - } -} - -// Skips a single DIE's attributes. -const uint8_t *CompilationUnit::SkipDIE(const uint8_t* start, - const Abbrev& abbrev) { - for (AttributeList::const_iterator i = abbrev.attributes.begin(); - i != abbrev.attributes.end(); - i++) { - start = SkipAttribute(start, i->second); - } - return start; -} - -// Skips a single attribute form's data. -const uint8_t *CompilationUnit::SkipAttribute(const uint8_t *start, - enum DwarfForm form) { - size_t len; - - switch (form) { - case DW_FORM_indirect: - form = static_cast<enum DwarfForm>(reader_->ReadUnsignedLEB128(start, - &len)); - start += len; - return SkipAttribute(start, form); - - case DW_FORM_flag_present: - return start; - case DW_FORM_data1: - case DW_FORM_flag: - case DW_FORM_ref1: - return start + 1; - case DW_FORM_ref2: - case DW_FORM_data2: - return start + 2; - case DW_FORM_ref4: - case DW_FORM_data4: - return start + 4; - case DW_FORM_ref8: - case DW_FORM_data8: - case DW_FORM_ref_sig8: - return start + 8; - case DW_FORM_string: - return start + strlen(reinterpret_cast<const char *>(start)) + 1; - case DW_FORM_udata: - case DW_FORM_ref_udata: - case DW_FORM_GNU_str_index: - case DW_FORM_GNU_addr_index: - reader_->ReadUnsignedLEB128(start, &len); - return start + len; - - case DW_FORM_sdata: - reader_->ReadSignedLEB128(start, &len); - return start + len; - case DW_FORM_addr: - return start + reader_->AddressSize(); - case DW_FORM_ref_addr: - // DWARF2 and 3/4 differ on whether ref_addr is address size or - // offset size. - assert(header_.version >= 2); - if (header_.version == 2) { - return start + reader_->AddressSize(); - } else if (header_.version >= 3) { - return start + reader_->OffsetSize(); - } - break; - - case DW_FORM_block1: - return start + 1 + reader_->ReadOneByte(start); - case DW_FORM_block2: - return start + 2 + reader_->ReadTwoBytes(start); - case DW_FORM_block4: - return start + 4 + reader_->ReadFourBytes(start); - case DW_FORM_block: - case DW_FORM_exprloc: { - uint64 size = reader_->ReadUnsignedLEB128(start, &len); - return start + size + len; - } - case DW_FORM_strp: - case DW_FORM_sec_offset: - return start + reader_->OffsetSize(); - } - fprintf(stderr,"Unhandled form type"); - return NULL; -} - -// Read a DWARF2/3 header. -// The header is variable length in DWARF3 (and DWARF2 as extended by -// most compilers), and consists of an length field, a version number, -// the offset in the .debug_abbrev section for our abbrevs, and an -// address size. -void CompilationUnit::ReadHeader() { - const uint8_t *headerptr = buffer_; - size_t initial_length_size; - - assert(headerptr + 4 < buffer_ + buffer_length_); - const uint64 initial_length - = reader_->ReadInitialLength(headerptr, &initial_length_size); - headerptr += initial_length_size; - header_.length = initial_length; - - assert(headerptr + 2 < buffer_ + buffer_length_); - header_.version = reader_->ReadTwoBytes(headerptr); - headerptr += 2; - - assert(headerptr + reader_->OffsetSize() < buffer_ + buffer_length_); - header_.abbrev_offset = reader_->ReadOffset(headerptr); - headerptr += reader_->OffsetSize(); - - // Compare against less than or equal because this may be the last - // section in the file. - assert(headerptr + 1 <= buffer_ + buffer_length_); - header_.address_size = reader_->ReadOneByte(headerptr); - reader_->SetAddressSize(header_.address_size); - headerptr += 1; - - after_header_ = headerptr; - - // This check ensures that we don't have to do checking during the - // reading of DIEs. header_.length does not include the size of the - // initial length. - assert(buffer_ + initial_length_size + header_.length <= - buffer_ + buffer_length_); -} - -uint64 CompilationUnit::Start() { - // First get the debug_info section. ".debug_info" is the name - // recommended in the DWARF spec, and used on Linux; "__debug_info" - // is the name used in Mac OS X Mach-O files. - SectionMap::const_iterator iter = sections_.find(".debug_info"); - if (iter == sections_.end()) - iter = sections_.find("__debug_info"); - assert(iter != sections_.end()); - - // Set up our buffer - buffer_ = iter->second.first + offset_from_section_start_; - buffer_length_ = iter->second.second - offset_from_section_start_; - - // Read the header - ReadHeader(); - - // Figure out the real length from the end of the initial length to - // the end of the compilation unit, since that is the value we - // return. - uint64 ourlength = header_.length; - if (reader_->OffsetSize() == 8) - ourlength += 12; - else - ourlength += 4; - - // See if the user wants this compilation unit, and if not, just return. - if (!handler_->StartCompilationUnit(offset_from_section_start_, - reader_->AddressSize(), - reader_->OffsetSize(), - header_.length, - header_.version)) - return ourlength; - - // Otherwise, continue by reading our abbreviation entries. - ReadAbbrevs(); - - // Set the string section if we have one. ".debug_str" is the name - // recommended in the DWARF spec, and used on Linux; "__debug_str" - // is the name used in Mac OS X Mach-O files. - iter = sections_.find(".debug_str"); - if (iter == sections_.end()) - iter = sections_.find("__debug_str"); - if (iter != sections_.end()) { - string_buffer_ = iter->second.first; - string_buffer_length_ = iter->second.second; - } - - // Set the string offsets section if we have one. - iter = sections_.find(".debug_str_offsets"); - if (iter != sections_.end()) { - str_offsets_buffer_ = iter->second.first; - str_offsets_buffer_length_ = iter->second.second; - } - - // Set the address section if we have one. - iter = sections_.find(".debug_addr"); - if (iter != sections_.end()) { - addr_buffer_ = iter->second.first; - addr_buffer_length_ = iter->second.second; - } - - // Now that we have our abbreviations, start processing DIE's. - ProcessDIEs(); - - // If this is a skeleton compilation unit generated with split DWARF, - // and the client needs the full debug info, we need to find the full - // compilation unit in a .dwo or .dwp file. - if (!is_split_dwarf_ - && dwo_name_ != NULL - && handler_->NeedSplitDebugInfo()) - ProcessSplitDwarf(); - - return ourlength; -} - -// If one really wanted, you could merge SkipAttribute and -// ProcessAttribute -// This is all boring data manipulation and calling of the handler. -const uint8_t *CompilationUnit::ProcessAttribute( - uint64 dieoffset, const uint8_t *start, enum DwarfAttribute attr, - enum DwarfForm form) { - size_t len; - - switch (form) { - // DW_FORM_indirect is never used because it is such a space - // waster. - case DW_FORM_indirect: - form = static_cast<enum DwarfForm>(reader_->ReadUnsignedLEB128(start, - &len)); - start += len; - return ProcessAttribute(dieoffset, start, attr, form); - - case DW_FORM_flag_present: - ProcessAttributeUnsigned(dieoffset, attr, form, 1); - return start; - case DW_FORM_data1: - case DW_FORM_flag: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadOneByte(start)); - return start + 1; - case DW_FORM_data2: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadTwoBytes(start)); - return start + 2; - case DW_FORM_data4: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadFourBytes(start)); - return start + 4; - case DW_FORM_data8: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadEightBytes(start)); - return start + 8; - case DW_FORM_string: { - const char *str = reinterpret_cast<const char *>(start); - ProcessAttributeString(dieoffset, attr, form, str); - return start + strlen(str) + 1; - } - case DW_FORM_udata: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadUnsignedLEB128(start, &len)); - return start + len; - - case DW_FORM_sdata: - ProcessAttributeSigned(dieoffset, attr, form, - reader_->ReadSignedLEB128(start, &len)); - return start + len; - case DW_FORM_addr: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadAddress(start)); - return start + reader_->AddressSize(); - case DW_FORM_sec_offset: - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadOffset(start)); - return start + reader_->OffsetSize(); - - case DW_FORM_ref1: - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadOneByte(start) - + offset_from_section_start_); - return start + 1; - case DW_FORM_ref2: - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadTwoBytes(start) - + offset_from_section_start_); - return start + 2; - case DW_FORM_ref4: - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadFourBytes(start) - + offset_from_section_start_); - return start + 4; - case DW_FORM_ref8: - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadEightBytes(start) - + offset_from_section_start_); - return start + 8; - case DW_FORM_ref_udata: - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadUnsignedLEB128(start, - &len) - + offset_from_section_start_); - return start + len; - case DW_FORM_ref_addr: - // DWARF2 and 3/4 differ on whether ref_addr is address size or - // offset size. - assert(header_.version >= 2); - if (header_.version == 2) { - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadAddress(start)); - return start + reader_->AddressSize(); - } else if (header_.version >= 3) { - handler_->ProcessAttributeReference(dieoffset, attr, form, - reader_->ReadOffset(start)); - return start + reader_->OffsetSize(); - } - break; - case DW_FORM_ref_sig8: - handler_->ProcessAttributeSignature(dieoffset, attr, form, - reader_->ReadEightBytes(start)); - return start + 8; - - case DW_FORM_block1: { - uint64 datalen = reader_->ReadOneByte(start); - handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 1, - datalen); - return start + 1 + datalen; - } - case DW_FORM_block2: { - uint64 datalen = reader_->ReadTwoBytes(start); - handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 2, - datalen); - return start + 2 + datalen; - } - case DW_FORM_block4: { - uint64 datalen = reader_->ReadFourBytes(start); - handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + 4, - datalen); - return start + 4 + datalen; - } - case DW_FORM_block: - case DW_FORM_exprloc: { - uint64 datalen = reader_->ReadUnsignedLEB128(start, &len); - handler_->ProcessAttributeBuffer(dieoffset, attr, form, start + len, - datalen); - return start + datalen + len; - } - case DW_FORM_strp: { - assert(string_buffer_ != NULL); - - const uint64 offset = reader_->ReadOffset(start); - assert(string_buffer_ + offset < string_buffer_ + string_buffer_length_); - - const char *str = reinterpret_cast<const char *>(string_buffer_ + offset); - ProcessAttributeString(dieoffset, attr, form, str); - return start + reader_->OffsetSize(); - } - - case DW_FORM_GNU_str_index: { - uint64 str_index = reader_->ReadUnsignedLEB128(start, &len); - const uint8_t* offset_ptr = - str_offsets_buffer_ + str_index * reader_->OffsetSize(); - const uint64 offset = reader_->ReadOffset(offset_ptr); - if (offset >= string_buffer_length_) { - return NULL; - } - - const char* str = reinterpret_cast<const char *>(string_buffer_) + offset; - ProcessAttributeString(dieoffset, attr, form, str); - return start + len; - break; - } - case DW_FORM_GNU_addr_index: { - uint64 addr_index = reader_->ReadUnsignedLEB128(start, &len); - const uint8_t* addr_ptr = - addr_buffer_ + addr_base_ + addr_index * reader_->AddressSize(); - ProcessAttributeUnsigned(dieoffset, attr, form, - reader_->ReadAddress(addr_ptr)); - return start + len; - } - } - fprintf(stderr, "Unhandled form type\n"); - return NULL; -} - -const uint8_t *CompilationUnit::ProcessDIE(uint64 dieoffset, - const uint8_t *start, - const Abbrev& abbrev) { - for (AttributeList::const_iterator i = abbrev.attributes.begin(); - i != abbrev.attributes.end(); - i++) { - start = ProcessAttribute(dieoffset, start, i->first, i->second); - } - - // If this is a compilation unit in a split DWARF object, verify that - // the dwo_id matches. If it does not match, we will ignore this - // compilation unit. - if (abbrev.tag == DW_TAG_compile_unit - && is_split_dwarf_ - && dwo_id_ != skeleton_dwo_id_) { - return NULL; - } - - return start; -} - -void CompilationUnit::ProcessDIEs() { - const uint8_t *dieptr = after_header_; - size_t len; - - // lengthstart is the place the length field is based on. - // It is the point in the header after the initial length field - const uint8_t *lengthstart = buffer_; - - // In 64 bit dwarf, the initial length is 12 bytes, because of the - // 0xffffffff at the start. - if (reader_->OffsetSize() == 8) - lengthstart += 12; - else - lengthstart += 4; - - std::stack<uint64> die_stack; - - while (dieptr < (lengthstart + header_.length)) { - // We give the user the absolute offset from the beginning of - // debug_info, since they need it to deal with ref_addr forms. - uint64 absolute_offset = (dieptr - buffer_) + offset_from_section_start_; - - uint64 abbrev_num = reader_->ReadUnsignedLEB128(dieptr, &len); - - dieptr += len; - - // Abbrev == 0 represents the end of a list of children, or padding - // at the end of the compilation unit. - if (abbrev_num == 0) { - if (die_stack.size() == 0) - // If it is padding, then we are done with the compilation unit's DIEs. - return; - const uint64 offset = die_stack.top(); - die_stack.pop(); - handler_->EndDIE(offset); - continue; - } - - const Abbrev& abbrev = abbrevs_->at(static_cast<size_t>(abbrev_num)); - const enum DwarfTag tag = abbrev.tag; - if (!handler_->StartDIE(absolute_offset, tag)) { - dieptr = SkipDIE(dieptr, abbrev); - } else { - dieptr = ProcessDIE(absolute_offset, dieptr, abbrev); - } - - if (abbrev.has_children) { - die_stack.push(absolute_offset); - } else { - handler_->EndDIE(absolute_offset); - } - } -} - -// Check for a valid ELF file and return the Address size. -// Returns 0 if not a valid ELF file. -inline int GetElfWidth(const ElfReader& elf) { - if (elf.IsElf32File()) - return 4; - if (elf.IsElf64File()) - return 8; - return 0; -} - -void CompilationUnit::ProcessSplitDwarf() { - struct stat statbuf; - if (!have_checked_for_dwp_) { - // Look for a .dwp file in the same directory as the executable. - have_checked_for_dwp_ = true; - string dwp_suffix(".dwp"); - dwp_path_ = path_ + dwp_suffix; - if (stat(dwp_path_.c_str(), &statbuf) != 0) { - // Fall back to a split .debug file in the same directory. - string debug_suffix(".debug"); - dwp_path_ = path_; - size_t found = path_.rfind(debug_suffix); - if (found + debug_suffix.length() == path_.length()) - dwp_path_ = dwp_path_.replace(found, debug_suffix.length(), dwp_suffix); - } - if (stat(dwp_path_.c_str(), &statbuf) == 0) { - ElfReader* elf = new ElfReader(dwp_path_); - int width = GetElfWidth(*elf); - if (width != 0) { - dwp_byte_reader_.reset(new ByteReader(reader_->GetEndianness())); - dwp_byte_reader_->SetAddressSize(width); - dwp_reader_.reset(new DwpReader(*dwp_byte_reader_, elf)); - dwp_reader_->Initialize(); - } else { - delete elf; - } - } - } - bool found_in_dwp = false; - if (dwp_reader_) { - // If we have a .dwp file, read the debug sections for the requested CU. - SectionMap sections; - dwp_reader_->ReadDebugSectionsForCU(dwo_id_, §ions); - if (!sections.empty()) { - found_in_dwp = true; - CompilationUnit dwp_comp_unit(dwp_path_, sections, 0, - dwp_byte_reader_.get(), handler_); - dwp_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, addr_base_, - ranges_base_, dwo_id_); - dwp_comp_unit.Start(); - } - } - if (!found_in_dwp) { - // If no .dwp file, try to open the .dwo file. - if (stat(dwo_name_, &statbuf) == 0) { - ElfReader elf(dwo_name_); - int width = GetElfWidth(elf); - if (width != 0) { - ByteReader reader(ENDIANNESS_LITTLE); - reader.SetAddressSize(width); - SectionMap sections; - ReadDebugSectionsFromDwo(&elf, §ions); - CompilationUnit dwo_comp_unit(dwo_name_, sections, 0, &reader, - handler_); - dwo_comp_unit.SetSplitDwarf(addr_buffer_, addr_buffer_length_, - addr_base_, ranges_base_, dwo_id_); - dwo_comp_unit.Start(); - } - } - } -} - -void CompilationUnit::ReadDebugSectionsFromDwo(ElfReader* elf_reader, - SectionMap* sections) { - static const char* const section_names[] = { - ".debug_abbrev", - ".debug_info", - ".debug_str_offsets", - ".debug_str" - }; - for (unsigned int i = 0u; - i < sizeof(section_names)/sizeof(*(section_names)); ++i) { - string base_name = section_names[i]; - string dwo_name = base_name + ".dwo"; - size_t section_size; - const char* section_data = elf_reader->GetSectionByName(dwo_name, - §ion_size); - if (section_data != NULL) - sections->insert(std::make_pair( - base_name, std::make_pair( - reinterpret_cast<const uint8_t *>(section_data), - section_size))); - } -} - -DwpReader::DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader) - : elf_reader_(elf_reader), byte_reader_(byte_reader), - cu_index_(NULL), cu_index_size_(0), string_buffer_(NULL), - string_buffer_size_(0), version_(0), ncolumns_(0), nunits_(0), - nslots_(0), phash_(NULL), pindex_(NULL), shndx_pool_(NULL), - offset_table_(NULL), size_table_(NULL), abbrev_data_(NULL), - abbrev_size_(0), info_data_(NULL), info_size_(0), - str_offsets_data_(NULL), str_offsets_size_(0) {} - -DwpReader::~DwpReader() { - if (elf_reader_) delete elf_reader_; -} - -void DwpReader::Initialize() { - cu_index_ = elf_reader_->GetSectionByName(".debug_cu_index", - &cu_index_size_); - if (cu_index_ == NULL) { - return; - } - // The .debug_str.dwo section is shared by all CUs in the file. - string_buffer_ = elf_reader_->GetSectionByName(".debug_str.dwo", - &string_buffer_size_); - - version_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_)); - - if (version_ == 1) { - nslots_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) - + 3 * sizeof(uint32)); - phash_ = cu_index_ + 4 * sizeof(uint32); - pindex_ = phash_ + nslots_ * sizeof(uint64); - shndx_pool_ = pindex_ + nslots_ * sizeof(uint32); - if (shndx_pool_ >= cu_index_ + cu_index_size_) { - version_ = 0; - } - } else if (version_ == 2) { - ncolumns_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + sizeof(uint32)); - nunits_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + 2 * sizeof(uint32)); - nslots_ = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(cu_index_) + 3 * sizeof(uint32)); - phash_ = cu_index_ + 4 * sizeof(uint32); - pindex_ = phash_ + nslots_ * sizeof(uint64); - offset_table_ = pindex_ + nslots_ * sizeof(uint32); - size_table_ = offset_table_ + ncolumns_ * (nunits_ + 1) * sizeof(uint32); - abbrev_data_ = elf_reader_->GetSectionByName(".debug_abbrev.dwo", - &abbrev_size_); - info_data_ = elf_reader_->GetSectionByName(".debug_info.dwo", &info_size_); - str_offsets_data_ = elf_reader_->GetSectionByName(".debug_str_offsets.dwo", - &str_offsets_size_); - if (size_table_ >= cu_index_ + cu_index_size_) { - version_ = 0; - } - } -} - -void DwpReader::ReadDebugSectionsForCU(uint64 dwo_id, - SectionMap* sections) { - if (version_ == 1) { - int slot = LookupCU(dwo_id); - if (slot == -1) { - return; - } - - // The index table points to the section index pool, where we - // can read a list of section indexes for the debug sections - // for the CU whose dwo_id we are looking for. - int index = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(pindex_) - + slot * sizeof(uint32)); - const char* shndx_list = shndx_pool_ + index * sizeof(uint32); - for (;;) { - if (shndx_list >= cu_index_ + cu_index_size_) { - version_ = 0; - return; - } - unsigned int shndx = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(shndx_list)); - shndx_list += sizeof(uint32); - if (shndx == 0) - break; - const char* section_name = elf_reader_->GetSectionName(shndx); - size_t section_size; - const char* section_data; - // We're only interested in these four debug sections. - // The section names in the .dwo file end with ".dwo", but we - // add them to the sections table with their normal names. - if (!strncmp(section_name, ".debug_abbrev", strlen(".debug_abbrev"))) { - section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); - sections->insert(std::make_pair( - ".debug_abbrev", - std::make_pair(reinterpret_cast<const uint8_t *> (section_data), - section_size))); - } else if (!strncmp(section_name, ".debug_info", strlen(".debug_info"))) { - section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); - sections->insert(std::make_pair( - ".debug_info", - std::make_pair(reinterpret_cast<const uint8_t *> (section_data), - section_size))); - } else if (!strncmp(section_name, ".debug_str_offsets", - strlen(".debug_str_offsets"))) { - section_data = elf_reader_->GetSectionByIndex(shndx, §ion_size); - sections->insert(std::make_pair( - ".debug_str_offsets", - std::make_pair(reinterpret_cast<const uint8_t *> (section_data), - section_size))); - } - } - sections->insert(std::make_pair( - ".debug_str", - std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_), - string_buffer_size_))); - } else if (version_ == 2) { - uint32 index = LookupCUv2(dwo_id); - if (index == 0) { - return; - } - - // The index points to a row in each of the section offsets table - // and the section size table, where we can read the offsets and sizes - // of the contributions to each debug section from the CU whose dwo_id - // we are looking for. Row 0 of the section offsets table has the - // section ids for each column of the table. The size table begins - // with row 1. - const char* id_row = offset_table_; - const char* offset_row = offset_table_ - + index * ncolumns_ * sizeof(uint32); - const char* size_row = - size_table_ + (index - 1) * ncolumns_ * sizeof(uint32); - if (size_row + ncolumns_ * sizeof(uint32) > cu_index_ + cu_index_size_) { - version_ = 0; - return; - } - for (unsigned int col = 0u; col < ncolumns_; ++col) { - uint32 section_id = - byte_reader_.ReadFourBytes(reinterpret_cast<const uint8_t *>(id_row) - + col * sizeof(uint32)); - uint32 offset = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(offset_row) - + col * sizeof(uint32)); - uint32 size = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(size_row) + col * sizeof(uint32)); - if (section_id == DW_SECT_ABBREV) { - sections->insert(std::make_pair( - ".debug_abbrev", - std::make_pair(reinterpret_cast<const uint8_t *> (abbrev_data_) - + offset, size))); - } else if (section_id == DW_SECT_INFO) { - sections->insert(std::make_pair( - ".debug_info", - std::make_pair(reinterpret_cast<const uint8_t *> (info_data_) - + offset, size))); - } else if (section_id == DW_SECT_STR_OFFSETS) { - sections->insert(std::make_pair( - ".debug_str_offsets", - std::make_pair(reinterpret_cast<const uint8_t *> (str_offsets_data_) - + offset, size))); - } - } - sections->insert(std::make_pair( - ".debug_str", - std::make_pair(reinterpret_cast<const uint8_t *> (string_buffer_), - string_buffer_size_))); - } -} - -int DwpReader::LookupCU(uint64 dwo_id) { - uint32 slot = static_cast<uint32>(dwo_id) & (nslots_ - 1); - uint64 probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64)); - if (probe != 0 && probe != dwo_id) { - uint32 secondary_hash = - (static_cast<uint32>(dwo_id >> 32) & (nslots_ - 1)) | 1; - do { - slot = (slot + secondary_hash) & (nslots_ - 1); - probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64)); - } while (probe != 0 && probe != dwo_id); - } - if (probe == 0) - return -1; - return slot; -} - -uint32 DwpReader::LookupCUv2(uint64 dwo_id) { - uint32 slot = static_cast<uint32>(dwo_id) & (nslots_ - 1); - uint64 probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64)); - uint32 index = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32)); - if (index != 0 && probe != dwo_id) { - uint32 secondary_hash = - (static_cast<uint32>(dwo_id >> 32) & (nslots_ - 1)) | 1; - do { - slot = (slot + secondary_hash) & (nslots_ - 1); - probe = byte_reader_.ReadEightBytes( - reinterpret_cast<const uint8_t *>(phash_) + slot * sizeof(uint64)); - index = byte_reader_.ReadFourBytes( - reinterpret_cast<const uint8_t *>(pindex_) + slot * sizeof(uint32)); - } while (index != 0 && probe != dwo_id); - } - return index; -} - -LineInfo::LineInfo(const uint8_t *buffer, uint64 buffer_length, - ByteReader* reader, LineInfoHandler* handler): - handler_(handler), reader_(reader), buffer_(buffer) { -#ifndef NDEBUG - buffer_length_ = buffer_length; -#endif - header_.std_opcode_lengths = NULL; -} - -uint64 LineInfo::Start() { - ReadHeader(); - ReadLines(); - return after_header_ - buffer_; -} - -// The header for a debug_line section is mildly complicated, because -// the line info is very tightly encoded. -void LineInfo::ReadHeader() { - const uint8_t *lineptr = buffer_; - size_t initial_length_size; - - const uint64 initial_length - = reader_->ReadInitialLength(lineptr, &initial_length_size); - - lineptr += initial_length_size; - header_.total_length = initial_length; - assert(buffer_ + initial_length_size + header_.total_length <= - buffer_ + buffer_length_); - - // Address size *must* be set by CU ahead of time. - assert(reader_->AddressSize() != 0); - - header_.version = reader_->ReadTwoBytes(lineptr); - lineptr += 2; - - header_.prologue_length = reader_->ReadOffset(lineptr); - lineptr += reader_->OffsetSize(); - - header_.min_insn_length = reader_->ReadOneByte(lineptr); - lineptr += 1; - - header_.default_is_stmt = reader_->ReadOneByte(lineptr); - lineptr += 1; - - header_.line_base = *reinterpret_cast<const int8*>(lineptr); - lineptr += 1; - - header_.line_range = reader_->ReadOneByte(lineptr); - lineptr += 1; - - header_.opcode_base = reader_->ReadOneByte(lineptr); - lineptr += 1; - - header_.std_opcode_lengths = new std::vector<unsigned char>; - header_.std_opcode_lengths->resize(header_.opcode_base + 1); - (*header_.std_opcode_lengths)[0] = 0; - for (int i = 1; i < header_.opcode_base; i++) { - (*header_.std_opcode_lengths)[i] = reader_->ReadOneByte(lineptr); - lineptr += 1; - } - - // It is legal for the directory entry table to be empty. - if (*lineptr) { - uint32 dirindex = 1; - while (*lineptr) { - const char *dirname = reinterpret_cast<const char *>(lineptr); - handler_->DefineDir(dirname, dirindex); - lineptr += strlen(dirname) + 1; - dirindex++; - } - } - lineptr++; - - // It is also legal for the file entry table to be empty. - if (*lineptr) { - uint32 fileindex = 1; - size_t len; - while (*lineptr) { - const char *filename = reinterpret_cast<const char *>(lineptr); - lineptr += strlen(filename) + 1; - - uint64 dirindex = reader_->ReadUnsignedLEB128(lineptr, &len); - lineptr += len; - - uint64 mod_time = reader_->ReadUnsignedLEB128(lineptr, &len); - lineptr += len; - - uint64 filelength = reader_->ReadUnsignedLEB128(lineptr, &len); - lineptr += len; - handler_->DefineFile(filename, fileindex, static_cast<uint32>(dirindex), - mod_time, filelength); - fileindex++; - } - } - lineptr++; - - after_header_ = lineptr; -} - -/* static */ -bool LineInfo::ProcessOneOpcode(ByteReader* reader, - LineInfoHandler* handler, - const struct LineInfoHeader &header, - const uint8_t *start, - struct LineStateMachine* lsm, - size_t* len, - uintptr pc, - bool *lsm_passes_pc) { - size_t oplen = 0; - size_t templen; - uint8 opcode = reader->ReadOneByte(start); - oplen++; - start++; - - // If the opcode is great than the opcode_base, it is a special - // opcode. Most line programs consist mainly of special opcodes. - if (opcode >= header.opcode_base) { - opcode -= header.opcode_base; - const int64 advance_address = (opcode / header.line_range) - * header.min_insn_length; - const int32 advance_line = (opcode % header.line_range) - + header.line_base; - - // Check if the lsm passes "pc". If so, mark it as passed. - if (lsm_passes_pc && - lsm->address <= pc && pc < lsm->address + advance_address) { - *lsm_passes_pc = true; - } - - lsm->address += advance_address; - lsm->line_num += advance_line; - lsm->basic_block = true; - *len = oplen; - return true; - } - - // Otherwise, we have the regular opcodes - switch (opcode) { - case DW_LNS_copy: { - lsm->basic_block = false; - *len = oplen; - return true; - } - - case DW_LNS_advance_pc: { - uint64 advance_address = reader->ReadUnsignedLEB128(start, &templen); - oplen += templen; - - // Check if the lsm passes "pc". If so, mark it as passed. - if (lsm_passes_pc && lsm->address <= pc && - pc < lsm->address + header.min_insn_length * advance_address) { - *lsm_passes_pc = true; - } - - lsm->address += header.min_insn_length * advance_address; - } - break; - case DW_LNS_advance_line: { - const int64 advance_line = reader->ReadSignedLEB128(start, &templen); - oplen += templen; - lsm->line_num += static_cast<int32>(advance_line); - - // With gcc 4.2.1, we can get the line_no here for the first time - // since DW_LNS_advance_line is called after DW_LNE_set_address is - // called. So we check if the lsm passes "pc" here, not in - // DW_LNE_set_address. - if (lsm_passes_pc && lsm->address == pc) { - *lsm_passes_pc = true; - } - } - break; - case DW_LNS_set_file: { - const uint64 fileno = reader->ReadUnsignedLEB128(start, &templen); - oplen += templen; - lsm->file_num = static_cast<uint32>(fileno); - } - break; - case DW_LNS_set_column: { - const uint64 colno = reader->ReadUnsignedLEB128(start, &templen); - oplen += templen; - lsm->column_num = static_cast<uint32>(colno); - } - break; - case DW_LNS_negate_stmt: { - lsm->is_stmt = !lsm->is_stmt; - } - break; - case DW_LNS_set_basic_block: { - lsm->basic_block = true; - } - break; - case DW_LNS_fixed_advance_pc: { - const uint16 advance_address = reader->ReadTwoBytes(start); - oplen += 2; - - // Check if the lsm passes "pc". If so, mark it as passed. - if (lsm_passes_pc && - lsm->address <= pc && pc < lsm->address + advance_address) { - *lsm_passes_pc = true; - } - - lsm->address += advance_address; - } - break; - case DW_LNS_const_add_pc: { - const int64 advance_address = header.min_insn_length - * ((255 - header.opcode_base) - / header.line_range); - - // Check if the lsm passes "pc". If so, mark it as passed. - if (lsm_passes_pc && - lsm->address <= pc && pc < lsm->address + advance_address) { - *lsm_passes_pc = true; - } - - lsm->address += advance_address; - } - break; - case DW_LNS_extended_op: { - const uint64 extended_op_len = reader->ReadUnsignedLEB128(start, - &templen); - start += templen; - oplen += templen + extended_op_len; - - const uint64 extended_op = reader->ReadOneByte(start); - start++; - - switch (extended_op) { - case DW_LNE_end_sequence: { - lsm->end_sequence = true; - *len = oplen; - return true; - } - break; - case DW_LNE_set_address: { - // With gcc 4.2.1, we cannot tell the line_no here since - // DW_LNE_set_address is called before DW_LNS_advance_line is - // called. So we do not check if the lsm passes "pc" here. See - // also the comment in DW_LNS_advance_line. - uint64 address = reader->ReadAddress(start); - lsm->address = address; - } - break; - case DW_LNE_define_file: { - const char *filename = reinterpret_cast<const char *>(start); - - templen = strlen(filename) + 1; - start += templen; - - uint64 dirindex = reader->ReadUnsignedLEB128(start, &templen); - oplen += templen; - - const uint64 mod_time = reader->ReadUnsignedLEB128(start, - &templen); - oplen += templen; - - const uint64 filelength = reader->ReadUnsignedLEB128(start, - &templen); - oplen += templen; - - if (handler) { - handler->DefineFile(filename, -1, static_cast<uint32>(dirindex), - mod_time, filelength); - } - } - break; - } - } - break; - - default: { - // Ignore unknown opcode silently - if (header.std_opcode_lengths) { - for (int i = 0; i < (*header.std_opcode_lengths)[opcode]; i++) { - reader->ReadUnsignedLEB128(start, &templen); - start += templen; - oplen += templen; - } - } - } - break; - } - *len = oplen; - return false; -} - -void LineInfo::ReadLines() { - struct LineStateMachine lsm; - - // lengthstart is the place the length field is based on. - // It is the point in the header after the initial length field - const uint8_t *lengthstart = buffer_; - - // In 64 bit dwarf, the initial length is 12 bytes, because of the - // 0xffffffff at the start. - if (reader_->OffsetSize() == 8) - lengthstart += 12; - else - lengthstart += 4; - - const uint8_t *lineptr = after_header_; - lsm.Reset(header_.default_is_stmt); - - // The LineInfoHandler interface expects each line's length along - // with its address, but DWARF only provides addresses (sans - // length), and an end-of-sequence address; one infers the length - // from the next address. So we report a line only when we get the - // next line's address, or the end-of-sequence address. - bool have_pending_line = false; - uint64 pending_address = 0; - uint32 pending_file_num = 0, pending_line_num = 0, pending_column_num = 0; - - while (lineptr < lengthstart + header_.total_length) { - size_t oplength; - bool add_row = ProcessOneOpcode(reader_, handler_, header_, - lineptr, &lsm, &oplength, (uintptr)-1, - NULL); - if (add_row) { - if (have_pending_line) - handler_->AddLine(pending_address, lsm.address - pending_address, - pending_file_num, pending_line_num, - pending_column_num); - if (lsm.end_sequence) { - lsm.Reset(header_.default_is_stmt); - have_pending_line = false; - } else { - pending_address = lsm.address; - pending_file_num = lsm.file_num; - pending_line_num = lsm.line_num; - pending_column_num = lsm.column_num; - have_pending_line = true; - } - } - lineptr += oplength; - } - - after_header_ = lengthstart + header_.total_length; -} - -// A DWARF rule for recovering the address or value of a register, or -// computing the canonical frame address. There is one subclass of this for -// each '*Rule' member function in CallFrameInfo::Handler. -// -// It's annoying that we have to handle Rules using pointers (because -// the concrete instances can have an arbitrary size). They're small, -// so it would be much nicer if we could just handle them by value -// instead of fretting about ownership and destruction. -// -// It seems like all these could simply be instances of std::tr1::bind, -// except that we need instances to be EqualityComparable, too. -// -// This could logically be nested within State, but then the qualified names -// get horrendous. -class CallFrameInfo::Rule { - public: - virtual ~Rule() { } - - // Tell HANDLER that, at ADDRESS in the program, REGISTER can be - // recovered using this rule. If REGISTER is kCFARegister, then this rule - // describes how to compute the canonical frame address. Return what the - // HANDLER member function returned. - virtual bool Handle(Handler *handler, - uint64 address, int register) const = 0; - - // Equality on rules. We use these to decide which rules we need - // to report after a DW_CFA_restore_state instruction. - virtual bool operator==(const Rule &rhs) const = 0; - - bool operator!=(const Rule &rhs) const { return ! (*this == rhs); } - - // Return a pointer to a copy of this rule. - virtual Rule *Copy() const = 0; - - // If this is a base+offset rule, change its base register to REG. - // Otherwise, do nothing. (Ugly, but required for DW_CFA_def_cfa_register.) - virtual void SetBaseRegister(unsigned reg) { } - - // If this is a base+offset rule, change its offset to OFFSET. Otherwise, - // do nothing. (Ugly, but required for DW_CFA_def_cfa_offset.) - virtual void SetOffset(long long offset) { } -}; - -// Rule: the value the register had in the caller cannot be recovered. -class CallFrameInfo::UndefinedRule: public CallFrameInfo::Rule { - public: - UndefinedRule() { } - ~UndefinedRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->UndefinedRule(address, reg); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const UndefinedRule *our_rhs = dynamic_cast<const UndefinedRule *>(&rhs); - return (our_rhs != NULL); - } - Rule *Copy() const { return new UndefinedRule(*this); } -}; - -// Rule: the register's value is the same as that it had in the caller. -class CallFrameInfo::SameValueRule: public CallFrameInfo::Rule { - public: - SameValueRule() { } - ~SameValueRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->SameValueRule(address, reg); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const SameValueRule *our_rhs = dynamic_cast<const SameValueRule *>(&rhs); - return (our_rhs != NULL); - } - Rule *Copy() const { return new SameValueRule(*this); } -}; - -// Rule: the register is saved at OFFSET from BASE_REGISTER. BASE_REGISTER -// may be CallFrameInfo::Handler::kCFARegister. -class CallFrameInfo::OffsetRule: public CallFrameInfo::Rule { - public: - OffsetRule(int base_register, long offset) - : base_register_(base_register), offset_(offset) { } - ~OffsetRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->OffsetRule(address, reg, base_register_, offset_); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const OffsetRule *our_rhs = dynamic_cast<const OffsetRule *>(&rhs); - return (our_rhs && - base_register_ == our_rhs->base_register_ && - offset_ == our_rhs->offset_); - } - Rule *Copy() const { return new OffsetRule(*this); } - // We don't actually need SetBaseRegister or SetOffset here, since they - // are only ever applied to CFA rules, for DW_CFA_def_cfa_offset, and it - // doesn't make sense to use OffsetRule for computing the CFA: it - // computes the address at which a register is saved, not a value. - private: - int base_register_; - long offset_; -}; - -// Rule: the value the register had in the caller is the value of -// BASE_REGISTER plus offset. BASE_REGISTER may be -// CallFrameInfo::Handler::kCFARegister. -class CallFrameInfo::ValOffsetRule: public CallFrameInfo::Rule { - public: - ValOffsetRule(int base_register, long offset) - : base_register_(base_register), offset_(offset) { } - ~ValOffsetRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->ValOffsetRule(address, reg, base_register_, offset_); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const ValOffsetRule *our_rhs = dynamic_cast<const ValOffsetRule *>(&rhs); - return (our_rhs && - base_register_ == our_rhs->base_register_ && - offset_ == our_rhs->offset_); - } - Rule *Copy() const { return new ValOffsetRule(*this); } - void SetBaseRegister(unsigned reg) { base_register_ = reg; } - void SetOffset(long long offset) { offset_ = offset; } - private: - int base_register_; - long offset_; -}; - -// Rule: the register has been saved in another register REGISTER_NUMBER_. -class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule { - public: - explicit RegisterRule(int register_number) - : register_number_(register_number) { } - ~RegisterRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->RegisterRule(address, reg, register_number_); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const RegisterRule *our_rhs = dynamic_cast<const RegisterRule *>(&rhs); - return (our_rhs && register_number_ == our_rhs->register_number_); - } - Rule *Copy() const { return new RegisterRule(*this); } - private: - int register_number_; -}; - -// Rule: EXPRESSION evaluates to the address at which the register is saved. -class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule { - public: - explicit ExpressionRule(const string &expression) - : expression_(expression) { } - ~ExpressionRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->ExpressionRule(address, reg, expression_); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const ExpressionRule *our_rhs = dynamic_cast<const ExpressionRule *>(&rhs); - return (our_rhs && expression_ == our_rhs->expression_); - } - Rule *Copy() const { return new ExpressionRule(*this); } - private: - string expression_; -}; - -// Rule: EXPRESSION evaluates to the address at which the register is saved. -class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule { - public: - explicit ValExpressionRule(const string &expression) - : expression_(expression) { } - ~ValExpressionRule() { } - bool Handle(Handler *handler, uint64 address, int reg) const { - return handler->ValExpressionRule(address, reg, expression_); - } - bool operator==(const Rule &rhs) const { - // dynamic_cast is allowed by the Google C++ Style Guide, if the use has - // been carefully considered; cheap RTTI-like workarounds are forbidden. - const ValExpressionRule *our_rhs = - dynamic_cast<const ValExpressionRule *>(&rhs); - return (our_rhs && expression_ == our_rhs->expression_); - } - Rule *Copy() const { return new ValExpressionRule(*this); } - private: - string expression_; -}; - -// A map from register numbers to rules. -class CallFrameInfo::RuleMap { - public: - RuleMap() : cfa_rule_(NULL) { } - RuleMap(const RuleMap &rhs) : cfa_rule_(NULL) { *this = rhs; } - ~RuleMap() { Clear(); } - - RuleMap &operator=(const RuleMap &rhs); - - // Set the rule for computing the CFA to RULE. Take ownership of RULE. - void SetCFARule(Rule *rule) { delete cfa_rule_; cfa_rule_ = rule; } - - // Return the current CFA rule. Unlike RegisterRule, this RuleMap retains - // ownership of the rule. We use this for DW_CFA_def_cfa_offset and - // DW_CFA_def_cfa_register, and for detecting references to the CFA before - // a rule for it has been established. - Rule *CFARule() const { return cfa_rule_; } - - // Return the rule for REG, or NULL if there is none. The caller takes - // ownership of the result. - Rule *RegisterRule(int reg) const; - - // Set the rule for computing REG to RULE. Take ownership of RULE. - void SetRegisterRule(int reg, Rule *rule); - - // Make all the appropriate calls to HANDLER as if we were changing from - // this RuleMap to NEW_RULES at ADDRESS. We use this to implement - // DW_CFA_restore_state, where lots of rules can change simultaneously. - // Return true if all handlers returned true; otherwise, return false. - bool HandleTransitionTo(Handler *handler, uint64 address, - const RuleMap &new_rules) const; - - private: - // A map from register numbers to Rules. - typedef std::map<int, Rule *> RuleByNumber; - - // Remove all register rules and clear cfa_rule_. - void Clear(); - - // The rule for computing the canonical frame address. This RuleMap owns - // this rule. - Rule *cfa_rule_; - - // A map from register numbers to postfix expressions to recover - // their values. This RuleMap owns the Rules the map refers to. - RuleByNumber registers_; -}; - -CallFrameInfo::RuleMap &CallFrameInfo::RuleMap::operator=(const RuleMap &rhs) { - Clear(); - // Since each map owns the rules it refers to, assignment must copy them. - if (rhs.cfa_rule_) cfa_rule_ = rhs.cfa_rule_->Copy(); - for (RuleByNumber::const_iterator it = rhs.registers_.begin(); - it != rhs.registers_.end(); it++) - registers_[it->first] = it->second->Copy(); - return *this; -} - -CallFrameInfo::Rule *CallFrameInfo::RuleMap::RegisterRule(int reg) const { - assert(reg != Handler::kCFARegister); - RuleByNumber::const_iterator it = registers_.find(reg); - if (it != registers_.end()) - return it->second->Copy(); - else - return NULL; -} - -void CallFrameInfo::RuleMap::SetRegisterRule(int reg, Rule *rule) { - assert(reg != Handler::kCFARegister); - assert(rule); - Rule **slot = ®isters_[reg]; - delete *slot; - *slot = rule; -} - -bool CallFrameInfo::RuleMap::HandleTransitionTo( - Handler *handler, - uint64 address, - const RuleMap &new_rules) const { - // Transition from cfa_rule_ to new_rules.cfa_rule_. - if (cfa_rule_ && new_rules.cfa_rule_) { - if (*cfa_rule_ != *new_rules.cfa_rule_ && - !new_rules.cfa_rule_->Handle(handler, address, - Handler::kCFARegister)) - return false; - } else if (cfa_rule_) { - // this RuleMap has a CFA rule but new_rules doesn't. - // CallFrameInfo::Handler has no way to handle this --- and shouldn't; - // it's garbage input. The instruction interpreter should have - // detected this and warned, so take no action here. - } else if (new_rules.cfa_rule_) { - // This shouldn't be possible: NEW_RULES is some prior state, and - // there's no way to remove entries. - assert(0); - } else { - // Both CFA rules are empty. No action needed. - } - - // Traverse the two maps in order by register number, and report - // whatever differences we find. - RuleByNumber::const_iterator old_it = registers_.begin(); - RuleByNumber::const_iterator new_it = new_rules.registers_.begin(); - while (old_it != registers_.end() && new_it != new_rules.registers_.end()) { - if (old_it->first < new_it->first) { - // This RuleMap has an entry for old_it->first, but NEW_RULES - // doesn't. - // - // This isn't really the right thing to do, but since CFI generally - // only mentions callee-saves registers, and GCC's convention for - // callee-saves registers is that they are unchanged, it's a good - // approximation. - if (!handler->SameValueRule(address, old_it->first)) - return false; - old_it++; - } else if (old_it->first > new_it->first) { - // NEW_RULES has entry for new_it->first, but this RuleMap - // doesn't. This shouldn't be possible: NEW_RULES is some prior - // state, and there's no way to remove entries. - assert(0); - } else { - // Both maps have an entry for this register. Report the new - // rule if it is different. - if (*old_it->second != *new_it->second && - !new_it->second->Handle(handler, address, new_it->first)) - return false; - new_it++, old_it++; - } - } - // Finish off entries from this RuleMap with no counterparts in new_rules. - while (old_it != registers_.end()) { - if (!handler->SameValueRule(address, old_it->first)) - return false; - old_it++; - } - // Since we only make transitions from a rule set to some previously - // saved rule set, and we can only add rules to the map, NEW_RULES - // must have fewer rules than *this. - assert(new_it == new_rules.registers_.end()); - - return true; -} - -// Remove all register rules and clear cfa_rule_. -void CallFrameInfo::RuleMap::Clear() { - delete cfa_rule_; - cfa_rule_ = NULL; - for (RuleByNumber::iterator it = registers_.begin(); - it != registers_.end(); it++) - delete it->second; - registers_.clear(); -} - -// The state of the call frame information interpreter as it processes -// instructions from a CIE and FDE. -class CallFrameInfo::State { - public: - // Create a call frame information interpreter state with the given - // reporter, reader, handler, and initial call frame info address. - State(ByteReader *reader, Handler *handler, Reporter *reporter, - uint64 address) - : reader_(reader), handler_(handler), reporter_(reporter), - address_(address), entry_(NULL), cursor_(NULL) { } - - // Interpret instructions from CIE, save the resulting rule set for - // DW_CFA_restore instructions, and return true. On error, report - // the problem to reporter_ and return false. - bool InterpretCIE(const CIE &cie); - - // Interpret instructions from FDE, and return true. On error, - // report the problem to reporter_ and return false. - bool InterpretFDE(const FDE &fde); - - private: - // The operands of a CFI instruction, for ParseOperands. - struct Operands { - unsigned register_number; // A register number. - uint64 offset; // An offset or address. - long signed_offset; // A signed offset. - string expression; // A DWARF expression. - }; - - // Parse CFI instruction operands from STATE's instruction stream as - // described by FORMAT. On success, populate OPERANDS with the - // results, and return true. On failure, report the problem and - // return false. - // - // Each character of FORMAT should be one of the following: - // - // 'r' unsigned LEB128 register number (OPERANDS->register_number) - // 'o' unsigned LEB128 offset (OPERANDS->offset) - // 's' signed LEB128 offset (OPERANDS->signed_offset) - // 'a' machine-size address (OPERANDS->offset) - // (If the CIE has a 'z' augmentation string, 'a' uses the - // encoding specified by the 'R' argument.) - // '1' a one-byte offset (OPERANDS->offset) - // '2' a two-byte offset (OPERANDS->offset) - // '4' a four-byte offset (OPERANDS->offset) - // '8' an eight-byte offset (OPERANDS->offset) - // 'e' a DW_FORM_block holding a (OPERANDS->expression) - // DWARF expression - bool ParseOperands(const char *format, Operands *operands); - - // Interpret one CFI instruction from STATE's instruction stream, update - // STATE, report any rule changes to handler_, and return true. On - // failure, report the problem and return false. - bool DoInstruction(); - - // The following Do* member functions are subroutines of DoInstruction, - // factoring out the actual work of operations that have several - // different encodings. - - // Set the CFA rule to be the value of BASE_REGISTER plus OFFSET, and - // return true. On failure, report and return false. (Used for - // DW_CFA_def_cfa and DW_CFA_def_cfa_sf.) - bool DoDefCFA(unsigned base_register, long offset); - - // Change the offset of the CFA rule to OFFSET, and return true. On - // failure, report and return false. (Subroutine for - // DW_CFA_def_cfa_offset and DW_CFA_def_cfa_offset_sf.) - bool DoDefCFAOffset(long offset); - - // Specify that REG can be recovered using RULE, and return true. On - // failure, report and return false. - bool DoRule(unsigned reg, Rule *rule); - - // Specify that REG can be found at OFFSET from the CFA, and return true. - // On failure, report and return false. (Subroutine for DW_CFA_offset, - // DW_CFA_offset_extended, and DW_CFA_offset_extended_sf.) - bool DoOffset(unsigned reg, long offset); - - // Specify that the caller's value for REG is the CFA plus OFFSET, - // and return true. On failure, report and return false. (Subroutine - // for DW_CFA_val_offset and DW_CFA_val_offset_sf.) - bool DoValOffset(unsigned reg, long offset); - - // Restore REG to the rule established in the CIE, and return true. On - // failure, report and return false. (Subroutine for DW_CFA_restore and - // DW_CFA_restore_extended.) - bool DoRestore(unsigned reg); - - // Return the section offset of the instruction at cursor. For use - // in error messages. - uint64 CursorOffset() { return entry_->offset + (cursor_ - entry_->start); } - - // Report that entry_ is incomplete, and return false. For brevity. - bool ReportIncomplete() { - reporter_->Incomplete(entry_->offset, entry_->kind); - return false; - } - - // For reading multi-byte values with the appropriate endianness. - ByteReader *reader_; - - // The handler to which we should report the data we find. - Handler *handler_; - - // For reporting problems in the info we're parsing. - Reporter *reporter_; - - // The code address to which the next instruction in the stream applies. - uint64 address_; - - // The entry whose instructions we are currently processing. This is - // first a CIE, and then an FDE. - const Entry *entry_; - - // The next instruction to process. - const uint8_t *cursor_; - - // The current set of rules. - RuleMap rules_; - - // The set of rules established by the CIE, used by DW_CFA_restore - // and DW_CFA_restore_extended. We set this after interpreting the - // CIE's instructions. - RuleMap cie_rules_; - - // A stack of saved states, for DW_CFA_remember_state and - // DW_CFA_restore_state. - std::stack<RuleMap> saved_rules_; -}; - -bool CallFrameInfo::State::InterpretCIE(const CIE &cie) { - entry_ = &cie; - cursor_ = entry_->instructions; - while (cursor_ < entry_->end) - if (!DoInstruction()) - return false; - // Note the rules established by the CIE, for use by DW_CFA_restore - // and DW_CFA_restore_extended. - cie_rules_ = rules_; - return true; -} - -bool CallFrameInfo::State::InterpretFDE(const FDE &fde) { - entry_ = &fde; - cursor_ = entry_->instructions; - while (cursor_ < entry_->end) - if (!DoInstruction()) - return false; - return true; -} - -bool CallFrameInfo::State::ParseOperands(const char *format, - Operands *operands) { - size_t len; - const char *operand; - - for (operand = format; *operand; operand++) { - size_t bytes_left = entry_->end - cursor_; - switch (*operand) { - case 'r': - operands->register_number = reader_->ReadUnsignedLEB128(cursor_, &len); - if (len > bytes_left) return ReportIncomplete(); - cursor_ += len; - break; - - case 'o': - operands->offset = reader_->ReadUnsignedLEB128(cursor_, &len); - if (len > bytes_left) return ReportIncomplete(); - cursor_ += len; - break; - - case 's': - operands->signed_offset = reader_->ReadSignedLEB128(cursor_, &len); - if (len > bytes_left) return ReportIncomplete(); - cursor_ += len; - break; - - case 'a': - operands->offset = - reader_->ReadEncodedPointer(cursor_, entry_->cie->pointer_encoding, - &len); - if (len > bytes_left) return ReportIncomplete(); - cursor_ += len; - break; - - case '1': - if (1 > bytes_left) return ReportIncomplete(); - operands->offset = static_cast<unsigned char>(*cursor_++); - break; - - case '2': - if (2 > bytes_left) return ReportIncomplete(); - operands->offset = reader_->ReadTwoBytes(cursor_); - cursor_ += 2; - break; - - case '4': - if (4 > bytes_left) return ReportIncomplete(); - operands->offset = reader_->ReadFourBytes(cursor_); - cursor_ += 4; - break; - - case '8': - if (8 > bytes_left) return ReportIncomplete(); - operands->offset = reader_->ReadEightBytes(cursor_); - cursor_ += 8; - break; - - case 'e': { - size_t expression_length = reader_->ReadUnsignedLEB128(cursor_, &len); - if (len > bytes_left || expression_length > bytes_left - len) - return ReportIncomplete(); - cursor_ += len; - operands->expression = string(reinterpret_cast<const char *>(cursor_), - expression_length); - cursor_ += expression_length; - break; - } - - default: - assert(0); - } - } - - return true; -} - -bool CallFrameInfo::State::DoInstruction() { - CIE *cie = entry_->cie; - Operands ops; - - // Our entry's kind should have been set by now. - assert(entry_->kind != kUnknown); - - // We shouldn't have been invoked unless there were more - // instructions to parse. - assert(cursor_ < entry_->end); - - unsigned opcode = *cursor_++; - if ((opcode & 0xc0) != 0) { - switch (opcode & 0xc0) { - // Advance the address. - case DW_CFA_advance_loc: { - size_t code_offset = opcode & 0x3f; - address_ += code_offset * cie->code_alignment_factor; - break; - } - - // Find a register at an offset from the CFA. - case DW_CFA_offset: - if (!ParseOperands("o", &ops) || - !DoOffset(opcode & 0x3f, ops.offset * cie->data_alignment_factor)) - return false; - break; - - // Restore the rule established for a register by the CIE. - case DW_CFA_restore: - if (!DoRestore(opcode & 0x3f)) return false; - break; - - // The 'if' above should have excluded this possibility. - default: - assert(0); - } - - // Return here, so the big switch below won't be indented. - return true; - } - - switch (opcode) { - // Set the address. - case DW_CFA_set_loc: - if (!ParseOperands("a", &ops)) return false; - address_ = ops.offset; - break; - - // Advance the address. - case DW_CFA_advance_loc1: - if (!ParseOperands("1", &ops)) return false; - address_ += ops.offset * cie->code_alignment_factor; - break; - - // Advance the address. - case DW_CFA_advance_loc2: - if (!ParseOperands("2", &ops)) return false; - address_ += ops.offset * cie->code_alignment_factor; - break; - - // Advance the address. - case DW_CFA_advance_loc4: - if (!ParseOperands("4", &ops)) return false; - address_ += ops.offset * cie->code_alignment_factor; - break; - - // Advance the address. - case DW_CFA_MIPS_advance_loc8: - if (!ParseOperands("8", &ops)) return false; - address_ += ops.offset * cie->code_alignment_factor; - break; - - // Compute the CFA by adding an offset to a register. - case DW_CFA_def_cfa: - if (!ParseOperands("ro", &ops) || - !DoDefCFA(ops.register_number, ops.offset)) - return false; - break; - - // Compute the CFA by adding an offset to a register. - case DW_CFA_def_cfa_sf: - if (!ParseOperands("rs", &ops) || - !DoDefCFA(ops.register_number, - ops.signed_offset * cie->data_alignment_factor)) - return false; - break; - - // Change the base register used to compute the CFA. - case DW_CFA_def_cfa_register: { - if (!ParseOperands("r", &ops)) return false; - Rule *cfa_rule = rules_.CFARule(); - if (!cfa_rule) { - if (!DoDefCFA(ops.register_number, ops.offset)) { - reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); - return false; - } - } else { - cfa_rule->SetBaseRegister(ops.register_number); - if (!cfa_rule->Handle(handler_, address_, - Handler::kCFARegister)) - return false; - } - break; - } - - // Change the offset used to compute the CFA. - case DW_CFA_def_cfa_offset: - if (!ParseOperands("o", &ops) || - !DoDefCFAOffset(ops.offset)) - return false; - break; - - // Change the offset used to compute the CFA. - case DW_CFA_def_cfa_offset_sf: - if (!ParseOperands("s", &ops) || - !DoDefCFAOffset(ops.signed_offset * cie->data_alignment_factor)) - return false; - break; - - // Specify an expression whose value is the CFA. - case DW_CFA_def_cfa_expression: { - if (!ParseOperands("e", &ops)) - return false; - Rule *rule = new ValExpressionRule(ops.expression); - rules_.SetCFARule(rule); - if (!rule->Handle(handler_, address_, - Handler::kCFARegister)) - return false; - break; - } - - // The register's value cannot be recovered. - case DW_CFA_undefined: { - if (!ParseOperands("r", &ops) || - !DoRule(ops.register_number, new UndefinedRule())) - return false; - break; - } - - // The register's value is unchanged from its value in the caller. - case DW_CFA_same_value: { - if (!ParseOperands("r", &ops) || - !DoRule(ops.register_number, new SameValueRule())) - return false; - break; - } - - // Find a register at an offset from the CFA. - case DW_CFA_offset_extended: - if (!ParseOperands("ro", &ops) || - !DoOffset(ops.register_number, - ops.offset * cie->data_alignment_factor)) - return false; - break; - - // The register is saved at an offset from the CFA. - case DW_CFA_offset_extended_sf: - if (!ParseOperands("rs", &ops) || - !DoOffset(ops.register_number, - ops.signed_offset * cie->data_alignment_factor)) - return false; - break; - - // The register is saved at an offset from the CFA. - case DW_CFA_GNU_negative_offset_extended: - if (!ParseOperands("ro", &ops) || - !DoOffset(ops.register_number, - -ops.offset * cie->data_alignment_factor)) - return false; - break; - - // The register's value is the sum of the CFA plus an offset. - case DW_CFA_val_offset: - if (!ParseOperands("ro", &ops) || - !DoValOffset(ops.register_number, - ops.offset * cie->data_alignment_factor)) - return false; - break; - - // The register's value is the sum of the CFA plus an offset. - case DW_CFA_val_offset_sf: - if (!ParseOperands("rs", &ops) || - !DoValOffset(ops.register_number, - ops.signed_offset * cie->data_alignment_factor)) - return false; - break; - - // The register has been saved in another register. - case DW_CFA_register: { - if (!ParseOperands("ro", &ops) || - !DoRule(ops.register_number, new RegisterRule(ops.offset))) - return false; - break; - } - - // An expression yields the address at which the register is saved. - case DW_CFA_expression: { - if (!ParseOperands("re", &ops) || - !DoRule(ops.register_number, new ExpressionRule(ops.expression))) - return false; - break; - } - - // An expression yields the caller's value for the register. - case DW_CFA_val_expression: { - if (!ParseOperands("re", &ops) || - !DoRule(ops.register_number, new ValExpressionRule(ops.expression))) - return false; - break; - } - - // Restore the rule established for a register by the CIE. - case DW_CFA_restore_extended: - if (!ParseOperands("r", &ops) || - !DoRestore( ops.register_number)) - return false; - break; - - // Save the current set of rules on a stack. - case DW_CFA_remember_state: - saved_rules_.push(rules_); - break; - - // Pop the current set of rules off the stack. - case DW_CFA_restore_state: { - if (saved_rules_.empty()) { - reporter_->EmptyStateStack(entry_->offset, entry_->kind, - CursorOffset()); - return false; - } - const RuleMap &new_rules = saved_rules_.top(); - if (rules_.CFARule() && !new_rules.CFARule()) { - reporter_->ClearingCFARule(entry_->offset, entry_->kind, - CursorOffset()); - return false; - } - rules_.HandleTransitionTo(handler_, address_, new_rules); - rules_ = new_rules; - saved_rules_.pop(); - break; - } - - // No operation. (Padding instruction.) - case DW_CFA_nop: - break; - - // A SPARC register window save: Registers 8 through 15 (%o0-%o7) - // are saved in registers 24 through 31 (%i0-%i7), and registers - // 16 through 31 (%l0-%l7 and %i0-%i7) are saved at CFA offsets - // (0-15 * the register size). The register numbers must be - // hard-coded. A GNU extension, and not a pretty one. - case DW_CFA_GNU_window_save: { - // Save %o0-%o7 in %i0-%i7. - for (int i = 8; i < 16; i++) - if (!DoRule(i, new RegisterRule(i + 16))) - return false; - // Save %l0-%l7 and %i0-%i7 at the CFA. - for (int i = 16; i < 32; i++) - // Assume that the byte reader's address size is the same as - // the architecture's register size. !@#%*^ hilarious. - if (!DoRule(i, new OffsetRule(Handler::kCFARegister, - (i - 16) * reader_->AddressSize()))) - return false; - break; - } - - // I'm not sure what this is. GDB doesn't use it for unwinding. - case DW_CFA_GNU_args_size: - if (!ParseOperands("o", &ops)) return false; - break; - - // An opcode we don't recognize. - default: { - reporter_->BadInstruction(entry_->offset, entry_->kind, CursorOffset()); - return false; - } - } - - return true; -} - -bool CallFrameInfo::State::DoDefCFA(unsigned base_register, long offset) { - Rule *rule = new ValOffsetRule(base_register, offset); - rules_.SetCFARule(rule); - return rule->Handle(handler_, address_, - Handler::kCFARegister); -} - -bool CallFrameInfo::State::DoDefCFAOffset(long offset) { - Rule *cfa_rule = rules_.CFARule(); - if (!cfa_rule) { - reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); - return false; - } - cfa_rule->SetOffset(offset); - return cfa_rule->Handle(handler_, address_, - Handler::kCFARegister); -} - -bool CallFrameInfo::State::DoRule(unsigned reg, Rule *rule) { - rules_.SetRegisterRule(reg, rule); - return rule->Handle(handler_, address_, reg); -} - -bool CallFrameInfo::State::DoOffset(unsigned reg, long offset) { - if (!rules_.CFARule()) { - reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); - return false; - } - return DoRule(reg, - new OffsetRule(Handler::kCFARegister, offset)); -} - -bool CallFrameInfo::State::DoValOffset(unsigned reg, long offset) { - if (!rules_.CFARule()) { - reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset()); - return false; - } - return DoRule(reg, - new ValOffsetRule(Handler::kCFARegister, offset)); -} - -bool CallFrameInfo::State::DoRestore(unsigned reg) { - // DW_CFA_restore and DW_CFA_restore_extended don't make sense in a CIE. - if (entry_->kind == kCIE) { - reporter_->RestoreInCIE(entry_->offset, CursorOffset()); - return false; - } - Rule *rule = cie_rules_.RegisterRule(reg); - if (!rule) { - // This isn't really the right thing to do, but since CFI generally - // only mentions callee-saves registers, and GCC's convention for - // callee-saves registers is that they are unchanged, it's a good - // approximation. - rule = new SameValueRule(); - } - return DoRule(reg, rule); -} - -bool CallFrameInfo::ReadEntryPrologue(const uint8_t *cursor, Entry *entry) { - const uint8_t *buffer_end = buffer_ + buffer_length_; - - // Initialize enough of ENTRY for use in error reporting. - entry->offset = cursor - buffer_; - entry->start = cursor; - entry->kind = kUnknown; - entry->end = NULL; - - // Read the initial length. This sets reader_'s offset size. - size_t length_size; - uint64 length = reader_->ReadInitialLength(cursor, &length_size); - if (length_size > size_t(buffer_end - cursor)) - return ReportIncomplete(entry); - cursor += length_size; - - // In a .eh_frame section, a length of zero marks the end of the series - // of entries. - if (length == 0 && eh_frame_) { - entry->kind = kTerminator; - entry->end = cursor; - return true; - } - - // Validate the length. - if (length > size_t(buffer_end - cursor)) - return ReportIncomplete(entry); - - // The length is the number of bytes after the initial length field; - // we have that position handy at this point, so compute the end - // now. (If we're parsing 64-bit-offset DWARF on a 32-bit machine, - // and the length didn't fit in a size_t, we would have rejected it - // above.) - entry->end = cursor + length; - - // Parse the next field: either the offset of a CIE or a CIE id. - size_t offset_size = reader_->OffsetSize(); - if (offset_size > size_t(entry->end - cursor)) return ReportIncomplete(entry); - entry->id = reader_->ReadOffset(cursor); - - // Don't advance cursor past id field yet; in .eh_frame data we need - // the id's position to compute the section offset of an FDE's CIE. - - // Now we can decide what kind of entry this is. - if (eh_frame_) { - // In .eh_frame data, an ID of zero marks the entry as a CIE, and - // anything else is an offset from the id field of the FDE to the start - // of the CIE. - if (entry->id == 0) { - entry->kind = kCIE; - } else { - entry->kind = kFDE; - // Turn the offset from the id into an offset from the buffer's start. - entry->id = (cursor - buffer_) - entry->id; - } - } else { - // In DWARF CFI data, an ID of ~0 (of the appropriate width, given the - // offset size for the entry) marks the entry as a CIE, and anything - // else is the offset of the CIE from the beginning of the section. - if (offset_size == 4) - entry->kind = (entry->id == 0xffffffff) ? kCIE : kFDE; - else { - assert(offset_size == 8); - entry->kind = (entry->id == 0xffffffffffffffffULL) ? kCIE : kFDE; - } - } - - // Now advance cursor past the id. - cursor += offset_size; - - // The fields specific to this kind of entry start here. - entry->fields = cursor; - - entry->cie = NULL; - - return true; -} - -bool CallFrameInfo::ReadCIEFields(CIE *cie) { - const uint8_t *cursor = cie->fields; - size_t len; - - assert(cie->kind == kCIE); - - // Prepare for early exit. - cie->version = 0; - cie->augmentation.clear(); - cie->code_alignment_factor = 0; - cie->data_alignment_factor = 0; - cie->return_address_register = 0; - cie->has_z_augmentation = false; - cie->pointer_encoding = DW_EH_PE_absptr; - cie->instructions = 0; - - // Parse the version number. - if (cie->end - cursor < 1) - return ReportIncomplete(cie); - cie->version = reader_->ReadOneByte(cursor); - cursor++; - - // If we don't recognize the version, we can't parse any more fields of the - // CIE. For DWARF CFI, we handle versions 1 through 3 (there was never a - // version 2 of CFI data). For .eh_frame, we handle versions 1 and 3 as well; - // the difference between those versions seems to be the same as for - // .debug_frame. - if (cie->version < 1 || cie->version > 3) { - reporter_->UnrecognizedVersion(cie->offset, cie->version); - return false; - } - - const uint8_t *augmentation_start = cursor; - const uint8_t *augmentation_end = - reinterpret_cast<const uint8_t *>(memchr(augmentation_start, '\0', - cie->end - augmentation_start)); - if (! augmentation_end) return ReportIncomplete(cie); - cursor = augmentation_end; - cie->augmentation = string(reinterpret_cast<const char *>(augmentation_start), - cursor - augmentation_start); - // Skip the terminating '\0'. - cursor++; - - // Is this CFI augmented? - if (!cie->augmentation.empty()) { - // Is it an augmentation we recognize? - if (cie->augmentation[0] == DW_Z_augmentation_start) { - // Linux C++ ABI 'z' augmentation, used for exception handling data. - cie->has_z_augmentation = true; - } else { - // Not an augmentation we recognize. Augmentations can have arbitrary - // effects on the form of rest of the content, so we have to give up. - reporter_->UnrecognizedAugmentation(cie->offset, cie->augmentation); - return false; - } - } - - // Parse the code alignment factor. - cie->code_alignment_factor = reader_->ReadUnsignedLEB128(cursor, &len); - if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); - cursor += len; - - // Parse the data alignment factor. - cie->data_alignment_factor = reader_->ReadSignedLEB128(cursor, &len); - if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); - cursor += len; - - // Parse the return address register. This is a ubyte in version 1, and - // a ULEB128 in version 3. - if (cie->version == 1) { - if (cursor >= cie->end) return ReportIncomplete(cie); - cie->return_address_register = uint8(*cursor++); - } else { - cie->return_address_register = reader_->ReadUnsignedLEB128(cursor, &len); - if (size_t(cie->end - cursor) < len) return ReportIncomplete(cie); - cursor += len; - } - - // If we have a 'z' augmentation string, find the augmentation data and - // use the augmentation string to parse it. - if (cie->has_z_augmentation) { - uint64_t data_size = reader_->ReadUnsignedLEB128(cursor, &len); - if (size_t(cie->end - cursor) < len + data_size) - return ReportIncomplete(cie); - cursor += len; - const uint8_t *data = cursor; - cursor += data_size; - const uint8_t *data_end = cursor; - - cie->has_z_lsda = false; - cie->has_z_personality = false; - cie->has_z_signal_frame = false; - - // Walk the augmentation string, and extract values from the - // augmentation data as the string directs. - for (size_t i = 1; i < cie->augmentation.size(); i++) { - switch (cie->augmentation[i]) { - case DW_Z_has_LSDA: - // The CIE's augmentation data holds the language-specific data - // area pointer's encoding, and the FDE's augmentation data holds - // the pointer itself. - cie->has_z_lsda = true; - // Fetch the LSDA encoding from the augmentation data. - if (data >= data_end) return ReportIncomplete(cie); - cie->lsda_encoding = DwarfPointerEncoding(*data++); - if (!reader_->ValidEncoding(cie->lsda_encoding)) { - reporter_->InvalidPointerEncoding(cie->offset, cie->lsda_encoding); - return false; - } - // Don't check if the encoding is usable here --- we haven't - // read the FDE's fields yet, so we're not prepared for - // DW_EH_PE_funcrel, although that's a fine encoding for the - // LSDA to use, since it appears in the FDE. - break; - - case DW_Z_has_personality_routine: - // The CIE's augmentation data holds the personality routine - // pointer's encoding, followed by the pointer itself. - cie->has_z_personality = true; - // Fetch the personality routine pointer's encoding from the - // augmentation data. - if (data >= data_end) return ReportIncomplete(cie); - cie->personality_encoding = DwarfPointerEncoding(*data++); - if (!reader_->ValidEncoding(cie->personality_encoding)) { - reporter_->InvalidPointerEncoding(cie->offset, - cie->personality_encoding); - return false; - } - if (!reader_->UsableEncoding(cie->personality_encoding)) { - reporter_->UnusablePointerEncoding(cie->offset, - cie->personality_encoding); - return false; - } - // Fetch the personality routine's pointer itself from the data. - cie->personality_address = - reader_->ReadEncodedPointer(data, cie->personality_encoding, - &len); - if (len > size_t(data_end - data)) - return ReportIncomplete(cie); - data += len; - break; - - case DW_Z_has_FDE_address_encoding: - // The CIE's augmentation data holds the pointer encoding to use - // for addresses in the FDE. - if (data >= data_end) return ReportIncomplete(cie); - cie->pointer_encoding = DwarfPointerEncoding(*data++); - if (!reader_->ValidEncoding(cie->pointer_encoding)) { - reporter_->InvalidPointerEncoding(cie->offset, - cie->pointer_encoding); - return false; - } - if (!reader_->UsableEncoding(cie->pointer_encoding)) { - reporter_->UnusablePointerEncoding(cie->offset, - cie->pointer_encoding); - return false; - } - break; - - case DW_Z_is_signal_trampoline: - // Frames using this CIE are signal delivery frames. - cie->has_z_signal_frame = true; - break; - - default: - // An augmentation we don't recognize. - reporter_->UnrecognizedAugmentation(cie->offset, cie->augmentation); - return false; - } - } - } - - // The CIE's instructions start here. - cie->instructions = cursor; - - return true; -} - -bool CallFrameInfo::ReadFDEFields(FDE *fde) { - const uint8_t *cursor = fde->fields; - size_t size; - - fde->address = reader_->ReadEncodedPointer(cursor, fde->cie->pointer_encoding, - &size); - if (size > size_t(fde->end - cursor)) - return ReportIncomplete(fde); - cursor += size; - reader_->SetFunctionBase(fde->address); - - // For the length, we strip off the upper nybble of the encoding used for - // the starting address. - DwarfPointerEncoding length_encoding = - DwarfPointerEncoding(fde->cie->pointer_encoding & 0x0f); - fde->size = reader_->ReadEncodedPointer(cursor, length_encoding, &size); - if (size > size_t(fde->end - cursor)) - return ReportIncomplete(fde); - cursor += size; - - // If the CIE has a 'z' augmentation string, then augmentation data - // appears here. - if (fde->cie->has_z_augmentation) { - uint64_t data_size = reader_->ReadUnsignedLEB128(cursor, &size); - if (size_t(fde->end - cursor) < size + data_size) - return ReportIncomplete(fde); - cursor += size; - - // In the abstract, we should walk the augmentation string, and extract - // items from the FDE's augmentation data as we encounter augmentation - // string characters that specify their presence: the ordering of items - // in the augmentation string determines the arrangement of values in - // the augmentation data. - // - // In practice, there's only ever one value in FDE augmentation data - // that we support --- the LSDA pointer --- and we have to bail if we - // see any unrecognized augmentation string characters. So if there is - // anything here at all, we know what it is, and where it starts. - if (fde->cie->has_z_lsda) { - // Check whether the LSDA's pointer encoding is usable now: only once - // we've parsed the FDE's starting address do we call reader_-> - // SetFunctionBase, so that the DW_EH_PE_funcrel encoding becomes - // usable. - if (!reader_->UsableEncoding(fde->cie->lsda_encoding)) { - reporter_->UnusablePointerEncoding(fde->cie->offset, - fde->cie->lsda_encoding); - return false; - } - - fde->lsda_address = - reader_->ReadEncodedPointer(cursor, fde->cie->lsda_encoding, &size); - if (size > data_size) - return ReportIncomplete(fde); - // Ideally, we would also complain here if there were unconsumed - // augmentation data. - } - - cursor += data_size; - } - - // The FDE's instructions start after those. - fde->instructions = cursor; - - return true; -} - -bool CallFrameInfo::Start() { - const uint8_t *buffer_end = buffer_ + buffer_length_; - const uint8_t *cursor; - bool all_ok = true; - const uint8_t *entry_end; - bool ok; - - // Traverse all the entries in buffer_, skipping CIEs and offering - // FDEs to the handler. - for (cursor = buffer_; cursor < buffer_end; - cursor = entry_end, all_ok = all_ok && ok) { - FDE fde; - - // Make it easy to skip this entry with 'continue': assume that - // things are not okay until we've checked all the data, and - // prepare the address of the next entry. - ok = false; - - // Read the entry's prologue. - if (!ReadEntryPrologue(cursor, &fde)) { - if (!fde.end) { - // If we couldn't even figure out this entry's extent, then we - // must stop processing entries altogether. - all_ok = false; - break; - } - entry_end = fde.end; - continue; - } - - // The next iteration picks up after this entry. - entry_end = fde.end; - - // Did we see an .eh_frame terminating mark? - if (fde.kind == kTerminator) { - // If there appears to be more data left in the section after the - // terminating mark, warn the user. But this is just a warning; - // we leave all_ok true. - if (fde.end < buffer_end) reporter_->EarlyEHTerminator(fde.offset); - break; - } - - // In this loop, we skip CIEs. We only parse them fully when we - // parse an FDE that refers to them. This limits our memory - // consumption (beyond the buffer itself) to that needed to - // process the largest single entry. - if (fde.kind != kFDE) { - ok = true; - continue; - } - - // Validate the CIE pointer. - if (fde.id > buffer_length_) { - reporter_->CIEPointerOutOfRange(fde.offset, fde.id); - continue; - } - - CIE cie; - - // Parse this FDE's CIE header. - if (!ReadEntryPrologue(buffer_ + fde.id, &cie)) - continue; - // This had better be an actual CIE. - if (cie.kind != kCIE) { - reporter_->BadCIEId(fde.offset, fde.id); - continue; - } - if (!ReadCIEFields(&cie)) - continue; - - // We now have the values that govern both the CIE and the FDE. - cie.cie = &cie; - fde.cie = &cie; - - // Parse the FDE's header. - if (!ReadFDEFields(&fde)) - continue; - - // Call Entry to ask the consumer if they're interested. - if (!handler_->Entry(fde.offset, fde.address, fde.size, - cie.version, cie.augmentation, - cie.return_address_register)) { - // The handler isn't interested in this entry. That's not an error. - ok = true; - continue; - } - - if (cie.has_z_augmentation) { - // Report the personality routine address, if we have one. - if (cie.has_z_personality) { - if (!handler_ - ->PersonalityRoutine(cie.personality_address, - IsIndirectEncoding(cie.personality_encoding))) - continue; - } - - // Report the language-specific data area address, if we have one. - if (cie.has_z_lsda) { - if (!handler_ - ->LanguageSpecificDataArea(fde.lsda_address, - IsIndirectEncoding(cie.lsda_encoding))) - continue; - } - - // If this is a signal-handling frame, report that. - if (cie.has_z_signal_frame) { - if (!handler_->SignalHandler()) - continue; - } - } - - // Interpret the CIE's instructions, and then the FDE's instructions. - State state(reader_, handler_, reporter_, fde.address); - ok = state.InterpretCIE(cie) && state.InterpretFDE(fde); - - // Tell the ByteReader that the function start address from the - // FDE header is no longer valid. - reader_->ClearFunctionBase(); - - // Report the end of the entry. - handler_->End(); - } - - return all_ok; -} - -const char *CallFrameInfo::KindName(EntryKind kind) { - if (kind == CallFrameInfo::kUnknown) - return "entry"; - else if (kind == CallFrameInfo::kCIE) - return "common information entry"; - else if (kind == CallFrameInfo::kFDE) - return "frame description entry"; - else { - assert (kind == CallFrameInfo::kTerminator); - return ".eh_frame sequence terminator"; - } -} - -bool CallFrameInfo::ReportIncomplete(Entry *entry) { - reporter_->Incomplete(entry->offset, entry->kind); - return false; -} - -void CallFrameInfo::Reporter::Incomplete(uint64 offset, - CallFrameInfo::EntryKind kind) { - fprintf(stderr, - "%s: CFI %s at offset 0x%llx in '%s': entry ends early\n", - filename_.c_str(), CallFrameInfo::KindName(kind), offset, - section_.c_str()); -} - -void CallFrameInfo::Reporter::EarlyEHTerminator(uint64 offset) { - fprintf(stderr, - "%s: CFI at offset 0x%llx in '%s': saw end-of-data marker" - " before end of section contents\n", - filename_.c_str(), offset, section_.c_str()); -} - -void CallFrameInfo::Reporter::CIEPointerOutOfRange(uint64 offset, - uint64 cie_offset) { - fprintf(stderr, - "%s: CFI frame description entry at offset 0x%llx in '%s':" - " CIE pointer is out of range: 0x%llx\n", - filename_.c_str(), offset, section_.c_str(), cie_offset); -} - -void CallFrameInfo::Reporter::BadCIEId(uint64 offset, uint64 cie_offset) { - fprintf(stderr, - "%s: CFI frame description entry at offset 0x%llx in '%s':" - " CIE pointer does not point to a CIE: 0x%llx\n", - filename_.c_str(), offset, section_.c_str(), cie_offset); -} - -void CallFrameInfo::Reporter::UnrecognizedVersion(uint64 offset, int version) { - fprintf(stderr, - "%s: CFI frame description entry at offset 0x%llx in '%s':" - " CIE specifies unrecognized version: %d\n", - filename_.c_str(), offset, section_.c_str(), version); -} - -void CallFrameInfo::Reporter::UnrecognizedAugmentation(uint64 offset, - const string &aug) { - fprintf(stderr, - "%s: CFI frame description entry at offset 0x%llx in '%s':" - " CIE specifies unrecognized augmentation: '%s'\n", - filename_.c_str(), offset, section_.c_str(), aug.c_str()); -} - -void CallFrameInfo::Reporter::InvalidPointerEncoding(uint64 offset, - uint8 encoding) { - fprintf(stderr, - "%s: CFI common information entry at offset 0x%llx in '%s':" - " 'z' augmentation specifies invalid pointer encoding: 0x%02x\n", - filename_.c_str(), offset, section_.c_str(), encoding); -} - -void CallFrameInfo::Reporter::UnusablePointerEncoding(uint64 offset, - uint8 encoding) { - fprintf(stderr, - "%s: CFI common information entry at offset 0x%llx in '%s':" - " 'z' augmentation specifies a pointer encoding for which" - " we have no base address: 0x%02x\n", - filename_.c_str(), offset, section_.c_str(), encoding); -} - -void CallFrameInfo::Reporter::RestoreInCIE(uint64 offset, uint64 insn_offset) { - fprintf(stderr, - "%s: CFI common information entry at offset 0x%llx in '%s':" - " the DW_CFA_restore instruction at offset 0x%llx" - " cannot be used in a common information entry\n", - filename_.c_str(), offset, section_.c_str(), insn_offset); -} - -void CallFrameInfo::Reporter::BadInstruction(uint64 offset, - CallFrameInfo::EntryKind kind, - uint64 insn_offset) { - fprintf(stderr, - "%s: CFI %s at offset 0x%llx in section '%s':" - " the instruction at offset 0x%llx is unrecognized\n", - filename_.c_str(), CallFrameInfo::KindName(kind), - offset, section_.c_str(), insn_offset); -} - -void CallFrameInfo::Reporter::NoCFARule(uint64 offset, - CallFrameInfo::EntryKind kind, - uint64 insn_offset) { - fprintf(stderr, - "%s: CFI %s at offset 0x%llx in section '%s':" - " the instruction at offset 0x%llx assumes that a CFA rule has" - " been set, but none has been set\n", - filename_.c_str(), CallFrameInfo::KindName(kind), offset, - section_.c_str(), insn_offset); -} - -void CallFrameInfo::Reporter::EmptyStateStack(uint64 offset, - CallFrameInfo::EntryKind kind, - uint64 insn_offset) { - fprintf(stderr, - "%s: CFI %s at offset 0x%llx in section '%s':" - " the DW_CFA_restore_state instruction at offset 0x%llx" - " should pop a saved state from the stack, but the stack is empty\n", - filename_.c_str(), CallFrameInfo::KindName(kind), offset, - section_.c_str(), insn_offset); -} - -void CallFrameInfo::Reporter::ClearingCFARule(uint64 offset, - CallFrameInfo::EntryKind kind, - uint64 insn_offset) { - fprintf(stderr, - "%s: CFI %s at offset 0x%llx in section '%s':" - " the DW_CFA_restore_state instruction at offset 0x%llx" - " would clear the CFA rule in effect\n", - filename_.c_str(), CallFrameInfo::KindName(kind), offset, - section_.c_str(), insn_offset); -} - -} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.h deleted file mode 100644 index 064c42bc8..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader.h +++ /dev/null @@ -1,1288 +0,0 @@ -// -*- mode: C++ -*- - -// 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. - -// CFI reader author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// This file contains definitions related to the DWARF2/3 reader and -// it's handler interfaces. -// The DWARF2/3 specification can be found at -// http://dwarf.freestandards.org and should be considered required -// reading if you wish to modify the implementation. -// Only a cursory attempt is made to explain terminology that is -// used here, as it is much better explained in the standard documents -#ifndef COMMON_DWARF_DWARF2READER_H__ -#define COMMON_DWARF_DWARF2READER_H__ - -#include <stdint.h> - -#include <list> -#include <map> -#include <string> -#include <utility> -#include <vector> -#include <memory> - -#include "common/dwarf/bytereader.h" -#include "common/dwarf/dwarf2enums.h" -#include "common/dwarf/types.h" -#include "common/using_std_string.h" -#include "common/dwarf/elf_reader.h" - -namespace dwarf2reader { -struct LineStateMachine; -class Dwarf2Handler; -class LineInfoHandler; -class DwpReader; - -// This maps from a string naming a section to a pair containing a -// the data for the section, and the size of the section. -typedef std::map<string, std::pair<const uint8_t *, uint64> > SectionMap; -typedef std::list<std::pair<enum DwarfAttribute, enum DwarfForm> > - AttributeList; -typedef AttributeList::iterator AttributeIterator; -typedef AttributeList::const_iterator ConstAttributeIterator; - -struct LineInfoHeader { - uint64 total_length; - uint16 version; - uint64 prologue_length; - uint8 min_insn_length; // insn stands for instructin - bool default_is_stmt; // stmt stands for statement - int8 line_base; - uint8 line_range; - uint8 opcode_base; - // Use a pointer so that signalsafe_addr2line is able to use this structure - // without heap allocation problem. - std::vector<unsigned char> *std_opcode_lengths; -}; - -class LineInfo { - public: - - // Initializes a .debug_line reader. Buffer and buffer length point - // to the beginning and length of the line information to read. - // Reader is a ByteReader class that has the endianness set - // properly. - LineInfo(const uint8_t *buffer_, uint64 buffer_length, - ByteReader* reader, LineInfoHandler* handler); - - virtual ~LineInfo() { - if (header_.std_opcode_lengths) { - delete header_.std_opcode_lengths; - } - } - - // Start processing line info, and calling callbacks in the handler. - // Consumes the line number information for a single compilation unit. - // Returns the number of bytes processed. - uint64 Start(); - - // Process a single line info opcode at START using the state - // machine at LSM. Return true if we should define a line using the - // current state of the line state machine. Place the length of the - // opcode in LEN. - // If LSM_PASSES_PC is non-NULL, this function also checks if the lsm - // passes the address of PC. In other words, LSM_PASSES_PC will be - // set to true, if the following condition is met. - // - // lsm's old address < PC <= lsm's new address - static bool ProcessOneOpcode(ByteReader* reader, - LineInfoHandler* handler, - const struct LineInfoHeader &header, - const uint8_t *start, - struct LineStateMachine* lsm, - size_t* len, - uintptr pc, - bool *lsm_passes_pc); - - private: - // Reads the DWARF2/3 header for this line info. - void ReadHeader(); - - // Reads the DWARF2/3 line information - void ReadLines(); - - // The associated handler to call processing functions in - LineInfoHandler* handler_; - - // The associated ByteReader that handles endianness issues for us - ByteReader* reader_; - - // A DWARF2/3 line info header. This is not the same size as - // in the actual file, as the one in the file may have a 32 bit or - // 64 bit lengths - - struct LineInfoHeader header_; - - // buffer is the buffer for our line info, starting at exactly where - // the line info to read is. after_header is the place right after - // the end of the line information header. - const uint8_t *buffer_; -#ifndef NDEBUG - uint64 buffer_length_; -#endif - const uint8_t *after_header_; -}; - -// This class is the main interface between the line info reader and -// the client. The virtual functions inside this get called for -// interesting events that happen during line info reading. The -// default implementation does nothing - -class LineInfoHandler { - public: - LineInfoHandler() { } - - virtual ~LineInfoHandler() { } - - // Called when we define a directory. NAME is the directory name, - // DIR_NUM is the directory number - virtual void DefineDir(const string& name, uint32 dir_num) { } - - // Called when we define a filename. NAME is the filename, FILE_NUM - // is the file number which is -1 if the file index is the next - // index after the last numbered index (this happens when files are - // dynamically defined by the line program), DIR_NUM is the - // directory index for the directory name of this file, MOD_TIME is - // the modification time of the file, and LENGTH is the length of - // the file - virtual void DefineFile(const string& name, int32 file_num, - uint32 dir_num, uint64 mod_time, - uint64 length) { } - - // Called when the line info reader has a new line, address pair - // ready for us. ADDRESS is the address of the code, LENGTH is the - // length of its machine code in bytes, FILE_NUM is the file number - // containing the code, LINE_NUM is the line number in that file for - // the code, and COLUMN_NUM is the column number the code starts at, - // if we know it (0 otherwise). - virtual void AddLine(uint64 address, uint64 length, - uint32 file_num, uint32 line_num, uint32 column_num) { } -}; - -// This class is the main interface between the reader and the -// client. The virtual functions inside this get called for -// interesting events that happen during DWARF2 reading. -// The default implementation skips everything. -class Dwarf2Handler { - public: - Dwarf2Handler() { } - - virtual ~Dwarf2Handler() { } - - // Start to process a compilation unit at OFFSET from the beginning of the - // .debug_info section. Return false if you would like to skip this - // compilation unit. - virtual bool StartCompilationUnit(uint64 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version) { return false; } - - // When processing a skeleton compilation unit, resulting from a split - // DWARF compilation, once the skeleton debug info has been read, - // the reader will call this function to ask the client if it needs - // the full debug info from the .dwo or .dwp file. Return true if - // you need it, or false to skip processing the split debug info. - virtual bool NeedSplitDebugInfo() { return true; } - - // Start to process a split compilation unit at OFFSET from the beginning of - // the debug_info section in the .dwp/.dwo file. Return false if you would - // like to skip this compilation unit. - virtual bool StartSplitCompilationUnit(uint64 offset, - uint64 cu_length) { return false; } - - // Start to process a DIE at OFFSET from the beginning of the .debug_info - // section. Return false if you would like to skip this DIE. - virtual bool StartDIE(uint64 offset, enum DwarfTag tag) { return false; } - - // Called when we have an attribute with unsigned data to give to our - // handler. The attribute is for the DIE at OFFSET from the beginning of the - // .debug_info section. Its name is ATTR, its form is FORM, and its value is - // DATA. - virtual void ProcessAttributeUnsigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { } - - // Called when we have an attribute with signed data to give to our handler. - // The attribute is for the DIE at OFFSET from the beginning of the - // .debug_info section. Its name is ATTR, its form is FORM, and its value is - // DATA. - virtual void ProcessAttributeSigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { } - - // Called when we have an attribute whose value is a reference to - // another DIE. The attribute belongs to the DIE at OFFSET from the - // beginning of the .debug_info section. Its name is ATTR, its form - // is FORM, and the offset of the DIE being referred to from the - // beginning of the .debug_info section is DATA. - virtual void ProcessAttributeReference(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { } - - // Called when we have an attribute with a buffer of data to give to our - // handler. The attribute is for the DIE at OFFSET from the beginning of the - // .debug_info section. Its name is ATTR, its form is FORM, DATA points to - // the buffer's contents, and its length in bytes is LENGTH. The buffer is - // owned by the caller, not the callee, and may not persist for very long. - // If you want the data to be available later, it needs to be copied. - virtual void ProcessAttributeBuffer(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const uint8_t *data, - uint64 len) { } - - // Called when we have an attribute with string data to give to our handler. - // The attribute is for the DIE at OFFSET from the beginning of the - // .debug_info section. Its name is ATTR, its form is FORM, and its value is - // DATA. - virtual void ProcessAttributeString(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const string& data) { } - - // Called when we have an attribute whose value is the 64-bit signature - // of a type unit in the .debug_types section. OFFSET is the offset of - // the DIE whose attribute we're reporting. ATTR and FORM are the - // attribute's name and form. SIGNATURE is the type unit's signature. - virtual void ProcessAttributeSignature(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 signature) { } - - // Called when finished processing the DIE at OFFSET. - // Because DWARF2/3 specifies a tree of DIEs, you may get starts - // before ends of the previous DIE, as we process children before - // ending the parent. - virtual void EndDIE(uint64 offset) { } - -}; - -// The base of DWARF2/3 debug info is a DIE (Debugging Information -// Entry. -// DWARF groups DIE's into a tree and calls the root of this tree a -// "compilation unit". Most of the time, there is one compilation -// unit in the .debug_info section for each file that had debug info -// generated. -// Each DIE consists of - -// 1. a tag specifying a thing that is being described (ie -// DW_TAG_subprogram for functions, DW_TAG_variable for variables, etc -// 2. attributes (such as DW_AT_location for location in memory, -// DW_AT_name for name), and data for each attribute. -// 3. A flag saying whether the DIE has children or not - -// In order to gain some amount of compression, the format of -// each DIE (tag name, attributes and data forms for the attributes) -// are stored in a separate table called the "abbreviation table". -// This is done because a large number of DIEs have the exact same tag -// and list of attributes, but different data for those attributes. -// As a result, the .debug_info section is just a stream of data, and -// requires reading of the .debug_abbrev section to say what the data -// means. - -// As a warning to the user, it should be noted that the reason for -// using absolute offsets from the beginning of .debug_info is that -// DWARF2/3 supports referencing DIE's from other DIE's by their offset -// from either the current compilation unit start, *or* the beginning -// of the .debug_info section. This means it is possible to reference -// a DIE in one compilation unit from a DIE in another compilation -// unit. This style of reference is usually used to eliminate -// duplicated information that occurs across compilation -// units, such as base types, etc. GCC 3.4+ support this with -// -feliminate-dwarf2-dups. Other toolchains will sometimes do -// duplicate elimination in the linker. - -class CompilationUnit { - public: - - // Initialize a compilation unit. This requires a map of sections, - // the offset of this compilation unit in the .debug_info section, a - // ByteReader, and a Dwarf2Handler class to call callbacks in. - CompilationUnit(const string& path, const SectionMap& sections, uint64 offset, - ByteReader* reader, Dwarf2Handler* handler); - virtual ~CompilationUnit() { - if (abbrevs_) delete abbrevs_; - } - - // Initialize a compilation unit from a .dwo or .dwp file. - // In this case, we need the .debug_addr section from the - // executable file that contains the corresponding skeleton - // compilation unit. We also inherit the Dwarf2Handler from - // the executable file, and call it as if we were still - // processing the original compilation unit. - void SetSplitDwarf(const uint8_t* addr_buffer, uint64 addr_buffer_length, - uint64 addr_base, uint64 ranges_base, uint64 dwo_id); - - // Begin reading a Dwarf2 compilation unit, and calling the - // callbacks in the Dwarf2Handler - - // Return the full length of the compilation unit, including - // headers. This plus the starting offset passed to the constructor - // is the offset of the end of the compilation unit --- and the - // start of the next compilation unit, if there is one. - uint64 Start(); - - private: - - // This struct represents a single DWARF2/3 abbreviation - // The abbreviation tells how to read a DWARF2/3 DIE, and consist of a - // tag and a list of attributes, as well as the data form of each attribute. - struct Abbrev { - uint64 number; - enum DwarfTag tag; - bool has_children; - AttributeList attributes; - }; - - // A DWARF2/3 compilation unit header. This is not the same size as - // in the actual file, as the one in the file may have a 32 bit or - // 64 bit length. - struct CompilationUnitHeader { - uint64 length; - uint16 version; - uint64 abbrev_offset; - uint8 address_size; - } header_; - - // Reads the DWARF2/3 header for this compilation unit. - void ReadHeader(); - - // Reads the DWARF2/3 abbreviations for this compilation unit - void ReadAbbrevs(); - - // Processes a single DIE for this compilation unit and return a new - // pointer just past the end of it - const uint8_t *ProcessDIE(uint64 dieoffset, - const uint8_t *start, - const Abbrev& abbrev); - - // Processes a single attribute and return a new pointer just past the - // end of it - const uint8_t *ProcessAttribute(uint64 dieoffset, - const uint8_t *start, - enum DwarfAttribute attr, - enum DwarfForm form); - - // Called when we have an attribute with unsigned data to give to - // our handler. The attribute is for the DIE at OFFSET from the - // beginning of compilation unit, has a name of ATTR, a form of - // FORM, and the actual data of the attribute is in DATA. - // If we see a DW_AT_GNU_dwo_id attribute, save the value so that - // we can find the debug info in a .dwo or .dwp file. - void ProcessAttributeUnsigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - if (attr == DW_AT_GNU_dwo_id) { - dwo_id_ = data; - } - else if (attr == DW_AT_GNU_addr_base) { - addr_base_ = data; - } - else if (attr == DW_AT_GNU_ranges_base) { - ranges_base_ = data; - } - // TODO(yunlian): When we add DW_AT_ranges_base from DWARF-5, - // that base will apply to DW_AT_ranges attributes in the - // skeleton CU as well as in the .dwo/.dwp files. - else if (attr == DW_AT_ranges && is_split_dwarf_) { - data += ranges_base_; - } - handler_->ProcessAttributeUnsigned(offset, attr, form, data); - } - - // Called when we have an attribute with signed data to give to - // our handler. The attribute is for the DIE at OFFSET from the - // beginning of compilation unit, has a name of ATTR, a form of - // FORM, and the actual data of the attribute is in DATA. - void ProcessAttributeSigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { - handler_->ProcessAttributeSigned(offset, attr, form, data); - } - - // Called when we have an attribute with a buffer of data to give to - // our handler. The attribute is for the DIE at OFFSET from the - // beginning of compilation unit, has a name of ATTR, a form of - // FORM, and the actual data of the attribute is in DATA, and the - // length of the buffer is LENGTH. - void ProcessAttributeBuffer(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const uint8_t* data, - uint64 len) { - handler_->ProcessAttributeBuffer(offset, attr, form, data, len); - } - - // Called when we have an attribute with string data to give to - // our handler. The attribute is for the DIE at OFFSET from the - // beginning of compilation unit, has a name of ATTR, a form of - // FORM, and the actual data of the attribute is in DATA. - // If we see a DW_AT_GNU_dwo_name attribute, save the value so - // that we can find the debug info in a .dwo or .dwp file. - void ProcessAttributeString(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const char* data) { - if (attr == DW_AT_GNU_dwo_name) - dwo_name_ = data; - handler_->ProcessAttributeString(offset, attr, form, data); - } - - // Processes all DIEs for this compilation unit - void ProcessDIEs(); - - // Skips the die with attributes specified in ABBREV starting at - // START, and return the new place to position the stream to. - const uint8_t *SkipDIE(const uint8_t *start, const Abbrev& abbrev); - - // Skips the attribute starting at START, with FORM, and return the - // new place to position the stream to. - const uint8_t *SkipAttribute(const uint8_t *start, enum DwarfForm form); - - // Process the actual debug information in a split DWARF file. - void ProcessSplitDwarf(); - - // Read the debug sections from a .dwo file. - void ReadDebugSectionsFromDwo(ElfReader* elf_reader, - SectionMap* sections); - - // Path of the file containing the debug information. - const string path_; - - // Offset from section start is the offset of this compilation unit - // from the beginning of the .debug_info section. - uint64 offset_from_section_start_; - - // buffer is the buffer for our CU, starting at .debug_info + offset - // passed in from constructor. - // after_header points to right after the compilation unit header. - const uint8_t *buffer_; - uint64 buffer_length_; - const uint8_t *after_header_; - - // The associated ByteReader that handles endianness issues for us - ByteReader* reader_; - - // The map of sections in our file to buffers containing their data - const SectionMap& sections_; - - // The associated handler to call processing functions in - Dwarf2Handler* handler_; - - // Set of DWARF2/3 abbreviations for this compilation unit. Indexed - // by abbreviation number, which means that abbrevs_[0] is not - // valid. - std::vector<Abbrev>* abbrevs_; - - // String section buffer and length, if we have a string section. - // This is here to avoid doing a section lookup for strings in - // ProcessAttribute, which is in the hot path for DWARF2 reading. - const uint8_t *string_buffer_; - uint64 string_buffer_length_; - - // String offsets section buffer and length, if we have a string offsets - // section (.debug_str_offsets or .debug_str_offsets.dwo). - const uint8_t* str_offsets_buffer_; - uint64 str_offsets_buffer_length_; - - // Address section buffer and length, if we have an address section - // (.debug_addr). - const uint8_t* addr_buffer_; - uint64 addr_buffer_length_; - - // Flag indicating whether this compilation unit is part of a .dwo - // or .dwp file. If true, we are reading this unit because a - // skeleton compilation unit in an executable file had a - // DW_AT_GNU_dwo_name or DW_AT_GNU_dwo_id attribute. - // In a .dwo file, we expect the string offsets section to - // have a ".dwo" suffix, and we will use the ".debug_addr" section - // associated with the skeleton compilation unit. - bool is_split_dwarf_; - - // The value of the DW_AT_GNU_dwo_id attribute, if any. - uint64 dwo_id_; - - // The value of the DW_AT_GNU_dwo_name attribute, if any. - const char* dwo_name_; - - // If this is a split DWARF CU, the value of the DW_AT_GNU_dwo_id attribute - // from the skeleton CU. - uint64 skeleton_dwo_id_; - - // The value of the DW_AT_GNU_ranges_base attribute, if any. - uint64 ranges_base_; - - // The value of the DW_AT_GNU_addr_base attribute, if any. - uint64 addr_base_; - - // True if we have already looked for a .dwp file. - bool have_checked_for_dwp_; - - // Path to the .dwp file. - string dwp_path_; - - // ByteReader for the DWP file. - std::unique_ptr<ByteReader> dwp_byte_reader_; - - // DWP reader. - std::unique_ptr<DwpReader> dwp_reader_; -}; - -// A Reader for a .dwp file. Supports the fetching of DWARF debug -// info for a given dwo_id. -// -// There are two versions of .dwp files. In both versions, the -// .dwp file is an ELF file containing only debug sections. -// In Version 1, the file contains many copies of each debug -// section, one for each .dwo file that is packaged in the .dwp -// file, and the .debug_cu_index section maps from the dwo_id -// to a set of section indexes. In Version 2, the file contains -// one of each debug section, and the .debug_cu_index section -// maps from the dwo_id to a set of offsets and lengths that -// identify each .dwo file's contribution to the larger sections. - -class DwpReader { - public: - DwpReader(const ByteReader& byte_reader, ElfReader* elf_reader); - - ~DwpReader(); - - // Read the CU index and initialize data members. - void Initialize(); - - // Read the debug sections for the given dwo_id. - void ReadDebugSectionsForCU(uint64 dwo_id, SectionMap* sections); - - private: - // Search a v1 hash table for "dwo_id". Returns the slot index - // where the dwo_id was found, or -1 if it was not found. - int LookupCU(uint64 dwo_id); - - // Search a v2 hash table for "dwo_id". Returns the row index - // in the offsets and sizes tables, or 0 if it was not found. - uint32 LookupCUv2(uint64 dwo_id); - - // The ELF reader for the .dwp file. - ElfReader* elf_reader_; - - // The ByteReader for the .dwp file. - const ByteReader& byte_reader_; - - // Pointer to the .debug_cu_index section. - const char* cu_index_; - - // Size of the .debug_cu_index section. - size_t cu_index_size_; - - // Pointer to the .debug_str.dwo section. - const char* string_buffer_; - - // Size of the .debug_str.dwo section. - size_t string_buffer_size_; - - // Version of the .dwp file. We support versions 1 and 2 currently. - int version_; - - // Number of columns in the section tables (version 2). - unsigned int ncolumns_; - - // Number of units in the section tables (version 2). - unsigned int nunits_; - - // Number of slots in the hash table. - unsigned int nslots_; - - // Pointer to the beginning of the hash table. - const char* phash_; - - // Pointer to the beginning of the index table. - const char* pindex_; - - // Pointer to the beginning of the section index pool (version 1). - const char* shndx_pool_; - - // Pointer to the beginning of the section offset table (version 2). - const char* offset_table_; - - // Pointer to the beginning of the section size table (version 2). - const char* size_table_; - - // Contents of the sections of interest (version 2). - const char* abbrev_data_; - size_t abbrev_size_; - const char* info_data_; - size_t info_size_; - const char* str_offsets_data_; - size_t str_offsets_size_; -}; - -// This class is a reader for DWARF's Call Frame Information. CFI -// describes how to unwind stack frames --- even for functions that do -// not follow fixed conventions for saving registers, whose frame size -// varies as they execute, etc. -// -// CFI describes, at each machine instruction, how to compute the -// stack frame's base address, how to find the return address, and -// where to find the saved values of the caller's registers (if the -// callee has stashed them somewhere to free up the registers for its -// own use). -// -// For example, suppose we have a function whose machine code looks -// like this (imagine an assembly language that looks like C, for a -// machine with 32-bit registers, and a stack that grows towards lower -// addresses): -// -// func: ; entry point; return address at sp -// func+0: sp = sp - 16 ; allocate space for stack frame -// func+1: sp[12] = r0 ; save r0 at sp+12 -// ... ; other code, not frame-related -// func+10: sp -= 4; *sp = x ; push some x on the stack -// ... ; other code, not frame-related -// func+20: r0 = sp[16] ; restore saved r0 -// func+21: sp += 20 ; pop whole stack frame -// func+22: pc = *sp; sp += 4 ; pop return address and jump to it -// -// DWARF CFI is (a very compressed representation of) a table with a -// row for each machine instruction address and a column for each -// register showing how to restore it, if possible. -// -// A special column named "CFA", for "Canonical Frame Address", tells how -// to compute the base address of the frame; registers' entries may -// refer to the CFA in describing where the registers are saved. -// -// Another special column, named "RA", represents the return address. -// -// For example, here is a complete (uncompressed) table describing the -// function above: -// -// insn cfa r0 r1 ... ra -// ======================================= -// func+0: sp cfa[0] -// func+1: sp+16 cfa[0] -// func+2: sp+16 cfa[-4] cfa[0] -// func+11: sp+20 cfa[-4] cfa[0] -// func+21: sp+20 cfa[0] -// func+22: sp cfa[0] -// -// Some things to note here: -// -// - Each row describes the state of affairs *before* executing the -// instruction at the given address. Thus, the row for func+0 -// describes the state before we allocate the stack frame. In the -// next row, the formula for computing the CFA has changed, -// reflecting that allocation. -// -// - The other entries are written in terms of the CFA; this allows -// them to remain unchanged as the stack pointer gets bumped around. -// For example, the rule for recovering the return address (the "ra" -// column) remains unchanged throughout the function, even as the -// stack pointer takes on three different offsets from the return -// address. -// -// - Although we haven't shown it, most calling conventions designate -// "callee-saves" and "caller-saves" registers. The callee must -// preserve the values of callee-saves registers; if it uses them, -// it must save their original values somewhere, and restore them -// before it returns. In contrast, the callee is free to trash -// caller-saves registers; if the callee uses these, it will -// probably not bother to save them anywhere, and the CFI will -// probably mark their values as "unrecoverable". -// -// (However, since the caller cannot assume the callee was going to -// save them, caller-saves registers are probably dead in the caller -// anyway, so compilers usually don't generate CFA for caller-saves -// registers.) -// -// - Exactly where the CFA points is a matter of convention that -// depends on the architecture and ABI in use. In the example, the -// CFA is the value the stack pointer had upon entry to the -// function, pointing at the saved return address. But on the x86, -// the call frame information generated by GCC follows the -// convention that the CFA is the address *after* the saved return -// address. -// -// But by definition, the CFA remains constant throughout the -// lifetime of the frame. This makes it a useful value for other -// columns to refer to. It is also gives debuggers a useful handle -// for identifying a frame. -// -// If you look at the table above, you'll notice that a given entry is -// often the same as the one immediately above it: most instructions -// change only one or two aspects of the stack frame, if they affect -// it at all. The DWARF format takes advantage of this fact, and -// reduces the size of the data by mentioning only the addresses and -// columns at which changes take place. So for the above, DWARF CFI -// data would only actually mention the following: -// -// insn cfa r0 r1 ... ra -// ======================================= -// func+0: sp cfa[0] -// func+1: sp+16 -// func+2: cfa[-4] -// func+11: sp+20 -// func+21: r0 -// func+22: sp -// -// In fact, this is the way the parser reports CFI to the consumer: as -// a series of statements of the form, "At address X, column Y changed -// to Z," and related conventions for describing the initial state. -// -// Naturally, it would be impractical to have to scan the entire -// program's CFI, noting changes as we go, just to recover the -// unwinding rules in effect at one particular instruction. To avoid -// this, CFI data is grouped into "entries", each of which covers a -// specified range of addresses and begins with a complete statement -// of the rules for all recoverable registers at that starting -// address. Each entry typically covers a single function. -// -// Thus, to compute the contents of a given row of the table --- that -// is, rules for recovering the CFA, RA, and registers at a given -// instruction --- the consumer should find the entry that covers that -// instruction's address, start with the initial state supplied at the -// beginning of the entry, and work forward until it has processed all -// the changes up to and including those for the present instruction. -// -// There are seven kinds of rules that can appear in an entry of the -// table: -// -// - "undefined": The given register is not preserved by the callee; -// its value cannot be recovered. -// -// - "same value": This register has the same value it did in the callee. -// -// - offset(N): The register is saved at offset N from the CFA. -// -// - val_offset(N): The value the register had in the caller is the -// CFA plus offset N. (This is usually only useful for describing -// the stack pointer.) -// -// - register(R): The register's value was saved in another register R. -// -// - expression(E): Evaluating the DWARF expression E using the -// current frame's registers' values yields the address at which the -// register was saved. -// -// - val_expression(E): Evaluating the DWARF expression E using the -// current frame's registers' values yields the value the register -// had in the caller. - -class CallFrameInfo { - public: - // The different kinds of entries one finds in CFI. Used internally, - // and for error reporting. - enum EntryKind { kUnknown, kCIE, kFDE, kTerminator }; - - // The handler class to which the parser hands the parsed call frame - // information. Defined below. - class Handler; - - // A reporter class, which CallFrameInfo uses to report errors - // encountered while parsing call frame information. Defined below. - class Reporter; - - // Create a DWARF CFI parser. BUFFER points to the contents of the - // .debug_frame section to parse; BUFFER_LENGTH is its length in bytes. - // REPORTER is an error reporter the parser should use to report - // problems. READER is a ByteReader instance that has the endianness and - // address size set properly. Report the data we find to HANDLER. - // - // This class can also parse Linux C++ exception handling data, as found - // in '.eh_frame' sections. This data is a variant of DWARF CFI that is - // placed in loadable segments so that it is present in the program's - // address space, and is interpreted by the C++ runtime to search the - // call stack for a handler interested in the exception being thrown, - // actually pop the frames, and find cleanup code to run. - // - // There are two differences between the call frame information described - // in the DWARF standard and the exception handling data Linux places in - // the .eh_frame section: - // - // - Exception handling data uses uses a different format for call frame - // information entry headers. The distinguished CIE id, the way FDEs - // refer to their CIEs, and the way the end of the series of entries is - // determined are all slightly different. - // - // If the constructor's EH_FRAME argument is true, then the - // CallFrameInfo parses the entry headers as Linux C++ exception - // handling data. If EH_FRAME is false or omitted, the CallFrameInfo - // parses standard DWARF call frame information. - // - // - Linux C++ exception handling data uses CIE augmentation strings - // beginning with 'z' to specify the presence of additional data after - // the CIE and FDE headers and special encodings used for addresses in - // frame description entries. - // - // CallFrameInfo can handle 'z' augmentations in either DWARF CFI or - // exception handling data if you have supplied READER with the base - // addresses needed to interpret the pointer encodings that 'z' - // augmentations can specify. See the ByteReader interface for details - // about the base addresses. See the CallFrameInfo::Handler interface - // for details about the additional information one might find in - // 'z'-augmented data. - // - // Thus: - // - // - If you are parsing standard DWARF CFI, as found in a .debug_frame - // section, you should pass false for the EH_FRAME argument, or omit - // it, and you need not worry about providing READER with the - // additional base addresses. - // - // - If you want to parse Linux C++ exception handling data from a - // .eh_frame section, you should pass EH_FRAME as true, and call - // READER's Set*Base member functions before calling our Start method. - // - // - If you want to parse DWARF CFI that uses the 'z' augmentations - // (although I don't think any toolchain ever emits such data), you - // could pass false for EH_FRAME, but call READER's Set*Base members. - // - // The extensions the Linux C++ ABI makes to DWARF for exception - // handling are described here, rather poorly: - // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html - // http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html - // - // The mechanics of C++ exception handling, personality routines, - // and language-specific data areas are described here, rather nicely: - // http://www.codesourcery.com/public/cxx-abi/abi-eh.html - CallFrameInfo(const uint8_t *buffer, size_t buffer_length, - ByteReader *reader, Handler *handler, Reporter *reporter, - bool eh_frame = false) - : buffer_(buffer), buffer_length_(buffer_length), - reader_(reader), handler_(handler), reporter_(reporter), - eh_frame_(eh_frame) { } - - ~CallFrameInfo() { } - - // Parse the entries in BUFFER, reporting what we find to HANDLER. - // Return true if we reach the end of the section successfully, or - // false if we encounter an error. - bool Start(); - - // Return the textual name of KIND. For error reporting. - static const char *KindName(EntryKind kind); - - private: - - struct CIE; - - // A CFI entry, either an FDE or a CIE. - struct Entry { - // The starting offset of the entry in the section, for error - // reporting. - size_t offset; - - // The start of this entry in the buffer. - const uint8_t *start; - - // Which kind of entry this is. - // - // We want to be able to use this for error reporting even while we're - // in the midst of parsing. Error reporting code may assume that kind, - // offset, and start fields are valid, although kind may be kUnknown. - EntryKind kind; - - // The end of this entry's common prologue (initial length and id), and - // the start of this entry's kind-specific fields. - const uint8_t *fields; - - // The start of this entry's instructions. - const uint8_t *instructions; - - // The address past the entry's last byte in the buffer. (Note that - // since offset points to the entry's initial length field, and the - // length field is the number of bytes after that field, this is not - // simply buffer_ + offset + length.) - const uint8_t *end; - - // For both DWARF CFI and .eh_frame sections, this is the CIE id in a - // CIE, and the offset of the associated CIE in an FDE. - uint64 id; - - // The CIE that applies to this entry, if we've parsed it. If this is a - // CIE, then this field points to this structure. - CIE *cie; - }; - - // A common information entry (CIE). - struct CIE: public Entry { - uint8 version; // CFI data version number - string augmentation; // vendor format extension markers - uint64 code_alignment_factor; // scale for code address adjustments - int data_alignment_factor; // scale for stack pointer adjustments - unsigned return_address_register; // which register holds the return addr - - // True if this CIE includes Linux C++ ABI 'z' augmentation data. - bool has_z_augmentation; - - // Parsed 'z' augmentation data. These are meaningful only if - // has_z_augmentation is true. - bool has_z_lsda; // The 'z' augmentation included 'L'. - bool has_z_personality; // The 'z' augmentation included 'P'. - bool has_z_signal_frame; // The 'z' augmentation included 'S'. - - // If has_z_lsda is true, this is the encoding to be used for language- - // specific data area pointers in FDEs. - DwarfPointerEncoding lsda_encoding; - - // If has_z_personality is true, this is the encoding used for the - // personality routine pointer in the augmentation data. - DwarfPointerEncoding personality_encoding; - - // If has_z_personality is true, this is the address of the personality - // routine --- or, if personality_encoding & DW_EH_PE_indirect, the - // address where the personality routine's address is stored. - uint64 personality_address; - - // This is the encoding used for addresses in the FDE header and - // in DW_CFA_set_loc instructions. This is always valid, whether - // or not we saw a 'z' augmentation string; its default value is - // DW_EH_PE_absptr, which is what normal DWARF CFI uses. - DwarfPointerEncoding pointer_encoding; - }; - - // A frame description entry (FDE). - struct FDE: public Entry { - uint64 address; // start address of described code - uint64 size; // size of described code, in bytes - - // If cie->has_z_lsda is true, then this is the language-specific data - // area's address --- or its address's address, if cie->lsda_encoding - // has the DW_EH_PE_indirect bit set. - uint64 lsda_address; - }; - - // Internal use. - class Rule; - class UndefinedRule; - class SameValueRule; - class OffsetRule; - class ValOffsetRule; - class RegisterRule; - class ExpressionRule; - class ValExpressionRule; - class RuleMap; - class State; - - // Parse the initial length and id of a CFI entry, either a CIE, an FDE, - // or a .eh_frame end-of-data mark. CURSOR points to the beginning of the - // data to parse. On success, populate ENTRY as appropriate, and return - // true. On failure, report the problem, and return false. Even if we - // return false, set ENTRY->end to the first byte after the entry if we - // were able to figure that out, or NULL if we weren't. - bool ReadEntryPrologue(const uint8_t *cursor, Entry *entry); - - // Parse the fields of a CIE after the entry prologue, including any 'z' - // augmentation data. Assume that the 'Entry' fields of CIE are - // populated; use CIE->fields and CIE->end as the start and limit for - // parsing. On success, populate the rest of *CIE, and return true; on - // failure, report the problem and return false. - bool ReadCIEFields(CIE *cie); - - // Parse the fields of an FDE after the entry prologue, including any 'z' - // augmentation data. Assume that the 'Entry' fields of *FDE are - // initialized; use FDE->fields and FDE->end as the start and limit for - // parsing. Assume that FDE->cie is fully initialized. On success, - // populate the rest of *FDE, and return true; on failure, report the - // problem and return false. - bool ReadFDEFields(FDE *fde); - - // Report that ENTRY is incomplete, and return false. This is just a - // trivial wrapper for invoking reporter_->Incomplete; it provides a - // little brevity. - bool ReportIncomplete(Entry *entry); - - // Return true if ENCODING has the DW_EH_PE_indirect bit set. - static bool IsIndirectEncoding(DwarfPointerEncoding encoding) { - return encoding & DW_EH_PE_indirect; - } - - // The contents of the DWARF .debug_info section we're parsing. - const uint8_t *buffer_; - size_t buffer_length_; - - // For reading multi-byte values with the appropriate endianness. - ByteReader *reader_; - - // The handler to which we should report the data we find. - Handler *handler_; - - // For reporting problems in the info we're parsing. - Reporter *reporter_; - - // True if we are processing .eh_frame-format data. - bool eh_frame_; -}; - -// The handler class for CallFrameInfo. The a CFI parser calls the -// member functions of a handler object to report the data it finds. -class CallFrameInfo::Handler { - public: - // The pseudo-register number for the canonical frame address. - enum { kCFARegister = -1 }; - - Handler() { } - virtual ~Handler() { } - - // The parser has found CFI for the machine code at ADDRESS, - // extending for LENGTH bytes. OFFSET is the offset of the frame - // description entry in the section, for use in error messages. - // VERSION is the version number of the CFI format. AUGMENTATION is - // a string describing any producer-specific extensions present in - // the data. RETURN_ADDRESS is the number of the register that holds - // the address to which the function should return. - // - // Entry should return true to process this CFI, or false to skip to - // the next entry. - // - // The parser invokes Entry for each Frame Description Entry (FDE) - // it finds. The parser doesn't report Common Information Entries - // to the handler explicitly; instead, if the handler elects to - // process a given FDE, the parser reiterates the appropriate CIE's - // contents at the beginning of the FDE's rules. - virtual bool Entry(size_t offset, uint64 address, uint64 length, - uint8 version, const string &augmentation, - unsigned return_address) = 0; - - // When the Entry function returns true, the parser calls these - // handler functions repeatedly to describe the rules for recovering - // registers at each instruction in the given range of machine code. - // Immediately after a call to Entry, the handler should assume that - // the rule for each callee-saves register is "unchanged" --- that - // is, that the register still has the value it had in the caller. - // - // If a *Rule function returns true, we continue processing this entry's - // instructions. If a *Rule function returns false, we stop evaluating - // instructions, and skip to the next entry. Either way, we call End - // before going on to the next entry. - // - // In all of these functions, if the REG parameter is kCFARegister, then - // the rule describes how to find the canonical frame address. - // kCFARegister may be passed as a BASE_REGISTER argument, meaning that - // the canonical frame address should be used as the base address for the - // computation. All other REG values will be positive. - - // At ADDRESS, register REG's value is not recoverable. - virtual bool UndefinedRule(uint64 address, int reg) = 0; - - // At ADDRESS, register REG's value is the same as that it had in - // the caller. - virtual bool SameValueRule(uint64 address, int reg) = 0; - - // At ADDRESS, register REG has been saved at offset OFFSET from - // BASE_REGISTER. - virtual bool OffsetRule(uint64 address, int reg, - int base_register, long offset) = 0; - - // At ADDRESS, the caller's value of register REG is the current - // value of BASE_REGISTER plus OFFSET. (This rule doesn't provide an - // address at which the register's value is saved.) - virtual bool ValOffsetRule(uint64 address, int reg, - int base_register, long offset) = 0; - - // At ADDRESS, register REG has been saved in BASE_REGISTER. This differs - // from ValOffsetRule(ADDRESS, REG, BASE_REGISTER, 0), in that - // BASE_REGISTER is the "home" for REG's saved value: if you want to - // assign to a variable whose home is REG in the calling frame, you - // should put the value in BASE_REGISTER. - virtual bool RegisterRule(uint64 address, int reg, int base_register) = 0; - - // At ADDRESS, the DWARF expression EXPRESSION yields the address at - // which REG was saved. - virtual bool ExpressionRule(uint64 address, int reg, - const string &expression) = 0; - - // At ADDRESS, the DWARF expression EXPRESSION yields the caller's - // value for REG. (This rule doesn't provide an address at which the - // register's value is saved.) - virtual bool ValExpressionRule(uint64 address, int reg, - const string &expression) = 0; - - // Indicate that the rules for the address range reported by the - // last call to Entry are complete. End should return true if - // everything is okay, or false if an error has occurred and parsing - // should stop. - virtual bool End() = 0; - - // Handler functions for Linux C++ exception handling data. These are - // only called if the data includes 'z' augmentation strings. - - // The Linux C++ ABI uses an extension of the DWARF CFI format to - // walk the stack to propagate exceptions from the throw to the - // appropriate catch, and do the appropriate cleanups along the way. - // CFI entries used for exception handling have two additional data - // associated with them: - // - // - The "language-specific data area" describes which exception - // types the function has 'catch' clauses for, and indicates how - // to go about re-entering the function at the appropriate catch - // clause. If the exception is not caught, it describes the - // destructors that must run before the frame is popped. - // - // - The "personality routine" is responsible for interpreting the - // language-specific data area's contents, and deciding whether - // the exception should continue to propagate down the stack, - // perhaps after doing some cleanup for this frame, or whether the - // exception will be caught here. - // - // In principle, the language-specific data area is opaque to - // everybody but the personality routine. In practice, these values - // may be useful or interesting to readers with extra context, and - // we have to at least skip them anyway, so we might as well report - // them to the handler. - - // This entry's exception handling personality routine's address is - // ADDRESS. If INDIRECT is true, then ADDRESS is the address at - // which the routine's address is stored. The default definition for - // this handler function simply returns true, allowing parsing of - // the entry to continue. - virtual bool PersonalityRoutine(uint64 address, bool indirect) { - return true; - } - - // This entry's language-specific data area (LSDA) is located at - // ADDRESS. If INDIRECT is true, then ADDRESS is the address at - // which the area's address is stored. The default definition for - // this handler function simply returns true, allowing parsing of - // the entry to continue. - virtual bool LanguageSpecificDataArea(uint64 address, bool indirect) { - return true; - } - - // This entry describes a signal trampoline --- this frame is the - // caller of a signal handler. The default definition for this - // handler function simply returns true, allowing parsing of the - // entry to continue. - // - // The best description of the rationale for and meaning of signal - // trampoline CFI entries seems to be in the GCC bug database: - // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=26208 - virtual bool SignalHandler() { return true; } -}; - -// The CallFrameInfo class makes calls on an instance of this class to -// report errors or warn about problems in the data it is parsing. The -// default definitions of these methods print a message to stderr, but -// you can make a derived class that overrides them. -class CallFrameInfo::Reporter { - public: - // Create an error reporter which attributes troubles to the section - // named SECTION in FILENAME. - // - // Normally SECTION would be .debug_frame, but the Mac puts CFI data - // in a Mach-O section named __debug_frame. If we support - // Linux-style exception handling data, we could be reading an - // .eh_frame section. - Reporter(const string &filename, - const string §ion = ".debug_frame") - : filename_(filename), section_(section) { } - virtual ~Reporter() { } - - // The CFI entry at OFFSET ends too early to be well-formed. KIND - // indicates what kind of entry it is; KIND can be kUnknown if we - // haven't parsed enough of the entry to tell yet. - virtual void Incomplete(uint64 offset, CallFrameInfo::EntryKind kind); - - // The .eh_frame data has a four-byte zero at OFFSET where the next - // entry's length would be; this is a terminator. However, the buffer - // length as given to the CallFrameInfo constructor says there should be - // more data. - virtual void EarlyEHTerminator(uint64 offset); - - // The FDE at OFFSET refers to the CIE at CIE_OFFSET, but the - // section is not that large. - virtual void CIEPointerOutOfRange(uint64 offset, uint64 cie_offset); - - // The FDE at OFFSET refers to the CIE at CIE_OFFSET, but the entry - // there is not a CIE. - virtual void BadCIEId(uint64 offset, uint64 cie_offset); - - // The FDE at OFFSET refers to a CIE with version number VERSION, - // which we don't recognize. We cannot parse DWARF CFI if it uses - // a version number we don't recognize. - virtual void UnrecognizedVersion(uint64 offset, int version); - - // The FDE at OFFSET refers to a CIE with augmentation AUGMENTATION, - // which we don't recognize. We cannot parse DWARF CFI if it uses - // augmentations we don't recognize. - virtual void UnrecognizedAugmentation(uint64 offset, - const string &augmentation); - - // The pointer encoding ENCODING, specified by the CIE at OFFSET, is not - // a valid encoding. - virtual void InvalidPointerEncoding(uint64 offset, uint8 encoding); - - // The pointer encoding ENCODING, specified by the CIE at OFFSET, depends - // on a base address which has not been supplied. - virtual void UnusablePointerEncoding(uint64 offset, uint8 encoding); - - // The CIE at OFFSET contains a DW_CFA_restore instruction at - // INSN_OFFSET, which may not appear in a CIE. - virtual void RestoreInCIE(uint64 offset, uint64 insn_offset); - - // The entry at OFFSET, of kind KIND, has an unrecognized - // instruction at INSN_OFFSET. - virtual void BadInstruction(uint64 offset, CallFrameInfo::EntryKind kind, - uint64 insn_offset); - - // The instruction at INSN_OFFSET in the entry at OFFSET, of kind - // KIND, establishes a rule that cites the CFA, but we have not - // established a CFA rule yet. - virtual void NoCFARule(uint64 offset, CallFrameInfo::EntryKind kind, - uint64 insn_offset); - - // The instruction at INSN_OFFSET in the entry at OFFSET, of kind - // KIND, is a DW_CFA_restore_state instruction, but the stack of - // saved states is empty. - virtual void EmptyStateStack(uint64 offset, CallFrameInfo::EntryKind kind, - uint64 insn_offset); - - // The DW_CFA_remember_state instruction at INSN_OFFSET in the entry - // at OFFSET, of kind KIND, would restore a state that has no CFA - // rule, whereas the current state does have a CFA rule. This is - // bogus input, which the CallFrameInfo::Handler interface doesn't - // (and shouldn't) have any way to report. - virtual void ClearingCFARule(uint64 offset, CallFrameInfo::EntryKind kind, - uint64 insn_offset); - - protected: - // The name of the file whose CFI we're reading. - string filename_; - - // The name of the CFI section in that file. - string section_; -}; - -} // namespace dwarf2reader - -#endif // UTIL_DEBUGINFO_DWARF2READER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc deleted file mode 100644 index e50ea5fbd..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc +++ /dev/null @@ -1,2468 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf2reader_cfi_unittest.cc: Unit tests for dwarf2reader::CallFrameInfo - -#include <stdint.h> -#include <stdlib.h> - -#include <string> -#include <vector> - -// The '.eh_frame' format, used by the Linux C++ ABI for exception -// handling, is poorly specified. To help test our support for .eh_frame, -// if you #define WRITE_ELF while compiling this file, and add the -// 'include' directory from the binutils, gcc, or gdb source tree to the -// #include path, then each test that calls the -// PERHAPS_WRITE_DEBUG_FRAME_FILE or PERHAPS_WRITE_EH_FRAME_FILE will write -// an ELF file containing a .debug_frame or .eh_frame section; you can then -// use tools like readelf to examine the test data, and check the tools' -// interpretation against the test's intentions. Each ELF file is named -// "cfitest-TEST", where TEST identifies the particular test. -#ifdef WRITE_ELF -#include <errno.h> -#include <stdio.h> -#include <string.h> -extern "C" { -// To compile with WRITE_ELF, you should add the 'include' directory -// of the binutils, gcc, or gdb source tree to your #include path; -// that directory contains this header. -#include "elf/common.h" -} -#endif - -#include "breakpad_googletest_includes.h" -#include "common/dwarf/bytereader-inl.h" -#include "common/dwarf/cfi_assembler.h" -#include "common/dwarf/dwarf2reader.h" -#include "common/using_std_string.h" -#include "google_breakpad/common/breakpad_types.h" - -using google_breakpad::CFISection; -using google_breakpad::test_assembler::Label; -using google_breakpad::test_assembler::kBigEndian; -using google_breakpad::test_assembler::kLittleEndian; -using google_breakpad::test_assembler::Section; - -using dwarf2reader::DwarfPointerEncoding; -using dwarf2reader::ENDIANNESS_BIG; -using dwarf2reader::ENDIANNESS_LITTLE; -using dwarf2reader::ByteReader; -using dwarf2reader::CallFrameInfo; - -using std::vector; -using testing::InSequence; -using testing::Return; -using testing::Sequence; -using testing::Test; -using testing::_; - -#ifdef WRITE_ELF -void WriteELFFrameSection(const char *filename, const char *section_name, - const CFISection §ion); -#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section) \ - WriteELFFrameSection("cfitest-" name, ".debug_frame", section); -#define PERHAPS_WRITE_EH_FRAME_FILE(name, section) \ - WriteELFFrameSection("cfitest-" name, ".eh_frame", section); -#else -#define PERHAPS_WRITE_DEBUG_FRAME_FILE(name, section) -#define PERHAPS_WRITE_EH_FRAME_FILE(name, section) -#endif - -class MockCallFrameInfoHandler: public CallFrameInfo::Handler { - public: - MOCK_METHOD6(Entry, bool(size_t offset, uint64 address, uint64 length, - uint8 version, const string &augmentation, - unsigned return_address)); - MOCK_METHOD2(UndefinedRule, bool(uint64 address, int reg)); - MOCK_METHOD2(SameValueRule, bool(uint64 address, int reg)); - MOCK_METHOD4(OffsetRule, bool(uint64 address, int reg, int base_register, - long offset)); - MOCK_METHOD4(ValOffsetRule, bool(uint64 address, int reg, int base_register, - long offset)); - MOCK_METHOD3(RegisterRule, bool(uint64 address, int reg, int base_register)); - MOCK_METHOD3(ExpressionRule, bool(uint64 address, int reg, - const string &expression)); - MOCK_METHOD3(ValExpressionRule, bool(uint64 address, int reg, - const string &expression)); - MOCK_METHOD0(End, bool()); - MOCK_METHOD2(PersonalityRoutine, bool(uint64 address, bool indirect)); - MOCK_METHOD2(LanguageSpecificDataArea, bool(uint64 address, bool indirect)); - MOCK_METHOD0(SignalHandler, bool()); -}; - -class MockCallFrameErrorReporter: public CallFrameInfo::Reporter { - public: - MockCallFrameErrorReporter() : Reporter("mock filename", "mock section") { } - MOCK_METHOD2(Incomplete, void(uint64, CallFrameInfo::EntryKind)); - MOCK_METHOD1(EarlyEHTerminator, void(uint64)); - MOCK_METHOD2(CIEPointerOutOfRange, void(uint64, uint64)); - MOCK_METHOD2(BadCIEId, void(uint64, uint64)); - MOCK_METHOD2(UnrecognizedVersion, void(uint64, int version)); - MOCK_METHOD2(UnrecognizedAugmentation, void(uint64, const string &)); - MOCK_METHOD2(InvalidPointerEncoding, void(uint64, uint8)); - MOCK_METHOD2(UnusablePointerEncoding, void(uint64, uint8)); - MOCK_METHOD2(RestoreInCIE, void(uint64, uint64)); - MOCK_METHOD3(BadInstruction, void(uint64, CallFrameInfo::EntryKind, uint64)); - MOCK_METHOD3(NoCFARule, void(uint64, CallFrameInfo::EntryKind, uint64)); - MOCK_METHOD3(EmptyStateStack, void(uint64, CallFrameInfo::EntryKind, uint64)); -}; - -struct CFIFixture { - - enum { kCFARegister = CallFrameInfo::Handler::kCFARegister }; - - CFIFixture() { - // Default expectations for the data handler. - // - // - Leave Entry and End without expectations, as it's probably a - // good idea to set those explicitly in each test. - // - // - Expect the *Rule functions to not be called, - // so that each test can simply list the calls they expect. - // - // I gather I could use StrictMock for this, but the manual seems - // to suggest using that only as a last resort, and this isn't so - // bad. - EXPECT_CALL(handler, UndefinedRule(_, _)).Times(0); - EXPECT_CALL(handler, SameValueRule(_, _)).Times(0); - EXPECT_CALL(handler, OffsetRule(_, _, _, _)).Times(0); - EXPECT_CALL(handler, ValOffsetRule(_, _, _, _)).Times(0); - EXPECT_CALL(handler, RegisterRule(_, _, _)).Times(0); - EXPECT_CALL(handler, ExpressionRule(_, _, _)).Times(0); - EXPECT_CALL(handler, ValExpressionRule(_, _, _)).Times(0); - EXPECT_CALL(handler, PersonalityRoutine(_, _)).Times(0); - EXPECT_CALL(handler, LanguageSpecificDataArea(_, _)).Times(0); - EXPECT_CALL(handler, SignalHandler()).Times(0); - - // Default expectations for the error/warning reporer. - EXPECT_CALL(reporter, Incomplete(_, _)).Times(0); - EXPECT_CALL(reporter, EarlyEHTerminator(_)).Times(0); - EXPECT_CALL(reporter, CIEPointerOutOfRange(_, _)).Times(0); - EXPECT_CALL(reporter, BadCIEId(_, _)).Times(0); - EXPECT_CALL(reporter, UnrecognizedVersion(_, _)).Times(0); - EXPECT_CALL(reporter, UnrecognizedAugmentation(_, _)).Times(0); - EXPECT_CALL(reporter, InvalidPointerEncoding(_, _)).Times(0); - EXPECT_CALL(reporter, UnusablePointerEncoding(_, _)).Times(0); - EXPECT_CALL(reporter, RestoreInCIE(_, _)).Times(0); - EXPECT_CALL(reporter, BadInstruction(_, _, _)).Times(0); - EXPECT_CALL(reporter, NoCFARule(_, _, _)).Times(0); - EXPECT_CALL(reporter, EmptyStateStack(_, _, _)).Times(0); - } - - MockCallFrameInfoHandler handler; - MockCallFrameErrorReporter reporter; -}; - -class CFI: public CFIFixture, public Test { }; - -TEST_F(CFI, EmptyRegion) { - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - static const uint8_t data[] = { 42 }; - - ByteReader byte_reader(ENDIANNESS_BIG); - CallFrameInfo parser(data, 0, &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -TEST_F(CFI, IncompleteLength32) { - CFISection section(kBigEndian, 8); - section - // Not even long enough for an initial length. - .D16(0xa0f) - // Padding to keep valgrind happy. We subtract these off when we - // construct the parser. - .D16(0); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) - .WillOnce(Return()); - - string contents; - ASSERT_TRUE(section.GetContents(&contents)); - - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size() - 2, - &byte_reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -TEST_F(CFI, IncompleteLength64) { - CFISection section(kLittleEndian, 4); - section - // An incomplete 64-bit DWARF initial length. - .D32(0xffffffff).D32(0x71fbaec2) - // Padding to keep valgrind happy. We subtract these off when we - // construct the parser. - .D32(0); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) - .WillOnce(Return()); - - string contents; - ASSERT_TRUE(section.GetContents(&contents)); - - ByteReader byte_reader(ENDIANNESS_LITTLE); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size() - 4, - &byte_reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -TEST_F(CFI, IncompleteId32) { - CFISection section(kBigEndian, 8); - section - .D32(3) // Initial length, not long enough for id - .D8(0xd7).D8(0xe5).D8(0xf1) // incomplete id - .CIEHeader(8727, 3983, 8889, 3, "") - .FinishEntry(); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - EXPECT_CALL(reporter, Incomplete(_, CallFrameInfo::kUnknown)) - .WillOnce(Return()); - - string contents; - ASSERT_TRUE(section.GetContents(&contents)); - - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -TEST_F(CFI, BadId32) { - CFISection section(kBigEndian, 8); - section - .D32(0x100) // Initial length - .D32(0xe802fade) // bogus ID - .Append(0x100 - 4, 0x42); // make the length true - section - .CIEHeader(1672, 9872, 8529, 3, "") - .FinishEntry(); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - EXPECT_CALL(reporter, CIEPointerOutOfRange(_, 0xe802fade)) - .WillOnce(Return()); - - string contents; - ASSERT_TRUE(section.GetContents(&contents)); - - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -// A lone CIE shouldn't cause any handler calls. -TEST_F(CFI, SingleCIE) { - CFISection section(kLittleEndian, 4); - section.CIEHeader(0xffe799a8, 0x3398dcdd, 0x6e9683de, 3, ""); - section.Append(10, dwarf2reader::DW_CFA_nop); - section.FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("SingleCIE", section); - - EXPECT_CALL(handler, Entry(_, _, _, _, _, _)).Times(0); - EXPECT_CALL(handler, End()).Times(0); - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_LITTLE); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// One FDE, one CIE. -TEST_F(CFI, OneFDE) { - CFISection section(kBigEndian, 4); - Label cie; - section - .Mark(&cie) - .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "") - .FinishEntry() - .FDEHeader(cie, 0x7714740d, 0x3d5a10cd) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("OneFDE", section); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0x7714740d, 0x3d5a10cd, 3, "", 0x6b6efb87)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// Two FDEs share a CIE. -TEST_F(CFI, TwoFDEsOneCIE) { - CFISection section(kBigEndian, 4); - Label cie; - section - // First FDE. readelf complains about this one because it makes - // a forward reference to its CIE. - .FDEHeader(cie, 0xa42744df, 0xa3b42121) - .FinishEntry() - // CIE. - .Mark(&cie) - .CIEHeader(0x04f7dc7b, 0x3d00c05f, 0xbd43cb59, 3, "") - .FinishEntry() - // Second FDE. - .FDEHeader(cie, 0x6057d391, 0x700f608d) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsOneCIE", section); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0xa42744df, 0xa3b42121, 3, "", 0xbd43cb59)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0x6057d391, 0x700f608d, 3, "", 0xbd43cb59)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// Two FDEs, two CIEs. -TEST_F(CFI, TwoFDEsTwoCIEs) { - CFISection section(kLittleEndian, 8); - Label cie1, cie2; - section - // First CIE. - .Mark(&cie1) - .CIEHeader(0x694d5d45, 0x4233221b, 0xbf45e65a, 3, "") - .FinishEntry() - // First FDE which cites second CIE. readelf complains about - // this one because it makes a forward reference to its CIE. - .FDEHeader(cie2, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL) - .FinishEntry() - // Second FDE, which cites first CIE. - .FDEHeader(cie1, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL) - .FinishEntry() - // Second CIE. - .Mark(&cie2) - .CIEHeader(0xfba3fad7, 0x6287e1fd, 0x61d2c581, 2, "") - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("TwoFDEsTwoCIEs", section); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0x778b27dfe5871f05ULL, 0x324ace3448070926ULL, 2, - "", 0x61d2c581)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, 0xf6054ca18b10bf5fULL, 0x45fdb970d8bca342ULL, 3, - "", 0xbf45e65a)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_LITTLE); - byte_reader.SetAddressSize(8); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// An FDE whose CIE specifies a version we don't recognize. -TEST_F(CFI, BadVersion) { - CFISection section(kBigEndian, 4); - Label cie1, cie2; - section - .Mark(&cie1) - .CIEHeader(0xca878cf0, 0x7698ec04, 0x7b616f54, 0x52, "") - .FinishEntry() - // We should skip this entry, as its CIE specifies a version we - // don't recognize. - .FDEHeader(cie1, 0x08852292, 0x2204004a) - .FinishEntry() - // Despite the above, we should visit this entry. - .Mark(&cie2) - .CIEHeader(0x7c3ae7c9, 0xb9b9a512, 0x96cb3264, 3, "") - .FinishEntry() - .FDEHeader(cie2, 0x2094735a, 0x6e875501) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("BadVersion", section); - - EXPECT_CALL(reporter, UnrecognizedVersion(_, 0x52)) - .WillOnce(Return()); - - { - InSequence s; - // We should see no mention of the first FDE, but we should get - // a call to Entry for the second. - EXPECT_CALL(handler, Entry(_, 0x2094735a, 0x6e875501, 3, "", - 0x96cb3264)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -// An FDE whose CIE specifies an augmentation we don't recognize. -TEST_F(CFI, BadAugmentation) { - CFISection section(kBigEndian, 4); - Label cie1, cie2; - section - .Mark(&cie1) - .CIEHeader(0x4be22f75, 0x2492236e, 0x6b6efb87, 3, "spaniels!") - .FinishEntry() - // We should skip this entry, as its CIE specifies an - // augmentation we don't recognize. - .FDEHeader(cie1, 0x7714740d, 0x3d5a10cd) - .FinishEntry() - // Despite the above, we should visit this entry. - .Mark(&cie2) - .CIEHeader(0xf8bc4399, 0x8cf09931, 0xf2f519b2, 3, "") - .FinishEntry() - .FDEHeader(cie2, 0x7bf0fda0, 0xcbcd28d8) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("BadAugmentation", section); - - EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "spaniels!")) - .WillOnce(Return()); - - { - InSequence s; - // We should see no mention of the first FDE, but we should get - // a call to Entry for the second. - EXPECT_CALL(handler, Entry(_, 0x7bf0fda0, 0xcbcd28d8, 3, "", - 0xf2f519b2)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_FALSE(parser.Start()); -} - -// The return address column field is a byte in CFI version 1 -// (DWARF2), but a ULEB128 value in version 3 (DWARF3). -TEST_F(CFI, CIEVersion1ReturnColumn) { - CFISection section(kBigEndian, 4); - Label cie; - section - // CIE, using the version 1 format: return column is a ubyte. - .Mark(&cie) - // Use a value for the return column that is parsed differently - // as a ubyte and as a ULEB128. - .CIEHeader(0xbcdea24f, 0x5be28286, 0x9f, 1, "") - .FinishEntry() - // FDE, citing that CIE. - .FDEHeader(cie, 0xb8d347b5, 0x825e55dc) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion1ReturnColumn", section); - - { - InSequence s; - EXPECT_CALL(handler, Entry(_, 0xb8d347b5, 0x825e55dc, 1, "", 0x9f)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -// The return address column field is a byte in CFI version 1 -// (DWARF2), but a ULEB128 value in version 3 (DWARF3). -TEST_F(CFI, CIEVersion3ReturnColumn) { - CFISection section(kBigEndian, 4); - Label cie; - section - // CIE, using the version 3 format: return column is a ULEB128. - .Mark(&cie) - // Use a value for the return column that is parsed differently - // as a ubyte and as a ULEB128. - .CIEHeader(0x0ab4758d, 0xc010fdf7, 0x89, 3, "") - .FinishEntry() - // FDE, citing that CIE. - .FDEHeader(cie, 0x86763f2b, 0x2a66dc23) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("CIEVersion3ReturnColumn", section); - - { - InSequence s; - EXPECT_CALL(handler, Entry(_, 0x86763f2b, 0x2a66dc23, 3, "", 0x89)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - string contents; - EXPECT_TRUE(section.GetContents(&contents)); - ByteReader byte_reader(ENDIANNESS_BIG); - byte_reader.SetAddressSize(4); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - EXPECT_TRUE(parser.Start()); -} - -struct CFIInsnFixture: public CFIFixture { - CFIInsnFixture() : CFIFixture() { - data_factor = 0xb6f; - return_register = 0x9be1ed9f; - version = 3; - cfa_base_register = 0x383a3aa; - cfa_offset = 0xf748; - } - - // Prepare SECTION to receive FDE instructions. - // - // - Append a stock CIE header that establishes the fixture's - // code_factor, data_factor, return_register, version, and - // augmentation values. - // - Have the CIE set up a CFA rule using cfa_base_register and - // cfa_offset. - // - Append a stock FDE header, referring to the above CIE, for the - // fde_size bytes at fde_start. Choose fde_start and fde_size - // appropriately for the section's address size. - // - Set appropriate expectations on handler in sequence s for the - // frame description entry and the CIE's CFA rule. - // - // On return, SECTION is ready to have FDE instructions appended to - // it, and its FinishEntry member called. - void StockCIEAndFDE(CFISection *section) { - // Choose appropriate constants for our address size. - if (section->AddressSize() == 4) { - fde_start = 0xc628ecfbU; - fde_size = 0x5dee04a2; - code_factor = 0x60b; - } else { - assert(section->AddressSize() == 8); - fde_start = 0x0005c57ce7806bd3ULL; - fde_size = 0x2699521b5e333100ULL; - code_factor = 0x01008e32855274a8ULL; - } - - // Create the CIE. - (*section) - .Mark(&cie_label) - .CIEHeader(code_factor, data_factor, return_register, version, - "") - .D8(dwarf2reader::DW_CFA_def_cfa) - .ULEB128(cfa_base_register) - .ULEB128(cfa_offset) - .FinishEntry(); - - // Create the FDE. - section->FDEHeader(cie_label, fde_start, fde_size); - - // Expect an Entry call for the FDE and a ValOffsetRule call for the - // CIE's CFA rule. - EXPECT_CALL(handler, Entry(_, fde_start, fde_size, version, "", - return_register)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start, kCFARegister, - cfa_base_register, cfa_offset)) - .InSequence(s) - .WillOnce(Return(true)); - } - - // Run the contents of SECTION through a CallFrameInfo parser, - // expecting parser.Start to return SUCCEEDS - void ParseSection(CFISection *section, bool succeeds = true) { - string contents; - EXPECT_TRUE(section->GetContents(&contents)); - dwarf2reader::Endianness endianness; - if (section->endianness() == kBigEndian) - endianness = ENDIANNESS_BIG; - else { - assert(section->endianness() == kLittleEndian); - endianness = ENDIANNESS_LITTLE; - } - ByteReader byte_reader(endianness); - byte_reader.SetAddressSize(section->AddressSize()); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter); - if (succeeds) - EXPECT_TRUE(parser.Start()); - else - EXPECT_FALSE(parser.Start()); - } - - Label cie_label; - Sequence s; - uint64 code_factor; - int data_factor; - unsigned return_register; - unsigned version; - unsigned cfa_base_register; - int cfa_offset; - uint64 fde_start, fde_size; -}; - -class CFIInsn: public CFIInsnFixture, public Test { }; - -TEST_F(CFIInsn, DW_CFA_set_loc) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_set_loc).D32(0xb1ee3e7a) - // Use DW_CFA_def_cfa to force a handler call that we can use to - // check the effect of the DW_CFA_set_loc. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4defb431).ULEB128(0x6d17b0ee) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_set_loc", section); - - EXPECT_CALL(handler, - ValOffsetRule(0xb1ee3e7a, kCFARegister, 0x4defb431, 0x6d17b0ee)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_advance_loc) { - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_advance_loc | 0x2a) - // Use DW_CFA_def_cfa to force a handler call that we can use to - // check the effect of the DW_CFA_advance_loc. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x5bbb3715).ULEB128(0x0186c7bf) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc", section); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start + 0x2a * code_factor, - kCFARegister, 0x5bbb3715, 0x0186c7bf)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_advance_loc1) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_advance_loc1).D8(0xd8) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x69d5696a).ULEB128(0x1eb7fc93) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc1", section); - - EXPECT_CALL(handler, - ValOffsetRule((fde_start + 0xd8 * code_factor), - kCFARegister, 0x69d5696a, 0x1eb7fc93)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_advance_loc2) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_advance_loc2).D16(0x3adb) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3a368bed).ULEB128(0x3194ee37) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc2", section); - - EXPECT_CALL(handler, - ValOffsetRule((fde_start + 0x3adb * code_factor), - kCFARegister, 0x3a368bed, 0x3194ee37)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_advance_loc4) { - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_advance_loc4).D32(0x15813c88) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x135270c5).ULEB128(0x24bad7cb) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc4", section); - - EXPECT_CALL(handler, - ValOffsetRule((fde_start + 0x15813c88ULL * code_factor), - kCFARegister, 0x135270c5, 0x24bad7cb)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_MIPS_advance_loc8) { - code_factor = 0x2d; - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_MIPS_advance_loc8).D64(0x3c4f3945b92c14ULL) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0xe17ed602).ULEB128(0x3d162e7f) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_advance_loc8", section); - - EXPECT_CALL(handler, - ValOffsetRule((fde_start + 0x3c4f3945b92c14ULL * code_factor), - kCFARegister, 0xe17ed602, 0x3d162e7f)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_def_cfa) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x4e363a85).ULEB128(0x815f9aa7) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("DW_CFA_def_cfa", section); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x4e363a85, 0x815f9aa7)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_def_cfa_sf) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x8ccb32b7).LEB128(0x9ea) - .D8(dwarf2reader::DW_CFA_def_cfa_sf).ULEB128(0x9b40f5da).LEB128(-0x40a2) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x8ccb32b7, - 0x9ea * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x9b40f5da, - -0x40a2 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_def_cfa_register) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0x3e7e9363) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x3e7e9363, cfa_offset)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -// DW_CFA_def_cfa_register should have no effect when applied to a -// non-base/offset rule. -TEST_F(CFIInsn, DW_CFA_def_cfa_registerBadRule) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("needle in a haystack") - .D8(dwarf2reader::DW_CFA_def_cfa_register).ULEB128(0xf1b49e49) - .FinishEntry(); - - EXPECT_CALL(handler, - ValExpressionRule(fde_start, kCFARegister, - "needle in a haystack")) - .WillRepeatedly(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_def_cfa_offset) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, cfa_base_register, - 0x1e8e3b9b)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_def_cfa_offset_sf) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(0x970) - .D8(dwarf2reader::DW_CFA_def_cfa_offset_sf).LEB128(-0x2cd) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, cfa_base_register, - 0x970 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, cfa_base_register, - -0x2cd * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -// DW_CFA_def_cfa_offset should have no effect when applied to a -// non-base/offset rule. -TEST_F(CFIInsn, DW_CFA_def_cfa_offsetBadRule) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("six ways to Sunday") - .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x1e8e3b9b) - .FinishEntry(); - - EXPECT_CALL(handler, - ValExpressionRule(fde_start, kCFARegister, "six ways to Sunday")) - .WillRepeatedly(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_def_cfa_expression) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_def_cfa_expression).Block("eating crow") - .FinishEntry(); - - EXPECT_CALL(handler, ValExpressionRule(fde_start, kCFARegister, - "eating crow")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_undefined) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x300ce45d) - .FinishEntry(); - - EXPECT_CALL(handler, UndefinedRule(fde_start, 0x300ce45d)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_same_value) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3865a760) - .FinishEntry(); - - EXPECT_CALL(handler, SameValueRule(fde_start, 0x3865a760)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_offset) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x9f6) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x2c, kCFARegister, 0x9f6 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_offset_extended) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_offset_extended).ULEB128(0x402b).ULEB128(0xb48) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x402b, kCFARegister, 0xb48 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_offset_extended_sf) { - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_offset_extended_sf) - .ULEB128(0x997c23ee).LEB128(0x2d00) - .D8(dwarf2reader::DW_CFA_offset_extended_sf) - .ULEB128(0x9519eb82).LEB128(-0xa77) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x997c23ee, - kCFARegister, 0x2d00 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x9519eb82, - kCFARegister, -0xa77 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_val_offset) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x623562fe).ULEB128(0x673) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, 0x623562fe, - kCFARegister, 0x673 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_val_offset_sf) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x6f4f).LEB128(0xaab) - .D8(dwarf2reader::DW_CFA_val_offset_sf).ULEB128(0x2483).LEB128(-0x8a2) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, 0x6f4f, - kCFARegister, 0xaab * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, - ValOffsetRule(fde_start, 0x2483, - kCFARegister, -0x8a2 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_register) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x278d18f9).ULEB128(0x1a684414) - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0x278d18f9, 0x1a684414)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_expression) { - CFISection section(kBigEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xa1619fb2) - .Block("plus ça change, plus c'est la même chose") - .FinishEntry(); - - EXPECT_CALL(handler, - ExpressionRule(fde_start, 0xa1619fb2, - "plus ça change, plus c'est la même chose")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_val_expression) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xc5e4a9e3) - .Block("he who has the gold makes the rules") - .FinishEntry(); - - EXPECT_CALL(handler, - ValExpressionRule(fde_start, 0xc5e4a9e3, - "he who has the gold makes the rules")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_restore) { - CFISection section(kLittleEndian, 8); - code_factor = 0x01bd188a9b1fa083ULL; - data_factor = -0x1ac8; - return_register = 0x8c35b049; - version = 2; - fde_start = 0x2d70fe998298bbb1ULL; - fde_size = 0x46ccc2e63cf0b108ULL; - Label cie; - section - .Mark(&cie) - .CIEHeader(code_factor, data_factor, return_register, version, - "") - // Provide a CFA rule, because register rules require them. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x6ca1d50e).ULEB128(0x372e38e8) - // Provide an offset(N) rule for register 0x3c. - .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0xb348) - .FinishEntry() - // In the FDE... - .FDEHeader(cie, fde_start, fde_size) - // At a second address, provide a new offset(N) rule for register 0x3c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x13) - .D8(dwarf2reader::DW_CFA_offset | 0x3c).ULEB128(0x9a50) - // At a third address, restore the original rule for register 0x3c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x01) - .D8(dwarf2reader::DW_CFA_restore | 0x3c) - .FinishEntry(); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, fde_start, fde_size, version, "", return_register)) - .WillOnce(Return(true)); - // CIE's CFA rule. - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x6ca1d50e, 0x372e38e8)) - .WillOnce(Return(true)); - // CIE's rule for register 0x3c. - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x3c, kCFARegister, 0xb348 * data_factor)) - .WillOnce(Return(true)); - // FDE's rule for register 0x3c. - EXPECT_CALL(handler, - OffsetRule(fde_start + 0x13 * code_factor, 0x3c, - kCFARegister, 0x9a50 * data_factor)) - .WillOnce(Return(true)); - // Restore CIE's rule for register 0x3c. - EXPECT_CALL(handler, - OffsetRule(fde_start + (0x13 + 0x01) * code_factor, 0x3c, - kCFARegister, 0xb348 * data_factor)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_restoreNoRule) { - CFISection section(kBigEndian, 4); - code_factor = 0x005f78143c1c3b82ULL; - data_factor = 0x25d0; - return_register = 0xe8; - version = 1; - fde_start = 0x4062e30f; - fde_size = 0x5302a389; - Label cie; - section - .Mark(&cie) - .CIEHeader(code_factor, data_factor, return_register, version, "") - // Provide a CFA rule, because register rules require them. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x470aa334).ULEB128(0x099ef127) - .FinishEntry() - // In the FDE... - .FDEHeader(cie, fde_start, fde_size) - // At a second address, provide an offset(N) rule for register 0x2c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x7) - .D8(dwarf2reader::DW_CFA_offset | 0x2c).ULEB128(0x1f47) - // At a third address, restore the (missing) CIE rule for register 0x2c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0xb) - .D8(dwarf2reader::DW_CFA_restore | 0x2c) - .FinishEntry(); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, fde_start, fde_size, version, "", return_register)) - .WillOnce(Return(true)); - // CIE's CFA rule. - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x470aa334, 0x099ef127)) - .WillOnce(Return(true)); - // FDE's rule for register 0x2c. - EXPECT_CALL(handler, - OffsetRule(fde_start + 0x7 * code_factor, 0x2c, - kCFARegister, 0x1f47 * data_factor)) - .WillOnce(Return(true)); - // Restore CIE's (missing) rule for register 0x2c. - EXPECT_CALL(handler, - SameValueRule(fde_start + (0x7 + 0xb) * code_factor, 0x2c)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_restore_extended) { - CFISection section(kBigEndian, 4); - code_factor = 0x126e; - data_factor = -0xd8b; - return_register = 0x77711787; - version = 3; - fde_start = 0x01f55a45; - fde_size = 0x452adb80; - Label cie; - section - .Mark(&cie) - .CIEHeader(code_factor, data_factor, return_register, version, - "", true /* dwarf64 */ ) - // Provide a CFA rule, because register rules require them. - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x56fa0edd).ULEB128(0x097f78a5) - // Provide an offset(N) rule for register 0x0f9b8a1c. - .D8(dwarf2reader::DW_CFA_offset_extended) - .ULEB128(0x0f9b8a1c).ULEB128(0xc979) - .FinishEntry() - // In the FDE... - .FDEHeader(cie, fde_start, fde_size) - // At a second address, provide a new offset(N) rule for reg 0x0f9b8a1c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x3) - .D8(dwarf2reader::DW_CFA_offset_extended) - .ULEB128(0x0f9b8a1c).ULEB128(0x3b7b) - // At a third address, restore the original rule for register 0x0f9b8a1c. - .D8(dwarf2reader::DW_CFA_advance_loc | 0x04) - .D8(dwarf2reader::DW_CFA_restore_extended).ULEB128(0x0f9b8a1c) - .FinishEntry(); - - { - InSequence s; - EXPECT_CALL(handler, - Entry(_, fde_start, fde_size, version, "", return_register)) - .WillOnce(Return(true)); - // CIE's CFA rule. - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x56fa0edd, 0x097f78a5)) - .WillOnce(Return(true)); - // CIE's rule for register 0x0f9b8a1c. - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x0f9b8a1c, kCFARegister, - 0xc979 * data_factor)) - .WillOnce(Return(true)); - // FDE's rule for register 0x0f9b8a1c. - EXPECT_CALL(handler, - OffsetRule(fde_start + 0x3 * code_factor, 0x0f9b8a1c, - kCFARegister, 0x3b7b * data_factor)) - .WillOnce(Return(true)); - // Restore CIE's rule for register 0x0f9b8a1c. - EXPECT_CALL(handler, - OffsetRule(fde_start + (0x3 + 0x4) * code_factor, 0x0f9b8a1c, - kCFARegister, 0xc979 * data_factor)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - } - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_remember_and_restore_state) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - - // We create a state, save it, modify it, and then restore. We - // refer to the state that is overridden the restore as the - // "outgoing" state, and the restored state the "incoming" state. - // - // Register outgoing incoming expect - // 1 offset(N) no rule new "same value" rule - // 2 register(R) offset(N) report changed rule - // 3 offset(N) offset(M) report changed offset - // 4 offset(N) offset(N) no report - // 5 offset(N) no rule new "same value" rule - section - // Create the "incoming" state, which we will save and later restore. - .D8(dwarf2reader::DW_CFA_offset | 2).ULEB128(0x9806) - .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0x995d) - .D8(dwarf2reader::DW_CFA_offset | 4).ULEB128(0x7055) - .D8(dwarf2reader::DW_CFA_remember_state) - // Advance to a new instruction; an implementation could legitimately - // ignore all but the final rule for a given register at a given address. - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - // Create the "outgoing" state, which we will discard. - .D8(dwarf2reader::DW_CFA_offset | 1).ULEB128(0xea1a) - .D8(dwarf2reader::DW_CFA_register).ULEB128(2).ULEB128(0x1d2a3767) - .D8(dwarf2reader::DW_CFA_offset | 3).ULEB128(0xdd29) - .D8(dwarf2reader::DW_CFA_offset | 5).ULEB128(0xf1ce) - // At a third address, restore the incoming state. - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - uint64 addr = fde_start; - - // Expect the incoming rules to be reported. - EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 4, kCFARegister, 0x7055 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - - addr += code_factor; - - // After the save, we establish the outgoing rule set. - EXPECT_CALL(handler, OffsetRule(addr, 1, kCFARegister, 0xea1a * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(addr, 2, 0x1d2a3767)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0xdd29 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 5, kCFARegister, 0xf1ce * data_factor)) - .InSequence(s).WillOnce(Return(true)); - - addr += code_factor; - - // Finally, after the restore, expect to see the differences from - // the outgoing to the incoming rules reported. - EXPECT_CALL(handler, SameValueRule(addr, 1)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 2, kCFARegister, 0x9806 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(addr, 3, kCFARegister, 0x995d * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SameValueRule(addr, 5)) - .InSequence(s).WillOnce(Return(true)); - - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -// Check that restoring a rule set reports changes to the CFA rule. -TEST_F(CFIInsn, DW_CFA_remember_and_restore_stateCFA) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - - section - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_def_cfa_offset).ULEB128(0x90481102) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, kCFARegister, - cfa_base_register, 0x90481102)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor * 2, kCFARegister, - cfa_base_register, cfa_offset)) - .InSequence(s).WillOnce(Return(true)); - - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_nop) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_nop) - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x3fb8d4f1).ULEB128(0x078dc67b) - .D8(dwarf2reader::DW_CFA_nop) - .FinishEntry(); - - EXPECT_CALL(handler, - ValOffsetRule(fde_start, kCFARegister, 0x3fb8d4f1, 0x078dc67b)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_GNU_window_save) { - CFISection section(kBigEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_GNU_window_save) - .FinishEntry(); - - // Don't include all the rules in any particular sequence. - - // The caller's %o0-%o7 have become the callee's %i0-%i7. This is - // the GCC register numbering. - for (int i = 8; i < 16; i++) - EXPECT_CALL(handler, RegisterRule(fde_start, i, i + 16)) - .WillOnce(Return(true)); - // The caller's %l0-%l7 and %i0-%i7 have been saved at the top of - // its frame. - for (int i = 16; i < 32; i++) - EXPECT_CALL(handler, OffsetRule(fde_start, i, kCFARegister, (i-16) * 4)) - .WillOnce(Return(true)); - - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_GNU_args_size) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_GNU_args_size).ULEB128(0xeddfa520) - // Verify that we see this, meaning we parsed the above properly. - .D8(dwarf2reader::DW_CFA_offset | 0x23).ULEB128(0x269) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x23, kCFARegister, 0x269 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIInsn, DW_CFA_GNU_negative_offset_extended) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_GNU_negative_offset_extended) - .ULEB128(0x430cc87a).ULEB128(0x613) - .FinishEntry(); - - EXPECT_CALL(handler, - OffsetRule(fde_start, 0x430cc87a, - kCFARegister, -0x613 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion); -} - -// Three FDEs: skip the second -TEST_F(CFIInsn, SkipFDE) { - CFISection section(kBigEndian, 4); - Label cie; - section - // CIE, used by all FDEs. - .Mark(&cie) - .CIEHeader(0x010269f2, 0x9177, 0xedca5849, 2, "") - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(0x42ed390b).ULEB128(0x98f43aad) - .FinishEntry() - // First FDE. - .FDEHeader(cie, 0xa870ebdd, 0x60f6aa4) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x3a860351).ULEB128(0x6c9a6bcf) - .FinishEntry() - // Second FDE. - .FDEHeader(cie, 0xc534f7c0, 0xf6552e9, true /* dwarf64 */) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x1b62c234).ULEB128(0x26586b18) - .FinishEntry() - // Third FDE. - .FDEHeader(cie, 0xf681cfc8, 0x7e4594e) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x26c53934).ULEB128(0x18eeb8a4) - .FinishEntry(); - - { - InSequence s; - - // Process the first FDE. - EXPECT_CALL(handler, Entry(_, 0xa870ebdd, 0x60f6aa4, 2, "", 0xedca5849)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0xa870ebdd, kCFARegister, - 0x42ed390b, 0x98f43aad)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(0xa870ebdd, 0x3a860351, 0x6c9a6bcf)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .WillOnce(Return(true)); - - // Skip the second FDE. - EXPECT_CALL(handler, Entry(_, 0xc534f7c0, 0xf6552e9, 2, "", 0xedca5849)) - .WillOnce(Return(false)); - - // Process the third FDE. - EXPECT_CALL(handler, Entry(_, 0xf681cfc8, 0x7e4594e, 2, "", 0xedca5849)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0xf681cfc8, kCFARegister, - 0x42ed390b, 0x98f43aad)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(0xf681cfc8, 0x26c53934, 0x18eeb8a4)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .WillOnce(Return(true)); - } - - ParseSection(§ion); -} - -// Quit processing in the middle of an entry's instructions. -TEST_F(CFIInsn, QuitMidentry) { - CFISection section(kLittleEndian, 8); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe0cf850d).ULEB128(0x15aab431) - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x46750aa5).Block("meat") - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0xe0cf850d, 0x15aab431)) - .InSequence(s).WillOnce(Return(false)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseSection(§ion, false); -} - -class CFIRestore: public CFIInsnFixture, public Test { }; - -TEST_F(CFIRestore, RestoreUndefinedRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x0bac878e) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, UndefinedRule(fde_start, 0x0bac878e)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreUndefinedRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x7dedff5f) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x7dedff5f) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, UndefinedRule(fde_start, 0x7dedff5f)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SameValueRule(fde_start + code_factor, 0x7dedff5f)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + 2 * code_factor, 0x7dedff5f)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreSameValueRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0xadbc9b3a) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, SameValueRule(fde_start, 0xadbc9b3a)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreSameValueRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_same_value).ULEB128(0x3d90dcb5) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x3d90dcb5) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, SameValueRule(fde_start, 0x3d90dcb5)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x3d90dcb5)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SameValueRule(fde_start + 2 * code_factor, 0x3d90dcb5)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreOffsetRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_offset | 0x14).ULEB128(0xb6f) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, OffsetRule(fde_start, 0x14, - kCFARegister, 0xb6f * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreOffsetRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xeb7) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x21) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, - kCFARegister, 0xeb7 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0x21)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21, - kCFARegister, 0xeb7 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreOffsetRuleChangedOffset) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0x134) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_offset | 0x21).ULEB128(0xf4f) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, OffsetRule(fde_start, 0x21, - kCFARegister, 0x134 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(fde_start + code_factor, 0x21, - kCFARegister, 0xf4f * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, OffsetRule(fde_start + 2 * code_factor, 0x21, - kCFARegister, 0x134 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreValOffsetRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x829caee6).ULEB128(0xe4c) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x829caee6, - kCFARegister, 0xe4c * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreValOffsetRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0xf17c36d6).ULEB128(0xeb7) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xf17c36d6) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValOffsetRule(fde_start, 0xf17c36d6, - kCFARegister, 0xeb7 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xf17c36d6)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0xf17c36d6, - kCFARegister, 0xeb7 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreValOffsetRuleChangedValOffset) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0x562) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_val_offset).ULEB128(0x2cf0ab1b).ULEB128(0xe88) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValOffsetRule(fde_start, 0x2cf0ab1b, - kCFARegister, 0x562 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start + code_factor, 0x2cf0ab1b, - kCFARegister, 0xe88 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(fde_start + 2 * code_factor, 0x2cf0ab1b, - kCFARegister, 0x562 * data_factor)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreRegisterRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0x77514acc).ULEB128(0x464de4ce) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0x77514acc, 0x464de4ce)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreRegisterRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xe39acce5).ULEB128(0x095f1559) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xe39acce5) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0xe39acce5, 0x095f1559)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xe39acce5)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xe39acce5, - 0x095f1559)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreRegisterRuleChangedRegister) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0x16607d6a) - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_register).ULEB128(0xd40e21b1).ULEB128(0xbabb4742) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, RegisterRule(fde_start, 0xd40e21b1, 0x16607d6a)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(fde_start + code_factor, 0xd40e21b1, - 0xbabb4742)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, RegisterRule(fde_start + 2 * code_factor, 0xd40e21b1, - 0x16607d6a)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreExpressionRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x666ae152).Block("dwarf") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ExpressionRule(fde_start, 0x666ae152, "dwarf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreExpressionRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0xb5ca5c46).Block("elf") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ExpressionRule(fde_start, 0xb5ca5c46, "elf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46, - "elf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreExpressionRuleChangedExpression) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("smurf") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_expression).ULEB128(0x500f5739).Block("orc") - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ExpressionRule(fde_start, 0x500f5739, "smurf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ExpressionRule(fde_start + code_factor, 0x500f5739, - "orc")) - .InSequence(s).WillOnce(Return(true)); - // Expectations are not wishes. - EXPECT_CALL(handler, ExpressionRule(fde_start + 2 * code_factor, 0x500f5739, - "smurf")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreValExpressionRuleUnchanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x666ae152) - .Block("hideous") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x666ae152, "hideous")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreValExpressionRuleChanged) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0xb5ca5c46) - .Block("revolting") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0xb5ca5c46) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChanged", section); - - EXPECT_CALL(handler, ValExpressionRule(fde_start, 0xb5ca5c46, "revolting")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(fde_start + code_factor, 0xb5ca5c46)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0xb5ca5c46, - "revolting")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -TEST_F(CFIRestore, RestoreValExpressionRuleChangedValExpression) { - CFISection section(kLittleEndian, 4); - StockCIEAndFDE(§ion); - section - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739) - .Block("repulsive") - .D8(dwarf2reader::DW_CFA_remember_state) - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_val_expression).ULEB128(0x500f5739) - .Block("nauseous") - .D8(dwarf2reader::DW_CFA_advance_loc | 1) - .D8(dwarf2reader::DW_CFA_restore_state) - .FinishEntry(); - - PERHAPS_WRITE_DEBUG_FRAME_FILE("RestoreValExpressionRuleChangedValExpression", - section); - - EXPECT_CALL(handler, ValExpressionRule(fde_start, 0x500f5739, "repulsive")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValExpressionRule(fde_start + code_factor, 0x500f5739, - "nauseous")) - .InSequence(s).WillOnce(Return(true)); - // Expectations are not wishes. - EXPECT_CALL(handler, ValExpressionRule(fde_start + 2 * code_factor, 0x500f5739, - "repulsive")) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()).WillOnce(Return(true)); - - ParseSection(§ion); -} - -struct EHFrameFixture: public CFIInsnFixture { - EHFrameFixture() - : CFIInsnFixture(), section(kBigEndian, 4, true) { - encoded_pointer_bases.cfi = 0x7f496cb2; - encoded_pointer_bases.text = 0x540f67b6; - encoded_pointer_bases.data = 0xe3eab768; - section.SetEncodedPointerBases(encoded_pointer_bases); - } - CFISection section; - CFISection::EncodedPointerBases encoded_pointer_bases; - - // Parse CFIInsnFixture::ParseSection, but parse the section as - // .eh_frame data, supplying stock base addresses. - void ParseEHFrameSection(CFISection *section, bool succeeds = true) { - EXPECT_TRUE(section->ContainsEHFrame()); - string contents; - EXPECT_TRUE(section->GetContents(&contents)); - dwarf2reader::Endianness endianness; - if (section->endianness() == kBigEndian) - endianness = ENDIANNESS_BIG; - else { - assert(section->endianness() == kLittleEndian); - endianness = ENDIANNESS_LITTLE; - } - ByteReader byte_reader(endianness); - byte_reader.SetAddressSize(section->AddressSize()); - byte_reader.SetCFIDataBase(encoded_pointer_bases.cfi, - reinterpret_cast<const uint8_t *>(contents.data())); - byte_reader.SetTextBase(encoded_pointer_bases.text); - byte_reader.SetDataBase(encoded_pointer_bases.data); - CallFrameInfo parser(reinterpret_cast<const uint8_t *>(contents.data()), - contents.size(), - &byte_reader, &handler, &reporter, true); - if (succeeds) - EXPECT_TRUE(parser.Start()); - else - EXPECT_FALSE(parser.Start()); - } - -}; - -class EHFrame: public EHFrameFixture, public Test { }; - -// A simple CIE, an FDE, and a terminator. -TEST_F(EHFrame, Terminator) { - Label cie; - section - .Mark(&cie) - .CIEHeader(9968, 2466, 67, 1, "") - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3772).ULEB128(1372) - .FinishEntry() - .FDEHeader(cie, 0x848037a1, 0x7b30475e) - .D8(dwarf2reader::DW_CFA_set_loc).D32(0x17713850) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(5721) - .FinishEntry() - .D32(0) // Terminate the sequence. - // This FDE should be ignored. - .FDEHeader(cie, 0xf19629fe, 0x439fb09b) - .FinishEntry(); - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.Terminator", section); - - EXPECT_CALL(handler, Entry(_, 0x848037a1, 0x7b30475e, 1, "", 67)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0x848037a1, kCFARegister, 3772, 1372)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(0x17713850, 5721)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(reporter, EarlyEHTerminator(_)) - .InSequence(s).WillOnce(Return()); - - ParseEHFrameSection(§ion); -} - -// The parser should recognize the Linux Standards Base 'z' augmentations. -TEST_F(EHFrame, SimpleFDE) { - DwarfPointerEncoding lsda_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_indirect - | dwarf2reader::DW_EH_PE_datarel - | dwarf2reader::DW_EH_PE_sdata2); - DwarfPointerEncoding fde_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel - | dwarf2reader::DW_EH_PE_udata2); - - section.SetPointerEncoding(fde_encoding); - section.SetEncodedPointerBases(encoded_pointer_bases); - Label cie; - section - .Mark(&cie) - .CIEHeader(4873, 7012, 100, 1, "zSLPR") - .ULEB128(7) // Augmentation data length - .D8(lsda_encoding) // LSDA pointer format - .D8(dwarf2reader::DW_EH_PE_pcrel) // personality pointer format - .EncodedPointer(0x97baa00, dwarf2reader::DW_EH_PE_pcrel) // and value - .D8(fde_encoding) // FDE pointer format - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(6706).ULEB128(31) - .FinishEntry() - .FDEHeader(cie, 0x540f6b56, 0xf686) - .ULEB128(2) // Augmentation data length - .EncodedPointer(0xe3eab475, lsda_encoding) // LSDA pointer, signed - .D8(dwarf2reader::DW_CFA_set_loc) - .EncodedPointer(0x540fa4ce, fde_encoding) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(0x675e) - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.SimpleFDE", section); - - EXPECT_CALL(handler, Entry(_, 0x540f6b56, 0xf686, 1, "zSLPR", 100)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, PersonalityRoutine(0x97baa00, false)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, LanguageSpecificDataArea(0xe3eab475, true)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SignalHandler()) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0x540f6b56, kCFARegister, 6706, 31)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(0x540fa4ce, 0x675e)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -// Check that we can handle an empty 'z' augmentation. -TEST_F(EHFrame, EmptyZ) { - Label cie; - section - .Mark(&cie) - .CIEHeader(5955, 5805, 228, 1, "z") - .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(3629).ULEB128(247) - .FinishEntry() - .FDEHeader(cie, 0xda007738, 0xfb55c641) - .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_advance_loc1).D8(11) - .D8(dwarf2reader::DW_CFA_undefined).ULEB128(3769) - .FinishEntry(); - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.EmptyZ", section); - - EXPECT_CALL(handler, Entry(_, 0xda007738, 0xfb55c641, 1, "z", 228)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, ValOffsetRule(0xda007738, kCFARegister, 3629, 247)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, UndefinedRule(0xda007738 + 11 * 5955, 3769)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -// Check that we recognize bad 'z' augmentation characters. -TEST_F(EHFrame, BadZ) { - Label cie; - section - .Mark(&cie) - .CIEHeader(6937, 1045, 142, 1, "zQ") - .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_def_cfa).ULEB128(9006).ULEB128(7725) - .FinishEntry() - .FDEHeader(cie, 0x1293efa8, 0x236f53f2) - .ULEB128(0) // Augmentation data length - .D8(dwarf2reader::DW_CFA_advance_loc | 12) - .D8(dwarf2reader::DW_CFA_register).ULEB128(5667).ULEB128(3462) - .FinishEntry(); - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.BadZ", section); - - EXPECT_CALL(reporter, UnrecognizedAugmentation(_, "zQ")) - .WillOnce(Return()); - - ParseEHFrameSection(§ion, false); -} - -TEST_F(EHFrame, zL) { - Label cie; - DwarfPointerEncoding lsda_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_funcrel - | dwarf2reader::DW_EH_PE_udata2); - section - .Mark(&cie) - .CIEHeader(9285, 9959, 54, 1, "zL") - .ULEB128(1) // Augmentation data length - .D8(lsda_encoding) // encoding for LSDA pointer in FDE - - .FinishEntry() - .FDEHeader(cie, 0xd40091aa, 0x9aa6e746) - .ULEB128(2) // Augmentation data length - .EncodedPointer(0xd40099cd, lsda_encoding) // LSDA pointer - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zL", section); - - EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zL", 54)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, LanguageSpecificDataArea(0xd40099cd, false)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -TEST_F(EHFrame, zP) { - Label cie; - DwarfPointerEncoding personality_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_datarel - | dwarf2reader::DW_EH_PE_udata2); - section - .Mark(&cie) - .CIEHeader(1097, 6313, 17, 1, "zP") - .ULEB128(3) // Augmentation data length - .D8(personality_encoding) // encoding for personality routine - .EncodedPointer(0xe3eaccac, personality_encoding) // value - .FinishEntry() - .FDEHeader(cie, 0x0c8350c9, 0xbef11087) - .ULEB128(0) // Augmentation data length - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zP", section); - - EXPECT_CALL(handler, Entry(_, 0x0c8350c9, 0xbef11087, 1, "zP", 17)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, PersonalityRoutine(0xe3eaccac, false)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -TEST_F(EHFrame, zR) { - Label cie; - DwarfPointerEncoding pointer_encoding = - DwarfPointerEncoding(dwarf2reader::DW_EH_PE_textrel - | dwarf2reader::DW_EH_PE_sdata2); - section.SetPointerEncoding(pointer_encoding); - section - .Mark(&cie) - .CIEHeader(8011, 5496, 75, 1, "zR") - .ULEB128(1) // Augmentation data length - .D8(pointer_encoding) // encoding for FDE addresses - .FinishEntry() - .FDEHeader(cie, 0x540f9431, 0xbd0) - .ULEB128(0) // Augmentation data length - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zR", section); - - EXPECT_CALL(handler, Entry(_, 0x540f9431, 0xbd0, 1, "zR", 75)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -TEST_F(EHFrame, zS) { - Label cie; - section - .Mark(&cie) - .CIEHeader(9217, 7694, 57, 1, "zS") - .ULEB128(0) // Augmentation data length - .FinishEntry() - .FDEHeader(cie, 0xd40091aa, 0x9aa6e746) - .ULEB128(0) // Augmentation data length - .FinishEntry() - .D32(0); // terminator - - PERHAPS_WRITE_EH_FRAME_FILE("EHFrame.zS", section); - - EXPECT_CALL(handler, Entry(_, 0xd40091aa, 0x9aa6e746, 1, "zS", 57)) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, SignalHandler()) - .InSequence(s).WillOnce(Return(true)); - EXPECT_CALL(handler, End()) - .InSequence(s).WillOnce(Return(true)); - - ParseEHFrameSection(§ion); -} - -// These tests require manual inspection of the test output. -struct CFIReporterFixture { - CFIReporterFixture() : reporter("test file name", "test section name") { } - CallFrameInfo::Reporter reporter; -}; - -class CFIReporter: public CFIReporterFixture, public Test { }; - -TEST_F(CFIReporter, Incomplete) { - reporter.Incomplete(0x0102030405060708ULL, CallFrameInfo::kUnknown); -} - -TEST_F(CFIReporter, EarlyEHTerminator) { - reporter.EarlyEHTerminator(0x0102030405060708ULL); -} - -TEST_F(CFIReporter, CIEPointerOutOfRange) { - reporter.CIEPointerOutOfRange(0x0123456789abcdefULL, 0xfedcba9876543210ULL); -} - -TEST_F(CFIReporter, BadCIEId) { - reporter.BadCIEId(0x0123456789abcdefULL, 0xfedcba9876543210ULL); -} - -TEST_F(CFIReporter, UnrecognizedVersion) { - reporter.UnrecognizedVersion(0x0123456789abcdefULL, 43); -} - -TEST_F(CFIReporter, UnrecognizedAugmentation) { - reporter.UnrecognizedAugmentation(0x0123456789abcdefULL, "poodles"); -} - -TEST_F(CFIReporter, InvalidPointerEncoding) { - reporter.InvalidPointerEncoding(0x0123456789abcdefULL, 0x42); -} - -TEST_F(CFIReporter, UnusablePointerEncoding) { - reporter.UnusablePointerEncoding(0x0123456789abcdefULL, 0x42); -} - -TEST_F(CFIReporter, RestoreInCIE) { - reporter.RestoreInCIE(0x0123456789abcdefULL, 0xfedcba9876543210ULL); -} - -TEST_F(CFIReporter, BadInstruction) { - reporter.BadInstruction(0x0123456789abcdefULL, CallFrameInfo::kFDE, - 0xfedcba9876543210ULL); -} - -TEST_F(CFIReporter, NoCFARule) { - reporter.NoCFARule(0x0123456789abcdefULL, CallFrameInfo::kCIE, - 0xfedcba9876543210ULL); -} - -TEST_F(CFIReporter, EmptyStateStack) { - reporter.EmptyStateStack(0x0123456789abcdefULL, CallFrameInfo::kTerminator, - 0xfedcba9876543210ULL); -} - -TEST_F(CFIReporter, ClearingCFARule) { - reporter.ClearingCFARule(0x0123456789abcdefULL, CallFrameInfo::kFDE, - 0xfedcba9876543210ULL); -} - -#ifdef WRITE_ELF -// See comments at the top of the file mentioning WRITE_ELF for details. - -using google_breakpad::test_assembler::Section; - -struct ELFSectionHeader { - ELFSectionHeader(unsigned int set_type) - : type(set_type), flags(0), address(0), link(0), info(0), - alignment(1), entry_size(0) { } - Label name; - unsigned int type; - uint64_t flags; - uint64_t address; - Label file_offset; - Label file_size; - unsigned int link; - unsigned int info; - uint64_t alignment; - uint64_t entry_size; -}; - -void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) { - (*table) - .D32(header.name) // name, index in string tbl - .D32(header.type) // type - .Address(header.flags) // flags - .Address(header.address) // address in memory - .Address(header.file_offset) // offset in ELF file - .Address(header.file_size) // length in bytes - .D32(header.link) // link to related section - .D32(header.info) // miscellaneous - .Address(header.alignment) // alignment - .Address(header.entry_size); // entry size -} - -void WriteELFFrameSection(const char *filename, const char *cfi_name, - const CFISection &cfi) { - int elf_class = cfi.AddressSize() == 4 ? ELFCLASS32 : ELFCLASS64; - int elf_data = (cfi.endianness() == kBigEndian - ? ELFDATA2MSB : ELFDATA2LSB); - CFISection elf(cfi.endianness(), cfi.AddressSize()); - Label elf_header_size, section_table_offset; - elf - .Append("\x7f" "ELF") - .D8(elf_class) // 32-bit or 64-bit ELF - .D8(elf_data) // endianness - .D8(1) // ELF version - .D8(ELFOSABI_LINUX) // Operating System/ABI indication - .D8(0) // ABI version - .Append(7, 0xda) // padding - .D16(ET_EXEC) // file type: executable file - .D16(EM_386) // architecture: Intel IA-32 - .D32(EV_CURRENT); // ELF version - elf - .Address(0x0123456789abcdefULL) // program entry point - .Address(0) // program header offset - .Address(section_table_offset) // section header offset - .D32(0) // processor-specific flags - .D16(elf_header_size) // ELF header size in bytes */ - .D16(elf_class == ELFCLASS32 ? 32 : 56) // program header entry size - .D16(0) // program header table entry count - .D16(elf_class == ELFCLASS32 ? 40 : 64) // section header entry size - .D16(3) // section count - .D16(1) // section name string table - .Mark(&elf_header_size); - - // The null section. Every ELF file has one, as the first entry in - // the section header table. - ELFSectionHeader null_header(SHT_NULL); - null_header.file_offset = 0; - null_header.file_size = 0; - - // The CFI section. The whole reason for writing out this ELF file - // is to put this in it so that we can run other dumping programs on - // it to check its contents. - ELFSectionHeader cfi_header(SHT_PROGBITS); - cfi_header.file_size = cfi.Size(); - - // The section holding the names of the sections. This is the - // section whose index appears in the e_shstrndx member of the ELF - // header. - ELFSectionHeader section_names_header(SHT_STRTAB); - CFISection section_names(cfi.endianness(), cfi.AddressSize()); - section_names - .Mark(&null_header.name) - .AppendCString("") - .Mark(§ion_names_header.name) - .AppendCString(".shstrtab") - .Mark(&cfi_header.name) - .AppendCString(cfi_name) - .Mark(§ion_names_header.file_size); - - // Create the section table. The ELF header's e_shoff member refers - // to this, and the e_shnum member gives the number of entries it - // contains. - CFISection section_table(cfi.endianness(), cfi.AddressSize()); - AppendSectionHeader(§ion_table, null_header); - AppendSectionHeader(§ion_table, section_names_header); - AppendSectionHeader(§ion_table, cfi_header); - - // Append the section table and the section contents to the ELF file. - elf - .Mark(§ion_table_offset) - .Append(section_table) - .Mark(§ion_names_header.file_offset) - .Append(section_names) - .Mark(&cfi_header.file_offset) - .Append(cfi); - - string contents; - if (!elf.GetContents(&contents)) { - fprintf(stderr, "failed to get ELF file contents\n"); - exit(1); - } - - FILE *out = fopen(filename, "w"); - if (!out) { - fprintf(stderr, "error opening ELF file '%s': %s\n", - filename, strerror(errno)); - exit(1); - } - - if (fwrite(contents.data(), 1, contents.size(), out) != contents.size()) { - fprintf(stderr, "error writing ELF data to '%s': %s\n", - filename, strerror(errno)); - exit(1); - } - - if (fclose(out) == EOF) { - fprintf(stderr, "error closing ELF file '%s': %s\n", - filename, strerror(errno)); - exit(1); - } -} -#endif diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc deleted file mode 100644 index 71418eb8d..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc +++ /dev/null @@ -1,487 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf2reader_die_unittest.cc: Unit tests for dwarf2reader::CompilationUnit - -#include <stdint.h> -#include <stdlib.h> - -#include <iostream> -#include <string> -#include <vector> - -#include "breakpad_googletest_includes.h" -#include "common/dwarf/bytereader-inl.h" -#include "common/dwarf/dwarf2reader_test_common.h" -#include "common/dwarf/dwarf2reader.h" -#include "common/using_std_string.h" -#include "google_breakpad/common/breakpad_types.h" - -using google_breakpad::test_assembler::Endianness; -using google_breakpad::test_assembler::Label; -using google_breakpad::test_assembler::Section; -using google_breakpad::test_assembler::kBigEndian; -using google_breakpad::test_assembler::kLittleEndian; - -using dwarf2reader::ByteReader; -using dwarf2reader::CompilationUnit; -using dwarf2reader::Dwarf2Handler; -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfHasChild; -using dwarf2reader::DwarfTag; -using dwarf2reader::ENDIANNESS_BIG; -using dwarf2reader::ENDIANNESS_LITTLE; -using dwarf2reader::SectionMap; - -using std::vector; -using testing::InSequence; -using testing::Pointee; -using testing::Return; -using testing::Sequence; -using testing::Test; -using testing::TestWithParam; -using testing::_; - -class MockDwarf2Handler: public Dwarf2Handler { - public: - MOCK_METHOD5(StartCompilationUnit, bool(uint64 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version)); - MOCK_METHOD2(StartDIE, bool(uint64 offset, enum DwarfTag tag)); - MOCK_METHOD4(ProcessAttributeUnsigned, void(uint64 offset, - DwarfAttribute attr, - enum DwarfForm form, - uint64 data)); - MOCK_METHOD4(ProcessAttributeSigned, void(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data)); - MOCK_METHOD4(ProcessAttributeReference, void(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data)); - MOCK_METHOD5(ProcessAttributeBuffer, void(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const uint8_t *data, - uint64 len)); - MOCK_METHOD4(ProcessAttributeString, void(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const string& data)); - MOCK_METHOD4(ProcessAttributeSignature, void(uint64 offset, - DwarfAttribute attr, - enum DwarfForm form, - uint64 signature)); - MOCK_METHOD1(EndDIE, void(uint64 offset)); -}; - -struct DIEFixture { - - DIEFixture() { - // Fix the initial offset of the .debug_info and .debug_abbrev sections. - info.start() = 0; - abbrevs.start() = 0; - - // Default expectations for the data handler. - EXPECT_CALL(handler, StartCompilationUnit(_, _, _, _, _)).Times(0); - EXPECT_CALL(handler, StartDIE(_, _)).Times(0); - EXPECT_CALL(handler, ProcessAttributeUnsigned(_, _, _, _)).Times(0); - EXPECT_CALL(handler, ProcessAttributeSigned(_, _, _, _)).Times(0); - EXPECT_CALL(handler, ProcessAttributeReference(_, _, _, _)).Times(0); - EXPECT_CALL(handler, ProcessAttributeBuffer(_, _, _, _, _)).Times(0); - EXPECT_CALL(handler, ProcessAttributeString(_, _, _, _)).Times(0); - EXPECT_CALL(handler, EndDIE(_)).Times(0); - } - - // Return a reference to a section map whose .debug_info section refers - // to |info|, and whose .debug_abbrev section refers to |abbrevs|. This - // function returns a reference to the same SectionMap each time; new - // calls wipe out maps established by earlier calls. - const SectionMap &MakeSectionMap() { - // Copy the sections' contents into strings that will live as long as - // the map itself. - assert(info.GetContents(&info_contents)); - assert(abbrevs.GetContents(&abbrevs_contents)); - section_map.clear(); - section_map[".debug_info"].first - = reinterpret_cast<const uint8_t *>(info_contents.data()); - section_map[".debug_info"].second = info_contents.size(); - section_map[".debug_abbrev"].first - = reinterpret_cast<const uint8_t *>(abbrevs_contents.data()); - section_map[".debug_abbrev"].second = abbrevs_contents.size(); - return section_map; - } - - TestCompilationUnit info; - TestAbbrevTable abbrevs; - MockDwarf2Handler handler; - string abbrevs_contents, info_contents; - SectionMap section_map; -}; - -struct DwarfHeaderParams { - DwarfHeaderParams(Endianness endianness, size_t format_size, - int version, size_t address_size) - : endianness(endianness), format_size(format_size), - version(version), address_size(address_size) { } - Endianness endianness; - size_t format_size; // 4-byte or 8-byte DWARF offsets - int version; - size_t address_size; -}; - -class DwarfHeader: public DIEFixture, - public TestWithParam<DwarfHeaderParams> { }; - -TEST_P(DwarfHeader, Header) { - Label abbrev_table = abbrevs.Here(); - abbrevs.Abbrev(1, dwarf2reader::DW_TAG_compile_unit, - dwarf2reader::DW_children_yes) - .Attribute(dwarf2reader::DW_AT_name, dwarf2reader::DW_FORM_string) - .EndAbbrev() - .EndTable(); - - info.set_format_size(GetParam().format_size); - info.set_endianness(GetParam().endianness); - - info.Header(GetParam().version, abbrev_table, GetParam().address_size) - .ULEB128(1) // DW_TAG_compile_unit, with children - .AppendCString("sam") // DW_AT_name, DW_FORM_string - .D8(0); // end of children - info.Finish(); - - { - InSequence s; - EXPECT_CALL(handler, - StartCompilationUnit(0, GetParam().address_size, - GetParam().format_size, _, - GetParam().version)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit)) - .WillOnce(Return(true)); - EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_string, - "sam")) - .WillOnce(Return()); - EXPECT_CALL(handler, EndDIE(_)) - .WillOnce(Return()); - } - - ByteReader byte_reader(GetParam().endianness == kLittleEndian ? - ENDIANNESS_LITTLE : ENDIANNESS_BIG); - CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler); - EXPECT_EQ(parser.Start(), info_contents.size()); -} - -INSTANTIATE_TEST_CASE_P( - HeaderVariants, DwarfHeader, - ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), - DwarfHeaderParams(kLittleEndian, 4, 2, 8), - DwarfHeaderParams(kLittleEndian, 4, 3, 4), - DwarfHeaderParams(kLittleEndian, 4, 3, 8), - DwarfHeaderParams(kLittleEndian, 4, 4, 4), - DwarfHeaderParams(kLittleEndian, 4, 4, 8), - DwarfHeaderParams(kLittleEndian, 8, 2, 4), - DwarfHeaderParams(kLittleEndian, 8, 2, 8), - DwarfHeaderParams(kLittleEndian, 8, 3, 4), - DwarfHeaderParams(kLittleEndian, 8, 3, 8), - DwarfHeaderParams(kLittleEndian, 8, 4, 4), - DwarfHeaderParams(kLittleEndian, 8, 4, 8), - DwarfHeaderParams(kBigEndian, 4, 2, 4), - DwarfHeaderParams(kBigEndian, 4, 2, 8), - DwarfHeaderParams(kBigEndian, 4, 3, 4), - DwarfHeaderParams(kBigEndian, 4, 3, 8), - DwarfHeaderParams(kBigEndian, 4, 4, 4), - DwarfHeaderParams(kBigEndian, 4, 4, 8), - DwarfHeaderParams(kBigEndian, 8, 2, 4), - DwarfHeaderParams(kBigEndian, 8, 2, 8), - DwarfHeaderParams(kBigEndian, 8, 3, 4), - DwarfHeaderParams(kBigEndian, 8, 3, 8), - DwarfHeaderParams(kBigEndian, 8, 4, 4), - DwarfHeaderParams(kBigEndian, 8, 4, 8))); - -struct DwarfFormsFixture: public DIEFixture { - // Start a compilation unit, as directed by |params|, containing one - // childless DIE of the given tag, with one attribute of the given name - // and form. The 'info' fixture member is left just after the abbrev - // code, waiting for the attribute value to be appended. - void StartSingleAttributeDIE(const DwarfHeaderParams ¶ms, - DwarfTag tag, DwarfAttribute name, - DwarfForm form) { - // Create the abbreviation table. - Label abbrev_table = abbrevs.Here(); - abbrevs.Abbrev(1, tag, dwarf2reader::DW_children_no) - .Attribute(name, form) - .EndAbbrev() - .EndTable(); - - // Create the compilation unit, up to the attribute value. - info.set_format_size(params.format_size); - info.set_endianness(params.endianness); - info.Header(params.version, abbrev_table, params.address_size) - .ULEB128(1); // abbrev code - } - - // Set up handler to expect a compilation unit matching |params|, - // containing one childless DIE of the given tag, in the sequence s. Stop - // just before the expectations. - void ExpectBeginCompilationUnit(const DwarfHeaderParams ¶ms, - DwarfTag tag, uint64 offset=0) { - EXPECT_CALL(handler, - StartCompilationUnit(offset, params.address_size, - params.format_size, _, - params.version)) - .InSequence(s) - .WillOnce(Return(true)); - EXPECT_CALL(handler, StartDIE(_, tag)) - .InSequence(s) - .WillOnce(Return(true)); - } - - void ExpectEndCompilationUnit() { - EXPECT_CALL(handler, EndDIE(_)) - .InSequence(s) - .WillOnce(Return()); - } - - void ParseCompilationUnit(const DwarfHeaderParams ¶ms, uint64 offset=0) { - ByteReader byte_reader(params.endianness == kLittleEndian ? - ENDIANNESS_LITTLE : ENDIANNESS_BIG); - CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader, &handler); - EXPECT_EQ(offset + parser.Start(), info_contents.size()); - } - - // The sequence to which the fixture's methods append expectations. - Sequence s; -}; - -struct DwarfForms: public DwarfFormsFixture, - public TestWithParam<DwarfHeaderParams> { }; - -TEST_P(DwarfForms, addr) { - StartSingleAttributeDIE(GetParam(), dwarf2reader::DW_TAG_compile_unit, - dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr); - uint64_t value; - if (GetParam().address_size == 4) { - value = 0xc8e9ffcc; - info.D32(value); - } else { - value = 0xe942517fc2768564ULL; - info.D64(value); - } - info.Finish(); - - ExpectBeginCompilationUnit(GetParam(), dwarf2reader::DW_TAG_compile_unit); - EXPECT_CALL(handler, ProcessAttributeUnsigned(_, dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, - value)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -TEST_P(DwarfForms, block2_empty) { - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, - (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2); - info.D16(0); - info.Finish(); - - ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); - EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2, - _, 0)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -TEST_P(DwarfForms, block2) { - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7, - (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2); - unsigned char data[258]; - memset(data, '*', sizeof(data)); - info.D16(sizeof(data)) - .Append(data, sizeof(data)); - info.Finish(); - - ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7); - EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463, - dwarf2reader::DW_FORM_block2, - Pointee('*'), 258)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -TEST_P(DwarfForms, flag_present) { - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2, - (DwarfAttribute) 0x359d1972, - dwarf2reader::DW_FORM_flag_present); - // DW_FORM_flag_present occupies no space in the DIE. - info.Finish(); - - ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2); - EXPECT_CALL(handler, - ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972, - dwarf2reader::DW_FORM_flag_present, - 1)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -TEST_P(DwarfForms, sec_offset) { - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689, - (DwarfAttribute) 0xa060bfd1, - dwarf2reader::DW_FORM_sec_offset); - uint64_t value; - if (GetParam().format_size == 4) { - value = 0xacc9c388; - info.D32(value); - } else { - value = 0xcffe5696ffe3ed0aULL; - info.D64(value); - } - info.Finish(); - - ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689); - EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1, - dwarf2reader::DW_FORM_sec_offset, - value)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -TEST_P(DwarfForms, exprloc) { - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb, - (DwarfAttribute) 0xba3ae5cb, - dwarf2reader::DW_FORM_exprloc); - info.ULEB128(29) - .Append(29, 173); - info.Finish(); - - ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb); - EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb, - dwarf2reader::DW_FORM_exprloc, - Pointee(173), 29)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -TEST_P(DwarfForms, ref_sig8) { - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, - (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8); - info.D64(0xf72fa0cb6ddcf9d6ULL); - info.Finish(); - - ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b); - EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8, - 0xf72fa0cb6ddcf9d6ULL)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam()); -} - -// A value passed to ProcessAttributeSignature is just an absolute number, -// not an offset within the compilation unit as most of the other -// DW_FORM_ref forms are. Check that the reader doesn't try to apply any -// offset to the signature, by reading it from a compilation unit that does -// not start at the beginning of the section. -TEST_P(DwarfForms, ref_sig8_not_first) { - info.Append(98, '*'); - StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b, - (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8); - info.D64(0xf72fa0cb6ddcf9d6ULL); - info.Finish(); - - ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98); - EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908, - dwarf2reader::DW_FORM_ref_sig8, - 0xf72fa0cb6ddcf9d6ULL)) - .InSequence(s) - .WillOnce(Return()); - ExpectEndCompilationUnit(); - - ParseCompilationUnit(GetParam(), 98); -} - -// Tests for the other attribute forms could go here. - -INSTANTIATE_TEST_CASE_P( - HeaderVariants, DwarfForms, - ::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4), - DwarfHeaderParams(kLittleEndian, 4, 2, 8), - DwarfHeaderParams(kLittleEndian, 4, 3, 4), - DwarfHeaderParams(kLittleEndian, 4, 3, 8), - DwarfHeaderParams(kLittleEndian, 4, 4, 4), - DwarfHeaderParams(kLittleEndian, 4, 4, 8), - DwarfHeaderParams(kLittleEndian, 8, 2, 4), - DwarfHeaderParams(kLittleEndian, 8, 2, 8), - DwarfHeaderParams(kLittleEndian, 8, 3, 4), - DwarfHeaderParams(kLittleEndian, 8, 3, 8), - DwarfHeaderParams(kLittleEndian, 8, 4, 4), - DwarfHeaderParams(kLittleEndian, 8, 4, 8), - DwarfHeaderParams(kBigEndian, 4, 2, 4), - DwarfHeaderParams(kBigEndian, 4, 2, 8), - DwarfHeaderParams(kBigEndian, 4, 3, 4), - DwarfHeaderParams(kBigEndian, 4, 3, 8), - DwarfHeaderParams(kBigEndian, 4, 4, 4), - DwarfHeaderParams(kBigEndian, 4, 4, 8), - DwarfHeaderParams(kBigEndian, 8, 2, 4), - DwarfHeaderParams(kBigEndian, 8, 2, 8), - DwarfHeaderParams(kBigEndian, 8, 3, 4), - DwarfHeaderParams(kBigEndian, 8, 3, 8), - DwarfHeaderParams(kBigEndian, 8, 4, 4), - DwarfHeaderParams(kBigEndian, 8, 4, 8))); diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_test_common.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_test_common.h deleted file mode 100644 index e91de9061..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/dwarf2reader_test_common.h +++ /dev/null @@ -1,149 +0,0 @@ -// -*- mode: c++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf2reader_test_common.h: Define TestCompilationUnit and -// TestAbbrevTable, classes for creating properly (and improperly) -// formatted DWARF compilation unit data for unit tests. - -#ifndef COMMON_DWARF_DWARF2READER_TEST_COMMON_H__ -#define COMMON_DWARF_DWARF2READER_TEST_COMMON_H__ - -#include "common/test_assembler.h" -#include "common/dwarf/dwarf2enums.h" - -// A subclass of test_assembler::Section, specialized for constructing -// DWARF compilation units. -class TestCompilationUnit: public google_breakpad::test_assembler::Section { - public: - typedef dwarf2reader::DwarfTag DwarfTag; - typedef dwarf2reader::DwarfAttribute DwarfAttribute; - typedef dwarf2reader::DwarfForm DwarfForm; - typedef google_breakpad::test_assembler::Label Label; - - // Set the section's DWARF format size (the 32-bit DWARF format or the - // 64-bit DWARF format, for lengths and section offsets --- not the - // address size) to format_size. - void set_format_size(size_t format_size) { - assert(format_size == 4 || format_size == 8); - format_size_ = format_size; - } - - // Append a DWARF section offset value, of the appropriate size for this - // compilation unit. - template<typename T> - void SectionOffset(T offset) { - if (format_size_ == 4) - D32(offset); - else - D64(offset); - } - - // Append a DWARF compilation unit header to the section, with the given - // DWARF version, abbrev table offset, and address size. - TestCompilationUnit &Header(int version, const Label &abbrev_offset, - size_t address_size) { - if (format_size_ == 4) { - D32(length_); - } else { - D32(0xffffffff); - D64(length_); - } - post_length_offset_ = Size(); - D16(version); - SectionOffset(abbrev_offset); - D8(address_size); - return *this; - } - - // Mark the end of this header's DIEs. - TestCompilationUnit &Finish() { - length_ = Size() - post_length_offset_; - return *this; - } - - private: - // The DWARF format size for this compilation unit. - size_t format_size_; - - // The offset of the point in the compilation unit header immediately - // after the initial length field. - uint64_t post_length_offset_; - - // The length of the compilation unit, not including the initial length field. - Label length_; -}; - -// A subclass of test_assembler::Section specialized for constructing DWARF -// abbreviation tables. -class TestAbbrevTable: public google_breakpad::test_assembler::Section { - public: - typedef dwarf2reader::DwarfTag DwarfTag; - typedef dwarf2reader::DwarfAttribute DwarfAttribute; - typedef dwarf2reader::DwarfForm DwarfForm; - typedef dwarf2reader::DwarfHasChild DwarfHasChild; - typedef google_breakpad::test_assembler::Label Label; - - // Start a new abbreviation table entry for abbreviation code |code|, - // encoding a DIE whose tag is |tag|, and which has children if and only - // if |has_children| is true. - TestAbbrevTable &Abbrev(int code, DwarfTag tag, DwarfHasChild has_children) { - assert(code != 0); - ULEB128(code); - ULEB128(static_cast<unsigned>(tag)); - D8(static_cast<unsigned>(has_children)); - return *this; - }; - - // Add an attribute to the current abbreviation code whose name is |name| - // and whose form is |form|. - TestAbbrevTable &Attribute(DwarfAttribute name, DwarfForm form) { - ULEB128(static_cast<unsigned>(name)); - ULEB128(static_cast<unsigned>(form)); - return *this; - } - - // Finish the current abbreviation code. - TestAbbrevTable &EndAbbrev() { - ULEB128(0); - ULEB128(0); - return *this; - } - - // Finish the current abbreviation table. - TestAbbrevTable &EndTable() { - ULEB128(0); - return *this; - } -}; - -#endif // COMMON_DWARF_DWARF2READER_TEST_COMMON_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.cc deleted file mode 100644 index 4135a51a9..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.cc +++ /dev/null @@ -1,1273 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// Author: chatham@google.com (Andrew Chatham) -// Author: satorux@google.com (Satoru Takabayashi) -// -// Code for reading in ELF files. -// -// For information on the ELF format, see -// http://www.x86.org/ftp/manuals/tools/elf.pdf -// -// I also liked: -// http://www.caldera.com/developers/gabi/1998-04-29/contents.html -// -// A note about types: When dealing with the file format, we use types -// like Elf32_Word, but in the public interfaces we treat all -// addresses as uint64. As a result, we should be able to symbolize -// 64-bit binaries from a 32-bit process (which we don't do, -// anyway). size_t should therefore be avoided, except where required -// by things like mmap(). -// -// Although most of this code can deal with arbitrary ELF files of -// either word size, the public ElfReader interface only examines -// files loaded into the current address space, which must all match -// __WORDSIZE. This code cannot handle ELF files with a non-native -// byte ordering. -// -// TODO(chatham): It would be nice if we could accomplish this task -// without using malloc(), so we could use it as the process is dying. - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE // needed for pread() -#endif - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> - -#include <algorithm> -#include <map> -#include <string> -#include <vector> -// TODO(saugustine): Add support for compressed debug. -// Also need to add configure tests for zlib. -//#include "zlib.h" - -#include "third_party/musl/include/elf.h" -#include "elf_reader.h" -#include "common/using_std_string.h" - -// EM_AARCH64 is not defined by elf.h of GRTE v3 on x86. -// TODO(dougkwan): Remove this when v17 is retired. -#if !defined(EM_AARCH64) -#define EM_AARCH64 183 /* ARM AARCH64 */ -#endif - -// Map Linux macros to their Apple equivalents. -#if __APPLE__ -#ifndef __LITTLE_ENDIAN -#define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ -#endif // __LITTLE_ENDIAN -#ifndef __BIG_ENDIAN -#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ -#endif // __BIG_ENDIAN -#ifndef __BYTE_ORDER -#define __BYTE_ORDER __BYTE_ORDER__ -#endif // __BYTE_ORDER -#endif // __APPLE__ - -// TODO(dthomson): Can be removed once all Java code is using the Google3 -// launcher. We need to avoid processing PLT functions as it causes memory -// fragmentation in malloc, which is fixed in tcmalloc - and if the Google3 -// launcher is used the JVM will then use tcmalloc. b/13735638 -//DEFINE_bool(elfreader_process_dynsyms, true, -// "Activate PLT function processing"); - -using std::vector; - -namespace { - -// The lowest bit of an ARM symbol value is used to indicate a Thumb address. -const int kARMThumbBitOffset = 0; - -// Converts an ARM Thumb symbol value to a true aligned address value. -template <typename T> -T AdjustARMThumbSymbolValue(const T& symbol_table_value) { - return symbol_table_value & ~(1 << kARMThumbBitOffset); -} - -// Names of PLT-related sections. -const char kElfPLTRelSectionName[] = ".rel.plt"; // Use Rel struct. -const char kElfPLTRelaSectionName[] = ".rela.plt"; // Use Rela struct. -const char kElfPLTSectionName[] = ".plt"; -const char kElfDynSymSectionName[] = ".dynsym"; - -const int kX86PLTCodeSize = 0x10; // Size of one x86 PLT function in bytes. -const int kARMPLTCodeSize = 0xc; -const int kAARCH64PLTCodeSize = 0x10; - -const int kX86PLT0Size = 0x10; // Size of the special PLT0 entry. -const int kARMPLT0Size = 0x14; -const int kAARCH64PLT0Size = 0x20; - -// Suffix for PLT functions when it needs to be explicitly identified as such. -const char kPLTFunctionSuffix[] = "@plt"; - -} // namespace - -namespace dwarf2reader { - -template <class ElfArch> class ElfReaderImpl; - -// 32-bit and 64-bit ELF files are processed exactly the same, except -// for various field sizes. Elf32 and Elf64 encompass all of the -// differences between the two formats, and all format-specific code -// in this file is templated on one of them. -class Elf32 { - public: - typedef Elf32_Ehdr Ehdr; - typedef Elf32_Shdr Shdr; - typedef Elf32_Phdr Phdr; - typedef Elf32_Word Word; - typedef Elf32_Sym Sym; - typedef Elf32_Rel Rel; - typedef Elf32_Rela Rela; - - // What should be in the EI_CLASS header. - static const int kElfClass = ELFCLASS32; - - // Given a symbol pointer, return the binding type (eg STB_WEAK). - static char Bind(const Elf32_Sym *sym) { - return ELF32_ST_BIND(sym->st_info); - } - // Given a symbol pointer, return the symbol type (eg STT_FUNC). - static char Type(const Elf32_Sym *sym) { - return ELF32_ST_TYPE(sym->st_info); - } - - // Extract the symbol index from the r_info field of a relocation. - static int r_sym(const Elf32_Word r_info) { - return ELF32_R_SYM(r_info); - } -}; - - -class Elf64 { - public: - typedef Elf64_Ehdr Ehdr; - typedef Elf64_Shdr Shdr; - typedef Elf64_Phdr Phdr; - typedef Elf64_Word Word; - typedef Elf64_Sym Sym; - typedef Elf64_Rel Rel; - typedef Elf64_Rela Rela; - - // What should be in the EI_CLASS header. - static const int kElfClass = ELFCLASS64; - - static char Bind(const Elf64_Sym *sym) { - return ELF64_ST_BIND(sym->st_info); - } - static char Type(const Elf64_Sym *sym) { - return ELF64_ST_TYPE(sym->st_info); - } - static int r_sym(const Elf64_Xword r_info) { - return ELF64_R_SYM(r_info); - } -}; - - -// ElfSectionReader mmaps a section of an ELF file ("section" is ELF -// terminology). The ElfReaderImpl object providing the section header -// must exist for the lifetime of this object. -// -// The motivation for mmaping individual sections of the file is that -// many Google executables are large enough when unstripped that we -// have to worry about running out of virtual address space. -// -// For compressed sections we have no choice but to allocate memory. -template<class ElfArch> -class ElfSectionReader { - public: - ElfSectionReader(const char *name, const string &path, int fd, - const typename ElfArch::Shdr §ion_header) - : contents_aligned_(NULL), - contents_(NULL), - header_(section_header) { - // Back up to the beginning of the page we're interested in. - const size_t additional = header_.sh_offset % getpagesize(); - const size_t offset_aligned = header_.sh_offset - additional; - section_size_ = header_.sh_size; - size_aligned_ = section_size_ + additional; - // If the section has been stripped or is empty, do not attempt - // to process its contents. - if (header_.sh_type == SHT_NOBITS || header_.sh_size == 0) - return; - contents_aligned_ = mmap(NULL, size_aligned_, PROT_READ, MAP_SHARED, - fd, offset_aligned); - // Set where the offset really should begin. - contents_ = reinterpret_cast<char *>(contents_aligned_) + - (header_.sh_offset - offset_aligned); - - // Check for and handle any compressed contents. - //if (strncmp(name, ".zdebug_", strlen(".zdebug_")) == 0) - // DecompressZlibContents(); - // TODO(saugustine): Add support for proposed elf-section flag - // "SHF_COMPRESS". - } - - ~ElfSectionReader() { - if (contents_aligned_ != NULL) - munmap(contents_aligned_, size_aligned_); - else - delete[] contents_; - } - - // Return the section header for this section. - typename ElfArch::Shdr const &header() const { return header_; } - - // Return memory at the given offset within this section. - const char *GetOffset(typename ElfArch::Word bytes) const { - return contents_ + bytes; - } - - const char *contents() const { return contents_; } - size_t section_size() const { return section_size_; } - - private: - // page-aligned file contents - void *contents_aligned_; - // contents as usable by the client. For non-compressed sections, - // pointer within contents_aligned_ to where the section data - // begins; for compressed sections, pointer to the decompressed - // data. - char *contents_; - // size of contents_aligned_ - size_t size_aligned_; - // size of contents. - size_t section_size_; - const typename ElfArch::Shdr header_; -}; - -// An iterator over symbols in a given section. It handles walking -// through the entries in the specified section and mapping symbol -// entries to their names in the appropriate string table (in -// another section). -template<class ElfArch> -class SymbolIterator { - public: - SymbolIterator(ElfReaderImpl<ElfArch> *reader, - typename ElfArch::Word section_type) - : symbol_section_(reader->GetSectionByType(section_type)), - string_section_(NULL), - num_symbols_in_section_(0), - symbol_within_section_(0) { - - // If this section type doesn't exist, leave - // num_symbols_in_section_ as zero, so this iterator is already - // done(). - if (symbol_section_ != NULL) { - num_symbols_in_section_ = symbol_section_->header().sh_size / - symbol_section_->header().sh_entsize; - - // Symbol sections have sh_link set to the section number of - // the string section containing the symbol names. - string_section_ = reader->GetSection(symbol_section_->header().sh_link); - } - } - - // Return true iff we have passed all symbols in this section. - bool done() const { - return symbol_within_section_ >= num_symbols_in_section_; - } - - // Advance to the next symbol in this section. - // REQUIRES: !done() - void Next() { ++symbol_within_section_; } - - // Return a pointer to the current symbol. - // REQUIRES: !done() - const typename ElfArch::Sym *GetSymbol() const { - return reinterpret_cast<const typename ElfArch::Sym*>( - symbol_section_->GetOffset(symbol_within_section_ * - symbol_section_->header().sh_entsize)); - } - - // Return the name of the current symbol, NULL if it has none. - // REQUIRES: !done() - const char *GetSymbolName() const { - int name_offset = GetSymbol()->st_name; - if (name_offset == 0) - return NULL; - return string_section_->GetOffset(name_offset); - } - - int GetCurrentSymbolIndex() const { - return symbol_within_section_; - } - - private: - const ElfSectionReader<ElfArch> *const symbol_section_; - const ElfSectionReader<ElfArch> *string_section_; - int num_symbols_in_section_; - int symbol_within_section_; -}; - - -// Copied from strings/strutil.h. Per chatham, -// this library should not depend on strings. - -static inline bool MyHasSuffixString(const string& str, const string& suffix) { - int len = str.length(); - int suflen = suffix.length(); - return (suflen <= len) && (str.compare(len-suflen, suflen, suffix) == 0); -} - - -// ElfReader loads an ELF binary and can provide information about its -// contents. It is most useful for matching addresses to function -// names. It does not understand debugging formats (eg dwarf2), so it -// can't print line numbers. It takes a path to an elf file and a -// readable file descriptor for that file, which it does not assume -// ownership of. -template<class ElfArch> -class ElfReaderImpl { - public: - explicit ElfReaderImpl(const string &path, int fd) - : path_(path), - fd_(fd), - section_headers_(NULL), - program_headers_(NULL), - opd_section_(NULL), - base_for_text_(0), - plts_supported_(false), - plt_code_size_(0), - plt0_size_(0), - visited_relocation_entries_(false) { - string error; - is_dwp_ = MyHasSuffixString(path, ".dwp"); - ParseHeaders(fd, path); - // Currently we need some extra information for PowerPC64 binaries - // including a way to read the .opd section for function descriptors and a - // way to find the linked base for function symbols. - if (header_.e_machine == EM_PPC64) { - // "opd_section_" must always be checked for NULL before use. - opd_section_ = GetSectionInfoByName(".opd", &opd_info_); - for (unsigned int k = 0u; k < GetNumSections(); ++k) { - const char *name = GetSectionName(section_headers_[k].sh_name); - if (strncmp(name, ".text", strlen(".text")) == 0) { - base_for_text_ = - section_headers_[k].sh_addr - section_headers_[k].sh_offset; - break; - } - } - } - // Turn on PLTs. - if (header_.e_machine == EM_386 || header_.e_machine == EM_X86_64) { - plt_code_size_ = kX86PLTCodeSize; - plt0_size_ = kX86PLT0Size; - plts_supported_ = true; - } else if (header_.e_machine == EM_ARM) { - plt_code_size_ = kARMPLTCodeSize; - plt0_size_ = kARMPLT0Size; - plts_supported_ = true; - } else if (header_.e_machine == EM_AARCH64) { - plt_code_size_ = kAARCH64PLTCodeSize; - plt0_size_ = kAARCH64PLT0Size; - plts_supported_ = true; - } - } - - ~ElfReaderImpl() { - for (unsigned int i = 0u; i < sections_.size(); ++i) - delete sections_[i]; - delete [] section_headers_; - delete [] program_headers_; - } - - // Examine the headers of the file and return whether the file looks - // like an ELF file for this architecture. Takes an already-open - // file descriptor for the candidate file, reading in the prologue - // to see if the ELF file appears to match the current - // architecture. If error is non-NULL, it will be set with a reason - // in case of failure. - static bool IsArchElfFile(int fd, string *error) { - unsigned char header[EI_NIDENT]; - if (pread(fd, header, sizeof(header), 0) != sizeof(header)) { - if (error != NULL) *error = "Could not read header"; - return false; - } - - if (memcmp(header, ELFMAG, SELFMAG) != 0) { - if (error != NULL) *error = "Missing ELF magic"; - return false; - } - - if (header[EI_CLASS] != ElfArch::kElfClass) { - if (error != NULL) *error = "Different word size"; - return false; - } - - int endian = 0; - if (header[EI_DATA] == ELFDATA2LSB) - endian = __LITTLE_ENDIAN; - else if (header[EI_DATA] == ELFDATA2MSB) - endian = __BIG_ENDIAN; - if (endian != __BYTE_ORDER) { - if (error != NULL) *error = "Different byte order"; - return false; - } - - return true; - } - - // Return true if we can use this symbol in Address-to-Symbol map. - bool CanUseSymbol(const char *name, const typename ElfArch::Sym *sym) { - // For now we only save FUNC and NOTYPE symbols. For now we just - // care about functions, but some functions written in assembler - // don't have a proper ELF type attached to them, so we store - // NOTYPE symbols as well. The remaining significant type is - // OBJECT (eg global variables), which represent about 25% of - // the symbols in a typical google3 binary. - if (ElfArch::Type(sym) != STT_FUNC && - ElfArch::Type(sym) != STT_NOTYPE) { - return false; - } - - // Target specific filtering. - switch (header_.e_machine) { - case EM_AARCH64: - case EM_ARM: - // Filter out '$x' special local symbols used by tools - return name[0] != '$' || ElfArch::Bind(sym) != STB_LOCAL; - case EM_X86_64: - // Filter out read-only constants like .LC123. - return name[0] != '.' || ElfArch::Bind(sym) != STB_LOCAL; - default: - return true; - } - } - - // Iterate over the symbols in a section, either SHT_DYNSYM or - // SHT_SYMTAB. Add all symbols to the given SymbolMap. - /* - void GetSymbolPositions(SymbolMap *symbols, - typename ElfArch::Word section_type, - uint64 mem_offset, - uint64 file_offset) { - // This map is used to filter out "nested" functions. - // See comment below. - AddrToSymMap addr_to_sym_map; - for (SymbolIterator<ElfArch> it(this, section_type); - !it.done(); it.Next()) { - const char *name = it.GetSymbolName(); - if (name == NULL) - continue; - const typename ElfArch::Sym *sym = it.GetSymbol(); - if (CanUseSymbol(name, sym)) { - const int sec = sym->st_shndx; - - // We don't support special section indices. The most common - // is SHN_ABS, for absolute symbols used deep in the bowels of - // glibc. Also ignore any undefined symbols. - if (sec == SHN_UNDEF || - (sec >= SHN_LORESERVE && sec <= SHN_HIRESERVE)) { - continue; - } - - const typename ElfArch::Shdr& hdr = section_headers_[sec]; - - // Adjust for difference between where we expected to mmap - // this section, and where it was actually mmapped. - const int64 expected_base = hdr.sh_addr - hdr.sh_offset; - const int64 real_base = mem_offset - file_offset; - const int64 adjust = real_base - expected_base; - - uint64 start = sym->st_value + adjust; - - // Adjust function symbols for PowerPC64 by dereferencing and adjusting - // the function descriptor to get the function address. - if (header_.e_machine == EM_PPC64 && ElfArch::Type(sym) == STT_FUNC) { - const uint64 opd_addr = - AdjustPPC64FunctionDescriptorSymbolValue(sym->st_value); - // Only adjust the returned value if the function address was found. - if (opd_addr != sym->st_value) { - const int64 adjust_function_symbols = - real_base - base_for_text_; - start = opd_addr + adjust_function_symbols; - } - } - - addr_to_sym_map.push_back(std::make_pair(start, sym)); - } - } - std::sort(addr_to_sym_map.begin(), addr_to_sym_map.end(), &AddrToSymSorter); - addr_to_sym_map.erase(std::unique(addr_to_sym_map.begin(), - addr_to_sym_map.end(), &AddrToSymEquals), - addr_to_sym_map.end()); - - // Squeeze out any "nested functions". - // Nested functions are not allowed in C, but libc plays tricks. - // - // For example, here is disassembly of /lib64/tls/libc-2.3.5.so: - // 0x00000000000aa380 <read+0>: cmpl $0x0,0x2781b9(%rip) - // 0x00000000000aa387 <read+7>: jne 0xaa39b <read+27> - // 0x00000000000aa389 <__read_nocancel+0>: mov $0x0,%rax - // 0x00000000000aa390 <__read_nocancel+7>: syscall - // 0x00000000000aa392 <__read_nocancel+9>: cmp $0xfffffffffffff001,%rax - // 0x00000000000aa398 <__read_nocancel+15>: jae 0xaa3ef <read+111> - // 0x00000000000aa39a <__read_nocancel+17>: retq - // 0x00000000000aa39b <read+27>: sub $0x28,%rsp - // 0x00000000000aa39f <read+31>: mov %rdi,0x8(%rsp) - // ... - // Without removing __read_nocancel, symbolizer will return NULL - // given e.g. 0xaa39f (because the lower bound is __read_nocancel, - // but 0xaa39f is beyond its end. - if (addr_to_sym_map.empty()) { - return; - } - const ElfSectionReader<ElfArch> *const symbol_section = - this->GetSectionByType(section_type); - const ElfSectionReader<ElfArch> *const string_section = - this->GetSection(symbol_section->header().sh_link); - - typename AddrToSymMap::iterator curr = addr_to_sym_map.begin(); - // Always insert the first symbol. - symbols->AddSymbol(string_section->GetOffset(curr->second->st_name), - curr->first, curr->second->st_size); - typename AddrToSymMap::iterator prev = curr++; - for (; curr != addr_to_sym_map.end(); ++curr) { - const uint64 prev_addr = prev->first; - const uint64 curr_addr = curr->first; - const typename ElfArch::Sym *const prev_sym = prev->second; - const typename ElfArch::Sym *const curr_sym = curr->second; - if (prev_addr + prev_sym->st_size <= curr_addr || - // The next condition is true if two symbols overlap like this: - // - // Previous symbol |----------------------------| - // Current symbol |-------------------------------| - // - // These symbols are not found in google3 codebase, but in - // jdk1.6.0_01_gg1/jre/lib/i386/server/libjvm.so. - // - // 0619e040 00000046 t CardTableModRefBS::write_region_work() - // 0619e070 00000046 t CardTableModRefBS::write_ref_array_work() - // - // We allow overlapped symbols rather than ignore these. - // Due to the way SymbolMap::GetSymbolAtPosition() works, - // lookup for any address in [curr_addr, curr_addr + its size) - // (e.g. 0619e071) will produce the current symbol, - // which is the desired outcome. - prev_addr + prev_sym->st_size < curr_addr + curr_sym->st_size) { - const char *name = string_section->GetOffset(curr_sym->st_name); - symbols->AddSymbol(name, curr_addr, curr_sym->st_size); - prev = curr; - } else { - // Current symbol is "nested" inside previous one like this: - // - // Previous symbol |----------------------------| - // Current symbol |---------------------| - // - // This happens within glibc, e.g. __read_nocancel is nested - // "inside" __read. Ignore "inner" symbol. - //DCHECK_LE(curr_addr + curr_sym->st_size, - // prev_addr + prev_sym->st_size); - ; - } - } - } -*/ - - void VisitSymbols(typename ElfArch::Word section_type, - ElfReader::SymbolSink *sink) { - VisitSymbols(section_type, sink, -1, -1, false); - } - - void VisitSymbols(typename ElfArch::Word section_type, - ElfReader::SymbolSink *sink, - int symbol_binding, - int symbol_type, - bool get_raw_symbol_values) { - for (SymbolIterator<ElfArch> it(this, section_type); - !it.done(); it.Next()) { - const char *name = it.GetSymbolName(); - if (!name) continue; - const typename ElfArch::Sym *sym = it.GetSymbol(); - if ((symbol_binding < 0 || ElfArch::Bind(sym) == symbol_binding) && - (symbol_type < 0 || ElfArch::Type(sym) == symbol_type)) { - typename ElfArch::Sym symbol = *sym; - // Add a PLT symbol in addition to the main undefined symbol. - // Only do this for SHT_DYNSYM, because PLT symbols are dynamic. - int symbol_index = it.GetCurrentSymbolIndex(); - // TODO(dthomson): Can be removed once all Java code is using the - // Google3 launcher. - if (section_type == SHT_DYNSYM && - static_cast<unsigned int>(symbol_index) < symbols_plt_offsets_.size() && - symbols_plt_offsets_[symbol_index] != 0) { - string plt_name = string(name) + kPLTFunctionSuffix; - if (plt_function_names_[symbol_index].empty()) { - plt_function_names_[symbol_index] = plt_name; - } else if (plt_function_names_[symbol_index] != plt_name) { - ; - } - sink->AddSymbol(plt_function_names_[symbol_index].c_str(), - symbols_plt_offsets_[it.GetCurrentSymbolIndex()], - plt_code_size_); - } - if (!get_raw_symbol_values) - AdjustSymbolValue(&symbol); - sink->AddSymbol(name, symbol.st_value, symbol.st_size); - } - } - } - - void VisitRelocationEntries() { - if (visited_relocation_entries_) { - return; - } - visited_relocation_entries_ = true; - - if (!plts_supported_) { - return; - } - // First determine if PLTs exist. If not, then there is nothing to do. - ElfReader::SectionInfo plt_section_info; - const char* plt_section = - GetSectionInfoByName(kElfPLTSectionName, &plt_section_info); - if (!plt_section) { - return; - } - if (plt_section_info.size == 0) { - return; - } - - // The PLTs could be referenced by either a Rel or Rela (Rel with Addend) - // section. - ElfReader::SectionInfo rel_section_info; - ElfReader::SectionInfo rela_section_info; - const char* rel_section = - GetSectionInfoByName(kElfPLTRelSectionName, &rel_section_info); - const char* rela_section = - GetSectionInfoByName(kElfPLTRelaSectionName, &rela_section_info); - - const typename ElfArch::Rel* rel = - reinterpret_cast<const typename ElfArch::Rel*>(rel_section); - const typename ElfArch::Rela* rela = - reinterpret_cast<const typename ElfArch::Rela*>(rela_section); - - if (!rel_section && !rela_section) { - return; - } - - // Use either Rel or Rela section, depending on which one exists. - size_t section_size = rel_section ? rel_section_info.size - : rela_section_info.size; - size_t entry_size = rel_section ? sizeof(typename ElfArch::Rel) - : sizeof(typename ElfArch::Rela); - - // Determine the number of entries in the dynamic symbol table. - ElfReader::SectionInfo dynsym_section_info; - const char* dynsym_section = - GetSectionInfoByName(kElfDynSymSectionName, &dynsym_section_info); - // The dynsym section might not exist, or it might be empty. In either case - // there is nothing to be done so return. - if (!dynsym_section || dynsym_section_info.size == 0) { - return; - } - size_t num_dynamic_symbols = - dynsym_section_info.size / dynsym_section_info.entsize; - symbols_plt_offsets_.resize(num_dynamic_symbols, 0); - - // TODO(dthomson): Can be removed once all Java code is using the - // Google3 launcher. - // Make storage room for PLT function name strings. - plt_function_names_.resize(num_dynamic_symbols); - - for (size_t i = 0; i < section_size / entry_size; ++i) { - // Determine symbol index from the |r_info| field. - int sym_index = ElfArch::r_sym(rel_section ? rel[i].r_info - : rela[i].r_info); - if (static_cast<unsigned int>(sym_index) >= symbols_plt_offsets_.size()) { - continue; - } - symbols_plt_offsets_[sym_index] = - plt_section_info.addr + plt0_size_ + i * plt_code_size_; - } - } - - // Return an ElfSectionReader for the first section of the given - // type by iterating through all section headers. Returns NULL if - // the section type is not found. - const ElfSectionReader<ElfArch> *GetSectionByType( - typename ElfArch::Word section_type) { - for (unsigned int k = 0u; k < GetNumSections(); ++k) { - if (section_headers_[k].sh_type == section_type) { - return GetSection(k); - } - } - return NULL; - } - - // Return the name of section "shndx". Returns NULL if the section - // is not found. - const char *GetSectionNameByIndex(int shndx) { - return GetSectionName(section_headers_[shndx].sh_name); - } - - // Return a pointer to section "shndx", and store the size in - // "size". Returns NULL if the section is not found. - const char *GetSectionContentsByIndex(int shndx, size_t *size) { - const ElfSectionReader<ElfArch> *section = GetSection(shndx); - if (section != NULL) { - *size = section->section_size(); - return section->contents(); - } - return NULL; - } - - // Return a pointer to the first section of the given name by - // iterating through all section headers, and store the size in - // "size". Returns NULL if the section name is not found. - const char *GetSectionContentsByName(const string §ion_name, - size_t *size) { - for (unsigned int k = 0u; k < GetNumSections(); ++k) { - // When searching for sections in a .dwp file, the sections - // we're looking for will always be at the end of the section - // table, so reverse the direction of iteration. - int shndx = is_dwp_ ? GetNumSections() - k - 1 : k; - const char *name = GetSectionName(section_headers_[shndx].sh_name); - if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) { - const ElfSectionReader<ElfArch> *section = GetSection(shndx); - if (section == NULL) { - return NULL; - } else { - *size = section->section_size(); - return section->contents(); - } - } - } - return NULL; - } - - // This is like GetSectionContentsByName() but it returns a lot of extra - // information about the section. - const char *GetSectionInfoByName(const string §ion_name, - ElfReader::SectionInfo *info) { - for (unsigned int k = 0u; k < GetNumSections(); ++k) { - // When searching for sections in a .dwp file, the sections - // we're looking for will always be at the end of the section - // table, so reverse the direction of iteration. - int shndx = is_dwp_ ? GetNumSections() - k - 1 : k; - const char *name = GetSectionName(section_headers_[shndx].sh_name); - if (name != NULL && ElfReader::SectionNamesMatch(section_name, name)) { - const ElfSectionReader<ElfArch> *section = GetSection(shndx); - if (section == NULL) { - return NULL; - } else { - info->type = section->header().sh_type; - info->flags = section->header().sh_flags; - info->addr = section->header().sh_addr; - info->offset = section->header().sh_offset; - info->size = section->header().sh_size; - info->link = section->header().sh_link; - info->info = section->header().sh_info; - info->addralign = section->header().sh_addralign; - info->entsize = section->header().sh_entsize; - return section->contents(); - } - } - } - return NULL; - } - - // p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD - // segments are present. This is the address an ELF image was linked - // (by static linker) to be loaded at. Usually (but not always) 0 for - // shared libraries and position-independent executables. - uint64 VaddrOfFirstLoadSegment() const { - // Relocatable objects (of type ET_REL) do not have LOAD segments. - if (header_.e_type == ET_REL) { - return 0; - } - for (int i = 0; i < GetNumProgramHeaders(); ++i) { - if (program_headers_[i].p_type == PT_LOAD) { - return program_headers_[i].p_vaddr; - } - } - return 0; - } - - // According to the LSB ("ELF special sections"), sections with debug - // info are prefixed by ".debug". The names are not specified, but they - // look like ".debug_line", ".debug_info", etc. - bool HasDebugSections() { - // Debug sections are likely to be near the end, so reverse the - // direction of iteration. - for (int k = GetNumSections() - 1; k >= 0; --k) { - const char *name = GetSectionName(section_headers_[k].sh_name); - if (strncmp(name, ".debug", strlen(".debug")) == 0) return true; - if (strncmp(name, ".zdebug", strlen(".zdebug")) == 0) return true; - } - return false; - } - - bool IsDynamicSharedObject() const { - return header_.e_type == ET_DYN; - } - - // Return the number of sections. - uint64_t GetNumSections() const { - if (HasManySections()) - return first_section_header_.sh_size; - return header_.e_shnum; - } - - private: - typedef vector<pair<uint64, const typename ElfArch::Sym *> > AddrToSymMap; - - static bool AddrToSymSorter(const typename AddrToSymMap::value_type& lhs, - const typename AddrToSymMap::value_type& rhs) { - return lhs.first < rhs.first; - } - - static bool AddrToSymEquals(const typename AddrToSymMap::value_type& lhs, - const typename AddrToSymMap::value_type& rhs) { - return lhs.first == rhs.first; - } - - // Does this ELF file have too many sections to fit in the program header? - bool HasManySections() const { - return header_.e_shnum == SHN_UNDEF; - } - - // Return the number of program headers. - int GetNumProgramHeaders() const { - if (HasManySections() && header_.e_phnum == 0xffff && - first_section_header_.sh_info != 0) - return first_section_header_.sh_info; - return header_.e_phnum; - } - - // Return the index of the string table. - int GetStringTableIndex() const { - if (HasManySections()) { - if (header_.e_shstrndx == 0xffff) - return first_section_header_.sh_link; - else if (header_.e_shstrndx >= GetNumSections()) - return 0; - } - return header_.e_shstrndx; - } - - // Given an offset into the section header string table, return the - // section name. - const char *GetSectionName(typename ElfArch::Word sh_name) { - const ElfSectionReader<ElfArch> *shstrtab = - GetSection(GetStringTableIndex()); - if (shstrtab != NULL) { - return shstrtab->GetOffset(sh_name); - } - return NULL; - } - - // Return an ElfSectionReader for the given section. The reader will - // be freed when this object is destroyed. - const ElfSectionReader<ElfArch> *GetSection(int num) { - const char *name; - // Hard-coding the name for the section-name string table prevents - // infinite recursion. - if (num == GetStringTableIndex()) - name = ".shstrtab"; - else - name = GetSectionNameByIndex(num); - ElfSectionReader<ElfArch> *& reader = sections_[num]; - if (reader == NULL) - reader = new ElfSectionReader<ElfArch>(name, path_, fd_, - section_headers_[num]); - return reader; - } - - // Parse out the overall header information from the file and assert - // that it looks sane. This contains information like the magic - // number and target architecture. - bool ParseHeaders(int fd, const string &path) { - // Read in the global ELF header. - if (pread(fd, &header_, sizeof(header_), 0) != sizeof(header_)) { - return false; - } - - // Must be an executable, dynamic shared object or relocatable object - if (header_.e_type != ET_EXEC && - header_.e_type != ET_DYN && - header_.e_type != ET_REL) { - return false; - } - // Need a section header. - if (header_.e_shoff == 0) { - return false; - } - - if (header_.e_shnum == SHN_UNDEF) { - // The number of sections in the program header is only a 16-bit value. In - // the event of overflow (greater than SHN_LORESERVE sections), e_shnum - // will read SHN_UNDEF and the true number of section header table entries - // is found in the sh_size field of the first section header. - // See: http://www.sco.com/developers/gabi/2003-12-17/ch4.sheader.html - if (pread(fd, &first_section_header_, sizeof(first_section_header_), - header_.e_shoff) != sizeof(first_section_header_)) { - return false; - } - } - - // Dynamically allocate enough space to store the section headers - // and read them out of the file. - const int section_headers_size = - GetNumSections() * sizeof(*section_headers_); - section_headers_ = new typename ElfArch::Shdr[section_headers_size]; - if (pread(fd, section_headers_, section_headers_size, header_.e_shoff) != - section_headers_size) { - return false; - } - - // Dynamically allocate enough space to store the program headers - // and read them out of the file. - //const int program_headers_size = - // GetNumProgramHeaders() * sizeof(*program_headers_); - program_headers_ = new typename ElfArch::Phdr[GetNumProgramHeaders()]; - - // Presize the sections array for efficiency. - sections_.resize(GetNumSections(), NULL); - return true; - } - - // Given the "value" of a function descriptor return the address of the - // function (i.e. the dereferenced value). Otherwise return "value". - uint64 AdjustPPC64FunctionDescriptorSymbolValue(uint64 value) { - if (opd_section_ != NULL && - opd_info_.addr <= value && - value < opd_info_.addr + opd_info_.size) { - uint64 offset = value - opd_info_.addr; - return (*reinterpret_cast<const uint64*>(opd_section_ + offset)); - } - return value; - } - - void AdjustSymbolValue(typename ElfArch::Sym* sym) { - switch (header_.e_machine) { - case EM_ARM: - // For ARM architecture, if the LSB of the function symbol offset is set, - // it indicates a Thumb function. This bit should not be taken literally. - // Clear it. - if (ElfArch::Type(sym) == STT_FUNC) - sym->st_value = AdjustARMThumbSymbolValue(sym->st_value); - break; - case EM_386: - // No adjustment needed for Intel x86 architecture. However, explicitly - // define this case as we use it quite often. - break; - case EM_PPC64: - // PowerPC64 currently has function descriptors as part of the ABI. - // Function symbols need to be adjusted accordingly. - if (ElfArch::Type(sym) == STT_FUNC) - sym->st_value = AdjustPPC64FunctionDescriptorSymbolValue(sym->st_value); - break; - default: - break; - } - } - - friend class SymbolIterator<ElfArch>; - - // The file we're reading. - const string path_; - // Open file descriptor for path_. Not owned by this object. - const int fd_; - - // The global header of the ELF file. - typename ElfArch::Ehdr header_; - - // The header of the first section. This may be used to supplement the ELF - // file header. - typename ElfArch::Shdr first_section_header_; - - // Array of GetNumSections() section headers, allocated when we read - // in the global header. - typename ElfArch::Shdr *section_headers_; - - // Array of GetNumProgramHeaders() program headers, allocated when we read - // in the global header. - typename ElfArch::Phdr *program_headers_; - - // An array of pointers to ElfSectionReaders. Sections are - // mmaped as they're needed and not released until this object is - // destroyed. - vector<ElfSectionReader<ElfArch>*> sections_; - - // For PowerPC64 we need to keep track of function descriptors when looking up - // values for funtion symbols values. Function descriptors are kept in the - // .opd section and are dereferenced to find the function address. - ElfReader::SectionInfo opd_info_; - const char *opd_section_; // Must be checked for NULL before use. - int64 base_for_text_; - - // Read PLT-related sections for the current architecture. - bool plts_supported_; - // Code size of each PLT function for the current architecture. - size_t plt_code_size_; - // Size of the special first entry in the .plt section that calls the runtime - // loader resolution routine, and that all other entries jump to when doing - // lazy symbol binding. - size_t plt0_size_; - - // Maps a dynamic symbol index to a PLT offset. - // The vector entry index is the dynamic symbol index. - std::vector<uint64> symbols_plt_offsets_; - - // Container for PLT function name strings. These strings are passed by - // reference to SymbolSink::AddSymbol() so they need to be stored somewhere. - std::vector<string> plt_function_names_; - - bool visited_relocation_entries_; - - // True if this is a .dwp file. - bool is_dwp_; -}; - -ElfReader::ElfReader(const string &path) - : path_(path), fd_(-1), impl32_(NULL), impl64_(NULL) { - // linux 2.6.XX kernel can show deleted files like this: - // /var/run/nscd/dbYLJYaE (deleted) - // and the kernel-supplied vdso and vsyscall mappings like this: - // [vdso] - // [vsyscall] - if (MyHasSuffixString(path, " (deleted)")) - return; - if (path == "[vdso]") - return; - if (path == "[vsyscall]") - return; - - fd_ = open(path.c_str(), O_RDONLY); -} - -ElfReader::~ElfReader() { - if (fd_ != -1) - close(fd_); - if (impl32_ != NULL) - delete impl32_; - if (impl64_ != NULL) - delete impl64_; -} - - -// The only word-size specific part of this file is IsNativeElfFile(). -#if __WORDSIZE == 32 -#define NATIVE_ELF_ARCH Elf32 -#elif __WORDSIZE == 64 -#define NATIVE_ELF_ARCH Elf64 -#else -#error "Invalid word size" -#endif - -template <typename ElfArch> -static bool IsElfFile(const int fd, const string &path) { - if (fd < 0) - return false; - if (!ElfReaderImpl<ElfArch>::IsArchElfFile(fd, NULL)) { - // No error message here. IsElfFile gets called many times. - return false; - } - return true; -} - -bool ElfReader::IsNativeElfFile() const { - return IsElfFile<NATIVE_ELF_ARCH>(fd_, path_); -} - -bool ElfReader::IsElf32File() const { - return IsElfFile<Elf32>(fd_, path_); -} - -bool ElfReader::IsElf64File() const { - return IsElfFile<Elf64>(fd_, path_); -} - -/* -void ElfReader::AddSymbols(SymbolMap *symbols, - uint64 mem_offset, uint64 file_offset, - uint64 length) { - if (fd_ < 0) - return; - // TODO(chatham): Actually use the information about file offset and - // the length of the mapped section. On some machines the data - // section gets mapped as executable, and we'll end up reading the - // file twice and getting some of the offsets wrong. - if (IsElf32File()) { - GetImpl32()->GetSymbolPositions(symbols, SHT_SYMTAB, - mem_offset, file_offset); - GetImpl32()->GetSymbolPositions(symbols, SHT_DYNSYM, - mem_offset, file_offset); - } else if (IsElf64File()) { - GetImpl64()->GetSymbolPositions(symbols, SHT_SYMTAB, - mem_offset, file_offset); - GetImpl64()->GetSymbolPositions(symbols, SHT_DYNSYM, - mem_offset, file_offset); - } -} -*/ - -void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink) { - VisitSymbols(sink, -1, -1); -} - -void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink, - int symbol_binding, - int symbol_type) { - VisitSymbols(sink, symbol_binding, symbol_type, false); -} - -void ElfReader::VisitSymbols(ElfReader::SymbolSink *sink, - int symbol_binding, - int symbol_type, - bool get_raw_symbol_values) { - if (IsElf32File()) { - GetImpl32()->VisitRelocationEntries(); - GetImpl32()->VisitSymbols(SHT_SYMTAB, sink, symbol_binding, symbol_type, - get_raw_symbol_values); - GetImpl32()->VisitSymbols(SHT_DYNSYM, sink, symbol_binding, symbol_type, - get_raw_symbol_values); - } else if (IsElf64File()) { - GetImpl64()->VisitRelocationEntries(); - GetImpl64()->VisitSymbols(SHT_SYMTAB, sink, symbol_binding, symbol_type, - get_raw_symbol_values); - GetImpl64()->VisitSymbols(SHT_DYNSYM, sink, symbol_binding, symbol_type, - get_raw_symbol_values); - } -} - -uint64 ElfReader::VaddrOfFirstLoadSegment() { - if (IsElf32File()) { - return GetImpl32()->VaddrOfFirstLoadSegment(); - } else if (IsElf64File()) { - return GetImpl64()->VaddrOfFirstLoadSegment(); - } else { - return 0; - } -} - -const char *ElfReader::GetSectionName(int shndx) { - if (shndx < 0 || static_cast<unsigned int>(shndx) >= GetNumSections()) return NULL; - if (IsElf32File()) { - return GetImpl32()->GetSectionNameByIndex(shndx); - } else if (IsElf64File()) { - return GetImpl64()->GetSectionNameByIndex(shndx); - } else { - return NULL; - } -} - -uint64 ElfReader::GetNumSections() { - if (IsElf32File()) { - return GetImpl32()->GetNumSections(); - } else if (IsElf64File()) { - return GetImpl64()->GetNumSections(); - } else { - return 0; - } -} - -const char *ElfReader::GetSectionByIndex(int shndx, size_t *size) { - if (IsElf32File()) { - return GetImpl32()->GetSectionContentsByIndex(shndx, size); - } else if (IsElf64File()) { - return GetImpl64()->GetSectionContentsByIndex(shndx, size); - } else { - return NULL; - } -} - -const char *ElfReader::GetSectionByName(const string §ion_name, - size_t *size) { - if (IsElf32File()) { - return GetImpl32()->GetSectionContentsByName(section_name, size); - } else if (IsElf64File()) { - return GetImpl64()->GetSectionContentsByName(section_name, size); - } else { - return NULL; - } -} - -const char *ElfReader::GetSectionInfoByName(const string §ion_name, - SectionInfo *info) { - if (IsElf32File()) { - return GetImpl32()->GetSectionInfoByName(section_name, info); - } else if (IsElf64File()) { - return GetImpl64()->GetSectionInfoByName(section_name, info); - } else { - return NULL; - } -} - -bool ElfReader::SectionNamesMatch(const string &name, const string &sh_name) { - if ((name.find(".debug_", 0) == 0) && (sh_name.find(".zdebug_", 0) == 0)) { - const string name_suffix(name, strlen(".debug_")); - const string sh_name_suffix(sh_name, strlen(".zdebug_")); - return name_suffix == sh_name_suffix; - } - return name == sh_name; -} - -bool ElfReader::IsDynamicSharedObject() { - if (IsElf32File()) { - return GetImpl32()->IsDynamicSharedObject(); - } else if (IsElf64File()) { - return GetImpl64()->IsDynamicSharedObject(); - } else { - return false; - } -} - -ElfReaderImpl<Elf32> *ElfReader::GetImpl32() { - if (impl32_ == NULL) { - impl32_ = new ElfReaderImpl<Elf32>(path_, fd_); - } - return impl32_; -} - -ElfReaderImpl<Elf64> *ElfReader::GetImpl64() { - if (impl64_ == NULL) { - impl64_ = new ElfReaderImpl<Elf64>(path_, fd_); - } - return impl64_; -} - -// Return true if file is an ELF binary of ElfArch, with unstripped -// debug info (debug_only=true) or symbol table (debug_only=false). -// Otherwise, return false. -template <typename ElfArch> -static bool IsNonStrippedELFBinaryImpl(const string &path, const int fd, - bool debug_only) { - if (!ElfReaderImpl<ElfArch>::IsArchElfFile(fd, NULL)) return false; - ElfReaderImpl<ElfArch> elf_reader(path, fd); - return debug_only ? - elf_reader.HasDebugSections() - : (elf_reader.GetSectionByType(SHT_SYMTAB) != NULL); -} - -// Helper for the IsNon[Debug]StrippedELFBinary functions. -static bool IsNonStrippedELFBinaryHelper(const string &path, - bool debug_only) { - const int fd = open(path.c_str(), O_RDONLY); - if (fd == -1) { - return false; - } - - if (IsNonStrippedELFBinaryImpl<Elf32>(path, fd, debug_only) || - IsNonStrippedELFBinaryImpl<Elf64>(path, fd, debug_only)) { - close(fd); - return true; - } - close(fd); - return false; -} - -bool ElfReader::IsNonStrippedELFBinary(const string &path) { - return IsNonStrippedELFBinaryHelper(path, false); -} - -bool ElfReader::IsNonDebugStrippedELFBinary(const string &path) { - return IsNonStrippedELFBinaryHelper(path, true); -} -} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.h deleted file mode 100644 index 07477341f..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/elf_reader.h +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2005 Google Inc. All Rights Reserved. -// Author: chatham@google.com (Andrew Chatham) -// Author: satorux@google.com (Satoru Takabayashi) -// -// ElfReader handles reading in ELF. It can extract symbols from the -// current process, which may be used to symbolize stack traces -// without having to make a potentially dangerous call to fork(). -// -// ElfReader dynamically allocates memory, so it is not appropriate to -// use once the address space might be corrupted, such as during -// process death. -// -// ElfReader supports both 32-bit and 64-bit ELF binaries. - -#ifndef COMMON_DWARF_ELF_READER_H__ -#define COMMON_DWARF_ELF_READER_H__ - -#include <string> -#include <vector> - -#include "common/dwarf/types.h" - -using std::string; -using std::vector; -using std::pair; - -namespace dwarf2reader { - -class SymbolMap; -class Elf32; -class Elf64; -template<typename ElfArch> -class ElfReaderImpl; - -class ElfReader { - public: - explicit ElfReader(const string &path); - ~ElfReader(); - - // Parse the ELF prologue of this file and return whether it was - // successfully parsed and matches the word size and byte order of - // the current process. - bool IsNativeElfFile() const; - - // Similar to IsNativeElfFile but checks if it's a 32-bit ELF file. - bool IsElf32File() const; - - // Similar to IsNativeElfFile but checks if it's a 64-bit ELF file. - bool IsElf64File() const; - - // Checks if it's an ELF file of type ET_DYN (shared object file). - bool IsDynamicSharedObject(); - - // Add symbols in the given ELF file into the provided SymbolMap, - // assuming that the file has been loaded into the specified - // offset. - // - // The remaining arguments are typically taken from a - // ProcMapsIterator (base/sysinfo.h) and describe which portions of - // the ELF file are mapped into which parts of memory: - // - // mem_offset - position at which the segment is mapped into memory - // file_offset - offset in the file where the mapping begins - // length - length of the mapped segment - void AddSymbols(SymbolMap *symbols, - uint64 mem_offset, uint64 file_offset, - uint64 length); - - class SymbolSink { - public: - virtual ~SymbolSink() {} - virtual void AddSymbol(const char *name, uint64 address, uint64 size) = 0; - }; - - // Like AddSymbols above, but with no address correction. - // Processes any SHT_SYMTAB section, followed by any SHT_DYNSYM section. - void VisitSymbols(SymbolSink *sink); - - // Like VisitSymbols above, but for a specific symbol binding/type. - // A negative value for the binding and type parameters means any - // binding or type. - void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type); - - // Like VisitSymbols above but can optionally export raw symbol values instead - // of adjusted ones. - void VisitSymbols(SymbolSink *sink, int symbol_binding, int symbol_type, - bool get_raw_symbol_values); - - // p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD - // segments are present. This is the address an ELF image was linked - // (by static linker) to be loaded at. Usually (but not always) 0 for - // shared libraries and position-independent executables. - uint64 VaddrOfFirstLoadSegment(); - - // Return the name of section "shndx". Returns NULL if the section - // is not found. - const char *GetSectionName(int shndx); - - // Return the number of sections in the given ELF file. - uint64 GetNumSections(); - - // Get section "shndx" from the given ELF file. On success, return - // the pointer to the section and store the size in "size". - // On error, return NULL. The returned section data is only valid - // until the ElfReader gets destroyed. - const char *GetSectionByIndex(int shndx, size_t *size); - - // Get section with "section_name" (ex. ".text", ".symtab") in the - // given ELF file. On success, return the pointer to the section - // and store the size in "size". On error, return NULL. The - // returned section data is only valid until the ElfReader gets - // destroyed. - const char *GetSectionByName(const string §ion_name, size_t *size); - - // This is like GetSectionByName() but it returns a lot of extra information - // about the section. The SectionInfo structure is almost identical to - // the typedef struct Elf64_Shdr defined in <elf.h>, but is redefined - // here so that the many short macro names in <elf.h> don't have to be - // added to our already cluttered namespace. - struct SectionInfo { - uint32 type; // Section type (SHT_xxx constant from elf.h). - uint64 flags; // Section flags (SHF_xxx constants from elf.h). - uint64 addr; // Section virtual address at execution. - uint64 offset; // Section file offset. - uint64 size; // Section size in bytes. - uint32 link; // Link to another section. - uint32 info; // Additional section information. - uint64 addralign; // Section alignment. - uint64 entsize; // Entry size if section holds a table. - }; - const char *GetSectionInfoByName(const string §ion_name, - SectionInfo *info); - - // Check if "path" is an ELF binary that has not been stripped of symbol - // tables. This function supports both 32-bit and 64-bit ELF binaries. - static bool IsNonStrippedELFBinary(const string &path); - - // Check if "path" is an ELF binary that has not been stripped of debug - // info. Unlike IsNonStrippedELFBinary, this function will return - // false for binaries passed through "strip -S". - static bool IsNonDebugStrippedELFBinary(const string &path); - - // Match a requested section name with the section name as it - // appears in the elf-file, adjusting for compressed debug section - // names. For example, returns true if name == ".debug_abbrev" and - // sh_name == ".zdebug_abbrev" - static bool SectionNamesMatch(const string &name, const string &sh_name); - - private: - // Lazily initialize impl32_ and return it. - ElfReaderImpl<Elf32> *GetImpl32(); - // Ditto for impl64_. - ElfReaderImpl<Elf64> *GetImpl64(); - - // Path of the file we're reading. - const string path_; - // Read-only file descriptor for the file. May be -1 if there was an - // error during open. - int fd_; - ElfReaderImpl<Elf32> *impl32_; - ElfReaderImpl<Elf64> *impl64_; -}; - -} // namespace dwarf2reader - -#endif // COMMON_DWARF_ELF_READER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.cc deleted file mode 100644 index 55a255eda..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.cc +++ /dev/null @@ -1,231 +0,0 @@ -// 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. - -// This is a client for the dwarf2reader to extract function and line -// information from the debug info. - -#include <assert.h> -#include <limits.h> -#include <stdio.h> - -#include <map> -#include <queue> -#include <vector> - -#include "common/dwarf/functioninfo.h" -#include "common/dwarf/bytereader.h" -#include "common/scoped_ptr.h" -#include "common/using_std_string.h" - -using google_breakpad::scoped_ptr; - -namespace dwarf2reader { - -CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files, - std::vector<string>* dirs, - LineMap* linemap):linemap_(linemap), - files_(files), - dirs_(dirs) { - // The dirs and files are 1 indexed, so just make sure we put - // nothing in the 0 vector. - assert(dirs->size() == 0); - assert(files->size() == 0); - dirs->push_back(""); - SourceFileInfo s; - s.name = ""; - s.lowpc = ULLONG_MAX; - files->push_back(s); -} - -void CULineInfoHandler::DefineDir(const string& name, uint32 dir_num) { - // These should never come out of order, actually - assert(dir_num == dirs_->size()); - dirs_->push_back(name); -} - -void CULineInfoHandler::DefineFile(const string& name, - int32 file_num, uint32 dir_num, - uint64 mod_time, uint64 length) { - assert(dir_num >= 0); - assert(dir_num < dirs_->size()); - - // These should never come out of order, actually. - if (file_num == (int32)files_->size() || file_num == -1) { - string dir = dirs_->at(dir_num); - - SourceFileInfo s; - s.lowpc = ULLONG_MAX; - - if (dir == "") { - s.name = name; - } else { - s.name = dir + "/" + name; - } - - files_->push_back(s); - } else { - fprintf(stderr, "error in DefineFile"); - } -} - -void CULineInfoHandler::AddLine(uint64 address, uint64 length, uint32 file_num, - uint32 line_num, uint32 column_num) { - if (file_num < files_->size()) { - linemap_->insert( - std::make_pair(address, - std::make_pair(files_->at(file_num).name.c_str(), - line_num))); - - if (address < files_->at(file_num).lowpc) { - files_->at(file_num).lowpc = address; - } - } else { - fprintf(stderr, "error in AddLine"); - } -} - -bool CUFunctionInfoHandler::StartCompilationUnit(uint64 offset, - uint8 address_size, - uint8 offset_size, - uint64 cu_length, - uint8 dwarf_version) { - current_compilation_unit_offset_ = offset; - return true; -} - - -// For function info, we only care about subprograms and inlined -// subroutines. For line info, the DW_AT_stmt_list lives in the -// compile unit tag. - -bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag) { - switch (tag) { - case DW_TAG_subprogram: - case DW_TAG_inlined_subroutine: { - current_function_info_ = new FunctionInfo; - current_function_info_->lowpc = current_function_info_->highpc = 0; - current_function_info_->name = ""; - current_function_info_->line = 0; - current_function_info_->file = ""; - offset_to_funcinfo_->insert(std::make_pair(offset, - current_function_info_)); - }; - // FALLTHROUGH - case DW_TAG_compile_unit: - return true; - default: - return false; - } - return false; -} - -// Only care about the name attribute for functions - -void CUFunctionInfoHandler::ProcessAttributeString(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const string &data) { - if (current_function_info_) { - if (attr == DW_AT_name) - current_function_info_->name = data; - else if (attr == DW_AT_MIPS_linkage_name) - current_function_info_->mangled_name = data; - } -} - -void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - if (attr == DW_AT_stmt_list) { - SectionMap::const_iterator iter = sections_.find("__debug_line"); - assert(iter != sections_.end()); - - scoped_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data, - iter->second.second - data, - reader_, linehandler_)); - lireader->Start(); - } else if (current_function_info_) { - switch (attr) { - case DW_AT_low_pc: - current_function_info_->lowpc = data; - break; - case DW_AT_high_pc: - current_function_info_->highpc = data; - break; - case DW_AT_decl_line: - current_function_info_->line = data; - break; - case DW_AT_decl_file: - current_function_info_->file = files_->at(data).name; - break; - default: - break; - } - } -} - -void CUFunctionInfoHandler::ProcessAttributeReference(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - if (current_function_info_) { - switch (attr) { - case DW_AT_specification: { - // Some functions have a "specification" attribute - // which means they were defined elsewhere. The name - // attribute is not repeated, and must be taken from - // the specification DIE. Here we'll assume that - // any DIE referenced in this manner will already have - // been seen, but that's not really required by the spec. - FunctionMap::iterator iter = offset_to_funcinfo_->find(data); - if (iter != offset_to_funcinfo_->end()) { - current_function_info_->name = iter->second->name; - current_function_info_->mangled_name = iter->second->mangled_name; - } else { - // If you hit this, this code probably needs to be rewritten. - fprintf(stderr, - "Error: DW_AT_specification was seen before the referenced " - "DIE! (Looking for DIE at offset %08llx, in DIE at " - "offset %08llx)\n", data, offset); - } - break; - } - default: - break; - } - } -} - -void CUFunctionInfoHandler::EndDIE(uint64 offset) { - if (current_function_info_ && current_function_info_->lowpc) - address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc, - current_function_info_)); -} - -} // namespace dwarf2reader diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.h deleted file mode 100644 index 0b08a5fc5..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/functioninfo.h +++ /dev/null @@ -1,188 +0,0 @@ -// 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. - - -// This file contains the definitions for a DWARF2/3 information -// collector that uses the DWARF2/3 reader interface to build a mapping -// of addresses to files, lines, and functions. - -#ifndef COMMON_DWARF_FUNCTIONINFO_H__ -#define COMMON_DWARF_FUNCTIONINFO_H__ - -#include <map> -#include <string> -#include <utility> -#include <vector> - -#include "common/dwarf/dwarf2reader.h" -#include "common/using_std_string.h" - - -namespace dwarf2reader { - -struct FunctionInfo { - // Name of the function - string name; - // Mangled name of the function - string mangled_name; - // File containing this function - string file; - // Line number for start of function. - uint32 line; - // Beginning address for this function - uint64 lowpc; - // End address for this function. - uint64 highpc; -}; - -struct SourceFileInfo { - // Name of the source file name - string name; - // Low address of source file name - uint64 lowpc; -}; - -typedef std::map<uint64, FunctionInfo*> FunctionMap; -typedef std::map<uint64, std::pair<string, uint32> > LineMap; - -// This class is a basic line info handler that fills in the dirs, -// file, and linemap passed into it with the data produced from the -// LineInfoHandler. -class CULineInfoHandler: public LineInfoHandler { - public: - - // - CULineInfoHandler(std::vector<SourceFileInfo>* files, - std::vector<string>* dirs, - LineMap* linemap); - virtual ~CULineInfoHandler() { } - - // Called when we define a directory. We just place NAME into dirs_ - // at position DIR_NUM. - virtual void DefineDir(const string& name, uint32 dir_num); - - // Called when we define a filename. We just place - // concat(dirs_[DIR_NUM], NAME) into files_ at position FILE_NUM. - virtual void DefineFile(const string& name, int32 file_num, - uint32 dir_num, uint64 mod_time, uint64 length); - - - // Called when the line info reader has a new line, address pair - // ready for us. ADDRESS is the address of the code, LENGTH is the - // length of its machine code in bytes, FILE_NUM is the file number - // containing the code, LINE_NUM is the line number in that file for - // the code, and COLUMN_NUM is the column number the code starts at, - // if we know it (0 otherwise). - virtual void AddLine(uint64 address, uint64 length, - uint32 file_num, uint32 line_num, uint32 column_num); - - private: - LineMap* linemap_; - std::vector<SourceFileInfo>* files_; - std::vector<string>* dirs_; -}; - -class CUFunctionInfoHandler: public Dwarf2Handler { - public: - CUFunctionInfoHandler(std::vector<SourceFileInfo>* files, - std::vector<string>* dirs, - LineMap* linemap, - FunctionMap* offset_to_funcinfo, - FunctionMap* address_to_funcinfo, - CULineInfoHandler* linehandler, - const SectionMap& sections, - ByteReader* reader) - : files_(files), dirs_(dirs), linemap_(linemap), - offset_to_funcinfo_(offset_to_funcinfo), - address_to_funcinfo_(address_to_funcinfo), - linehandler_(linehandler), sections_(sections), - reader_(reader), current_function_info_(NULL) { } - - virtual ~CUFunctionInfoHandler() { } - - // Start to process a compilation unit at OFFSET from the beginning of the - // .debug_info section. We want to see all compilation units, so we - // always return true. - - virtual bool StartCompilationUnit(uint64 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version); - - // Start to process a DIE at OFFSET from the beginning of the - // .debug_info section. We only care about function related DIE's. - virtual bool StartDIE(uint64 offset, enum DwarfTag tag); - - // Called when we have an attribute with unsigned data to give to - // our handler. The attribute is for the DIE at OFFSET from the - // beginning of the .debug_info section, has a name of ATTR, a form of - // FORM, and the actual data of the attribute is in DATA. - virtual void ProcessAttributeUnsigned(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - - // Called when we have an attribute with a DIE reference to give to - // our handler. The attribute is for the DIE at OFFSET from the - // beginning of the .debug_info section, has a name of ATTR, a form of - // FORM, and the offset of the referenced DIE from the start of the - // .debug_info section is in DATA. - virtual void ProcessAttributeReference(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - - // Called when we have an attribute with string data to give to - // our handler. The attribute is for the DIE at OFFSET from the - // beginning of the .debug_info section, has a name of ATTR, a form of - // FORM, and the actual data of the attribute is in DATA. - virtual void ProcessAttributeString(uint64 offset, - enum DwarfAttribute attr, - enum DwarfForm form, - const string& data); - - // Called when finished processing the DIE at OFFSET. - // Because DWARF2/3 specifies a tree of DIEs, you may get starts - // before ends of the previous DIE, as we process children before - // ending the parent. - virtual void EndDIE(uint64 offset); - - private: - std::vector<SourceFileInfo>* files_; - std::vector<string>* dirs_; - LineMap* linemap_; - FunctionMap* offset_to_funcinfo_; - FunctionMap* address_to_funcinfo_; - CULineInfoHandler* linehandler_; - const SectionMap& sections_; - ByteReader* reader_; - FunctionInfo* current_function_info_; - uint64 current_compilation_unit_offset_; -}; - -} // namespace dwarf2reader -#endif // COMMON_DWARF_FUNCTIONINFO_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/line_state_machine.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/line_state_machine.h deleted file mode 100644 index 0ff72abcf..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/line_state_machine.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2008 Google Inc. All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -#ifndef COMMON_DWARF_LINE_STATE_MACHINE_H__ -#define COMMON_DWARF_LINE_STATE_MACHINE_H__ - -namespace dwarf2reader { - -// This is the format of a DWARF2/3 line state machine that we process -// opcodes using. There is no need for anything outside the lineinfo -// processor to know how this works. -struct LineStateMachine { - void Reset(bool default_is_stmt) { - file_num = 1; - address = 0; - line_num = 1; - column_num = 0; - is_stmt = default_is_stmt; - basic_block = false; - end_sequence = false; - } - - uint32 file_num; - uint64 address; - uint32 line_num; - uint32 column_num; - bool is_stmt; // stmt means statement. - bool basic_block; - bool end_sequence; -}; - -} // namespace dwarf2reader - - -#endif // COMMON_DWARF_LINE_STATE_MACHINE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/moz.build b/toolkit/crashreporter/google-breakpad/src/common/dwarf/moz.build deleted file mode 100644 index e1ccc65ac..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/moz.build +++ /dev/null @@ -1,35 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -HostLibrary('host_breakpad_dwarf_s') -HOST_SOURCES += [ - 'bytereader.cc', - 'dwarf2diehandler.cc', - 'dwarf2reader.cc', - 'elf_reader.cc', - 'functioninfo.cc', -] -HOST_CXXFLAGS += [ - '-O2', - '-g', -] - -# need static lib -FORCE_STATIC_LIB = True - -# This code is only compiled for build-time tools, -# so enabling RTTI should be fine. -HOST_CXXFLAGS += [ - '-frtti', - '-funsigned-char', -] - -if CONFIG['OS_ARCH'] == 'Darwin': - HOST_CXXFLAGS += [ - '-stdlib=libc++', - ] - -include('/toolkit/crashreporter/crashreporter.mozbuild') diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf/types.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf/types.h deleted file mode 100644 index 59dda3160..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf/types.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2008 Google, Inc. All Rights reserved -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -// This file contains some typedefs for basic types - - -#ifndef _COMMON_DWARF_TYPES_H__ -#define _COMMON_DWARF_TYPES_H__ - -#include <stdint.h> - -typedef signed char int8; -typedef short int16; -typedef int int32; -typedef long long int64; - -typedef unsigned char uint8; -typedef unsigned short uint16; -typedef unsigned int uint32; -typedef unsigned long long uint64; - -typedef intptr_t intptr; -typedef uintptr_t uintptr; - -#endif // _COMMON_DWARF_TYPES_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.cc deleted file mode 100644 index 1bf1d96d5..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.cc +++ /dev/null @@ -1,295 +0,0 @@ -// -*- mode: c++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// Implementation of google_breakpad::DwarfCFIToModule. -// See dwarf_cfi_to_module.h for details. - -#include <sstream> - -#include "common/dwarf_cfi_to_module.h" - -namespace google_breakpad { - -using std::ostringstream; - -vector<string> DwarfCFIToModule::RegisterNames::MakeVector( - const char * const *strings, - size_t size) { - vector<string> names(strings, strings + size); - return names; -} - -vector<string> DwarfCFIToModule::RegisterNames::I386() { - static const char *const names[] = { - "$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi", - "$eip", "$eflags", "$unused1", - "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", - "$unused2", "$unused3", - "$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", - "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", - "$fcw", "$fsw", "$mxcsr", - "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5", - "$tr", "$ldtr" - }; - - return MakeVector(names, sizeof(names) / sizeof(names[0])); -} - -vector<string> DwarfCFIToModule::RegisterNames::X86_64() { - static const char *const names[] = { - "$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp", - "$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15", - "$rip", - "$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7", - "$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15", - "$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7", - "$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7", - "$rflags", - "$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2", - "$fs.base", "$gs.base", "$unused3", "$unused4", - "$tr", "$ldtr", - "$mxcsr", "$fcw", "$fsw" - }; - - return MakeVector(names, sizeof(names) / sizeof(names[0])); -} - -// Per ARM IHI 0040A, section 3.1 -vector<string> DwarfCFIToModule::RegisterNames::ARM() { - static const char *const names[] = { - "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc", - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "fps", "cpsr", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", - "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", - "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", - "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", - "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" - }; - - return MakeVector(names, sizeof(names) / sizeof(names[0])); -} - -// Per ARM IHI 0057A, section 3.1 -vector<string> DwarfCFIToModule::RegisterNames::ARM64() { - static const char *const names[] = { - "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", - "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", - "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", - "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", - "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", - "", "", "", "", "", "", "", "", - "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", - "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", - "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", - "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" - }; - - return MakeVector(names, sizeof(names) / sizeof(names[0])); -} - -vector<string> DwarfCFIToModule::RegisterNames::MIPS() { - static const char* const kRegisterNames[] = { - "$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3", - "$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7", - "$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7", - "$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra", - "$lo", "$hi", "$pc", "$f0", "$f2", "$f3", "$f4", "$f5", - "$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", - "$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20", - "$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27", - "$f28", "$f29", "$f30", "$f31", "$fcsr", "$fir" - }; - - return MakeVector(kRegisterNames, - sizeof(kRegisterNames) / sizeof(kRegisterNames[0])); -} - -bool DwarfCFIToModule::Entry(size_t offset, uint64 address, uint64 length, - uint8 version, const string &augmentation, - unsigned return_address) { - assert(!entry_); - - // If dwarf2reader::CallFrameInfo can handle this version and - // augmentation, then we should be okay with that, so there's no - // need to check them here. - - // Get ready to collect entries. - entry_ = new Module::StackFrameEntry; - entry_->address = address; - entry_->size = length; - entry_offset_ = offset; - return_address_ = return_address; - - // Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI - // may not establish any rule for .ra if the return address column - // is an ordinary register, and that register holds the return - // address on entry to the function. So establish an initial .ra - // rule citing the return address register. - if (return_address_ < register_names_.size()) - entry_->initial_rules[ra_name_] = register_names_[return_address_]; - - return true; -} - -string DwarfCFIToModule::RegisterName(int i) { - assert(entry_); - if (i < 0) { - assert(i == kCFARegister); - return cfa_name_; - } - unsigned reg = i; - if (reg == return_address_) - return ra_name_; - - // Ensure that a non-empty name exists for this register value. - if (reg < register_names_.size() && !register_names_[reg].empty()) - return register_names_[reg]; - - reporter_->UnnamedRegister(entry_offset_, reg); - char buf[30]; - sprintf(buf, "unnamed_register%u", reg); - return buf; -} - -void DwarfCFIToModule::Record(Module::Address address, int reg, - const string &rule) { - assert(entry_); - - // Place the name in our global set of strings, and then use the string - // from the set. Even though the assignment looks like a copy, all the - // major std::string implementations use reference counting internally, - // so the effect is to have all our data structures share copies of rules - // whenever possible. Since register names are drawn from a - // vector<string>, register names are already shared. - string shared_rule = *common_strings_.insert(rule).first; - - // Is this one of this entry's initial rules? - if (address == entry_->address) - entry_->initial_rules[RegisterName(reg)] = shared_rule; - // File it under the appropriate address. - else - entry_->rule_changes[address][RegisterName(reg)] = shared_rule; -} - -bool DwarfCFIToModule::UndefinedRule(uint64 address, int reg) { - reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg)); - // Treat this as a non-fatal error. - return true; -} - -bool DwarfCFIToModule::SameValueRule(uint64 address, int reg) { - ostringstream s; - s << RegisterName(reg); - Record(address, reg, s.str()); - return true; -} - -bool DwarfCFIToModule::OffsetRule(uint64 address, int reg, - int base_register, long offset) { - ostringstream s; - s << RegisterName(base_register) << " " << offset << " + ^"; - Record(address, reg, s.str()); - return true; -} - -bool DwarfCFIToModule::ValOffsetRule(uint64 address, int reg, - int base_register, long offset) { - ostringstream s; - s << RegisterName(base_register) << " " << offset << " +"; - Record(address, reg, s.str()); - return true; -} - -bool DwarfCFIToModule::RegisterRule(uint64 address, int reg, - int base_register) { - ostringstream s; - s << RegisterName(base_register); - Record(address, reg, s.str()); - return true; -} - -bool DwarfCFIToModule::ExpressionRule(uint64 address, int reg, - const string &expression) { - reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); - // Treat this as a non-fatal error. - return true; -} - -bool DwarfCFIToModule::ValExpressionRule(uint64 address, int reg, - const string &expression) { - reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg)); - // Treat this as a non-fatal error. - return true; -} - -bool DwarfCFIToModule::End() { - module_->AddStackFrameEntry(entry_); - entry_ = NULL; - return true; -} - -void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) { - fprintf(stderr, "%s, section '%s': " - "the call frame entry at offset 0x%zx refers to register %d," - " whose name we don't know\n", - file_.c_str(), section_.c_str(), offset, reg); -} - -void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset, - const string ®) { - fprintf(stderr, "%s, section '%s': " - "the call frame entry at offset 0x%zx sets the rule for " - "register '%s' to 'undefined', but the Breakpad symbol file format" - " cannot express this\n", - file_.c_str(), section_.c_str(), offset, reg.c_str()); -} - -void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset, - const string ®) { - fprintf(stderr, "%s, section '%s': " - "the call frame entry at offset 0x%zx uses a DWARF expression to" - " describe how to recover register '%s', " - " but this translator cannot yet translate DWARF expressions to" - " Breakpad postfix expressions\n", - file_.c_str(), section_.c_str(), offset, reg.c_str()); -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.h deleted file mode 100644 index 084b8f5a7..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module.h +++ /dev/null @@ -1,202 +0,0 @@ -// -*- mode: c++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf_cfi_to_module.h: Define the DwarfCFIToModule class, which -// accepts parsed DWARF call frame info and adds it to a -// google_breakpad::Module object, which can write that information to -// a Breakpad symbol file. - -#ifndef COMMON_LINUX_DWARF_CFI_TO_MODULE_H -#define COMMON_LINUX_DWARF_CFI_TO_MODULE_H - -#include <assert.h> -#include <stdio.h> - -#include <set> -#include <string> -#include <vector> - -#include "common/module.h" -#include "common/dwarf/dwarf2reader.h" -#include "common/using_std_string.h" - -namespace google_breakpad { - -using dwarf2reader::CallFrameInfo; -using google_breakpad::Module; -using std::set; -using std::vector; - -// A class that accepts parsed call frame information from the DWARF -// CFI parser and populates a google_breakpad::Module object with the -// contents. -class DwarfCFIToModule: public CallFrameInfo::Handler { - public: - - // DwarfCFIToModule uses an instance of this class to report errors - // detected while converting DWARF CFI to Breakpad STACK CFI records. - class Reporter { - public: - // Create a reporter that writes messages to the standard error - // stream. FILE is the name of the file we're processing, and - // SECTION is the name of the section within that file that we're - // looking at (.debug_frame, .eh_frame, etc.). - Reporter(const string &file, const string §ion) - : file_(file), section_(section) { } - virtual ~Reporter() { } - - // The DWARF CFI entry at OFFSET cites register REG, but REG is not - // covered by the vector of register names passed to the - // DwarfCFIToModule constructor, nor does it match the return - // address column number for this entry. - virtual void UnnamedRegister(size_t offset, int reg); - - // The DWARF CFI entry at OFFSET says that REG is undefined, but the - // Breakpad symbol file format cannot express this. - virtual void UndefinedNotSupported(size_t offset, const string ®); - - // The DWARF CFI entry at OFFSET says that REG uses a DWARF - // expression to find its value, but DwarfCFIToModule is not - // capable of translating DWARF expressions to Breakpad postfix - // expressions. - virtual void ExpressionsNotSupported(size_t offset, const string ®); - - protected: - string file_, section_; - }; - - // Register name tables. If TABLE is a vector returned by one of these - // functions, then TABLE[R] is the name of the register numbered R in - // DWARF call frame information. - class RegisterNames { - public: - // Intel's "x86" or IA-32. - static vector<string> I386(); - - // AMD x86_64, AMD64, Intel EM64T, or Intel 64 - static vector<string> X86_64(); - - // ARM. - static vector<string> ARM(); - - // ARM64, aka AARCH64. - static vector<string> ARM64(); - - // MIPS. - static vector<string> MIPS(); - - private: - // Given STRINGS, an array of C strings with SIZE elements, return an - // equivalent vector<string>. - static vector<string> MakeVector(const char * const *strings, size_t size); - }; - - // Create a handler for the dwarf2reader::CallFrameInfo parser that - // records the stack unwinding information it receives in MODULE. - // - // Use REGISTER_NAMES[I] as the name of register number I; *this - // keeps a reference to the vector, so the vector should remain - // alive for as long as the DwarfCFIToModule does. - // - // Use REPORTER for reporting problems encountered in the conversion - // process. - DwarfCFIToModule(Module *module, const vector<string> ®ister_names, - Reporter *reporter) - : module_(module), register_names_(register_names), reporter_(reporter), - entry_(NULL), return_address_(-1), cfa_name_(".cfa"), ra_name_(".ra") { - } - virtual ~DwarfCFIToModule() { delete entry_; } - - virtual bool Entry(size_t offset, uint64 address, uint64 length, - uint8 version, const string &augmentation, - unsigned return_address); - virtual bool UndefinedRule(uint64 address, int reg); - virtual bool SameValueRule(uint64 address, int reg); - virtual bool OffsetRule(uint64 address, int reg, - int base_register, long offset); - virtual bool ValOffsetRule(uint64 address, int reg, - int base_register, long offset); - virtual bool RegisterRule(uint64 address, int reg, int base_register); - virtual bool ExpressionRule(uint64 address, int reg, - const string &expression); - virtual bool ValExpressionRule(uint64 address, int reg, - const string &expression); - virtual bool End(); - - private: - // Return the name to use for register REG. - string RegisterName(int i); - - // Record RULE for register REG at ADDRESS. - void Record(Module::Address address, int reg, const string &rule); - - // The module to which we should add entries. - Module *module_; - - // Map from register numbers to register names. - const vector<string> ®ister_names_; - - // The reporter to use to report problems. - Reporter *reporter_; - - // The current entry we're constructing. - Module::StackFrameEntry *entry_; - - // The section offset of the current frame description entry, for - // use in error messages. - size_t entry_offset_; - - // The return address column for that entry. - unsigned return_address_; - - // The names of the return address and canonical frame address. Putting - // these here instead of using string literals allows us to share their - // texts in reference-counted std::string implementations (all the - // popular ones). Many, many rules cite these strings. - string cfa_name_, ra_name_; - - // A set of strings used by this CFI. Before storing a string in one of - // our data structures, insert it into this set, and then use the string - // from the set. - // - // Because std::string uses reference counting internally, simply using - // strings from this set, even if passed by value, assigned, or held - // directly in structures and containers (map<string, ...>, for example), - // causes those strings to share a single instance of each distinct piece - // of text. - set<string> common_strings_; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_DWARF_CFI_TO_MODULE_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module_unittest.cc deleted file mode 100644 index 807d1b20c..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cfi_to_module_unittest.cc +++ /dev/null @@ -1,306 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule. - -#include <string> -#include <vector> - -#include "breakpad_googletest_includes.h" -#include "common/dwarf_cfi_to_module.h" -#include "common/using_std_string.h" - -using std::vector; - -using google_breakpad::Module; -using google_breakpad::DwarfCFIToModule; -using testing::ContainerEq; -using testing::Test; -using testing::_; - -struct MockCFIReporter: public DwarfCFIToModule::Reporter { - MockCFIReporter(const string &file, const string §ion) - : Reporter(file, section) { } - MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg)); - MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string ®)); - MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string ®)); -}; - -struct DwarfCFIToModuleFixture { - DwarfCFIToModuleFixture() - : module("module name", "module os", "module arch", "module id"), - reporter("reporter file", "reporter section"), - handler(&module, register_names, &reporter) { - register_names.push_back("reg0"); - register_names.push_back("reg1"); - register_names.push_back("reg2"); - register_names.push_back("reg3"); - register_names.push_back("reg4"); - register_names.push_back("reg5"); - register_names.push_back("reg6"); - register_names.push_back("reg7"); - register_names.push_back("sp"); - register_names.push_back("pc"); - register_names.push_back(""); - - EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0); - EXPECT_CALL(reporter, UndefinedNotSupported(_, _)).Times(0); - EXPECT_CALL(reporter, ExpressionsNotSupported(_, _)).Times(0); - } - - Module module; - vector<string> register_names; - MockCFIReporter reporter; - DwarfCFIToModule handler; - vector<Module::StackFrameEntry *> entries; -}; - -class Entry: public DwarfCFIToModuleFixture, public Test { }; - -TEST_F(Entry, Accept) { - ASSERT_TRUE(handler.Entry(0x3b8961b8, 0xa21069698096fc98ULL, - 0xb440ce248169c8d6ULL, 3, "", 0xea93c106)); - ASSERT_TRUE(handler.End()); - module.GetStackFrameEntries(&entries); - EXPECT_EQ(1U, entries.size()); - EXPECT_EQ(0xa21069698096fc98ULL, entries[0]->address); - EXPECT_EQ(0xb440ce248169c8d6ULL, entries[0]->size); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Entry, AcceptOldVersion) { - ASSERT_TRUE(handler.Entry(0xeb60e0fc, 0x75b8806bb09eab78ULL, - 0xc771f44958d40bbcULL, 1, "", 0x093c945e)); - ASSERT_TRUE(handler.End()); - module.GetStackFrameEntries(&entries); - EXPECT_EQ(1U, entries.size()); - EXPECT_EQ(0x75b8806bb09eab78ULL, entries[0]->address); - EXPECT_EQ(0xc771f44958d40bbcULL, entries[0]->size); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -struct RuleFixture: public DwarfCFIToModuleFixture { - RuleFixture() : DwarfCFIToModuleFixture() { - entry_address = 0x89327ebf86b47492ULL; - entry_size = 0x2f8cd573072fe02aULL; - return_reg = 0x7886a346; - } - void StartEntry() { - ASSERT_TRUE(handler.Entry(0x4445c05c, entry_address, entry_size, - 3, "", return_reg)); - } - void CheckEntry() { - module.GetStackFrameEntries(&entries); - EXPECT_EQ(1U, entries.size()); - EXPECT_EQ(entry_address, entries[0]->address); - EXPECT_EQ(entry_size, entries[0]->size); - } - uint64 entry_address, entry_size; - unsigned return_reg; -}; - -class Rule: public RuleFixture, public Test { }; - -TEST_F(Rule, UndefinedRule) { - EXPECT_CALL(reporter, UndefinedNotSupported(_, "reg7")); - StartEntry(); - ASSERT_TRUE(handler.UndefinedRule(entry_address, 7)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, RegisterWithEmptyName) { - EXPECT_CALL(reporter, UnnamedRegister(_, 10)); - EXPECT_CALL(reporter, UndefinedNotSupported(_, "unnamed_register10")); - StartEntry(); - ASSERT_TRUE(handler.UndefinedRule(entry_address, 10)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, SameValueRule) { - StartEntry(); - ASSERT_TRUE(handler.SameValueRule(entry_address, 6)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - Module::RuleMap expected_initial; - expected_initial["reg6"] = "reg6"; - EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, OffsetRule) { - StartEntry(); - ASSERT_TRUE(handler.OffsetRule(entry_address + 1, return_reg, - DwarfCFIToModule::kCFARegister, - 16927065)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - Module::RuleChangeMap expected_changes; - expected_changes[entry_address + 1][".ra"] = ".cfa 16927065 + ^"; - EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); -} - -TEST_F(Rule, OffsetRuleNegative) { - StartEntry(); - ASSERT_TRUE(handler.OffsetRule(entry_address + 1, - DwarfCFIToModule::kCFARegister, 4, -34530721)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - Module::RuleChangeMap expected_changes; - expected_changes[entry_address + 1][".cfa"] = "reg4 -34530721 + ^"; - EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); -} - -TEST_F(Rule, ValOffsetRule) { - // Use an unnamed register number, to exercise that branch of RegisterName. - EXPECT_CALL(reporter, UnnamedRegister(_, 11)); - StartEntry(); - ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7, - DwarfCFIToModule::kCFARegister, - 11, 61812979)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - Module::RuleChangeMap expected_changes; - expected_changes[entry_address + 0x5ab7][".cfa"] = - "unnamed_register11 61812979 +"; - EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); -} - -TEST_F(Rule, RegisterRule) { - StartEntry(); - ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 3)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - Module::RuleMap expected_initial; - expected_initial[".ra"] = "reg3"; - EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, ExpressionRule) { - EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg2")); - StartEntry(); - ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2, - "it takes two to tango")); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, ValExpressionRule) { - EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg0")); - StartEntry(); - ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0, - "bit off more than he could chew")); - ASSERT_TRUE(handler.End()); - CheckEntry(); - EXPECT_EQ(0U, entries[0]->initial_rules.size()); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, DefaultReturnAddressRule) { - return_reg = 2; - StartEntry(); - ASSERT_TRUE(handler.RegisterRule(entry_address, 0, 1)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - Module::RuleMap expected_initial; - expected_initial[".ra"] = "reg2"; - expected_initial["reg0"] = "reg1"; - EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, DefaultReturnAddressRuleOverride) { - return_reg = 2; - StartEntry(); - ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 1)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - Module::RuleMap expected_initial; - expected_initial[".ra"] = "reg1"; - EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); - EXPECT_EQ(0U, entries[0]->rule_changes.size()); -} - -TEST_F(Rule, DefaultReturnAddressRuleLater) { - return_reg = 2; - StartEntry(); - ASSERT_TRUE(handler.RegisterRule(entry_address + 1, return_reg, 1)); - ASSERT_TRUE(handler.End()); - CheckEntry(); - Module::RuleMap expected_initial; - expected_initial[".ra"] = "reg2"; - EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial)); - Module::RuleChangeMap expected_changes; - expected_changes[entry_address + 1][".ra"] = "reg1"; - EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes)); -} - -TEST(RegisterNames, I386) { - vector<string> names = DwarfCFIToModule::RegisterNames::I386(); - - EXPECT_EQ("$eax", names[0]); - EXPECT_EQ("$ecx", names[1]); - EXPECT_EQ("$esp", names[4]); - EXPECT_EQ("$eip", names[8]); -} - -TEST(RegisterNames, ARM) { - vector<string> names = DwarfCFIToModule::RegisterNames::ARM(); - - EXPECT_EQ("r0", names[0]); - EXPECT_EQ("r10", names[10]); - EXPECT_EQ("sp", names[13]); - EXPECT_EQ("lr", names[14]); - EXPECT_EQ("pc", names[15]); -} - -TEST(RegisterNames, X86_64) { - vector<string> names = DwarfCFIToModule::RegisterNames::X86_64(); - - EXPECT_EQ("$rax", names[0]); - EXPECT_EQ("$rdx", names[1]); - EXPECT_EQ("$rbp", names[6]); - EXPECT_EQ("$rsp", names[7]); - EXPECT_EQ("$rip", names[16]); -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.cc deleted file mode 100644 index 479e39b22..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.cc +++ /dev/null @@ -1,1075 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// Implement the DwarfCUToModule class; see dwarf_cu_to_module.h. - -// For <inttypes.h> PRI* macros, before anything else might #include it. -#ifndef __STDC_FORMAT_MACROS -#define __STDC_FORMAT_MACROS -#endif /* __STDC_FORMAT_MACROS */ - -#include "common/dwarf_cu_to_module.h" - -#include <assert.h> -#if !defined(__ANDROID__) -#include <cxxabi.h> -#endif -#include <inttypes.h> -#include <stdint.h> -#include <stdio.h> - -#include <algorithm> -#include <utility> - -#include "common/dwarf_line_to_module.h" -#include "common/unordered.h" - -namespace google_breakpad { - -using std::map; -using std::pair; -using std::sort; -using std::vector; - -// Data provided by a DWARF specification DIE. -// -// In DWARF, the DIE for a definition may contain a DW_AT_specification -// attribute giving the offset of the corresponding declaration DIE, and -// the definition DIE may omit information given in the declaration. For -// example, it's common for a function's address range to appear only in -// its definition DIE, but its name to appear only in its declaration -// DIE. -// -// The dumper needs to be able to follow DW_AT_specification links to -// bring all this information together in a FUNC record. Conveniently, -// DIEs that are the target of such links have a DW_AT_declaration flag -// set, so we can identify them when we first see them, and record their -// contents for later reference. -// -// A Specification holds information gathered from a declaration DIE that -// we may need if we find a DW_AT_specification link pointing to it. -struct DwarfCUToModule::Specification { - // The qualified name that can be found by demangling DW_AT_MIPS_linkage_name. - string qualified_name; - - // The name of the enclosing scope, or the empty string if there is none. - string enclosing_name; - - // The name for the specification DIE itself, without any enclosing - // name components. - string unqualified_name; -}; - -// An abstract origin -- base definition of an inline function. -struct AbstractOrigin { - AbstractOrigin() : name() {} - explicit AbstractOrigin(const string& name) : name(name) {} - - string name; -}; - -typedef map<uint64, AbstractOrigin> AbstractOriginByOffset; - -// Data global to the DWARF-bearing file that is private to the -// DWARF-to-Module process. -struct DwarfCUToModule::FilePrivate { - // A set of strings used in this CU. Before storing a string in one of - // our data structures, insert it into this set, and then use the string - // from the set. - // - // In some STL implementations, strings are reference-counted internally, - // meaning that simply using strings from this set, even if passed by - // value, assigned, or held directly in structures and containers - // (map<string, ...>, for example), causes those strings to share a - // single instance of each distinct piece of text. GNU's libstdc++ uses - // reference counts, and I believe MSVC did as well, at some point. - // However, C++ '11 implementations are moving away from reference - // counting. - // - // In other implementations, string assignments copy the string's text, - // so this set will actually hold yet another copy of the string (although - // everything will still work). To improve memory consumption portably, - // we will probably need to use pointers to strings held in this set. - unordered_set<string> common_strings; - - // A map from offsets of DIEs within the .debug_info section to - // Specifications describing those DIEs. Specification references can - // cross compilation unit boundaries. - SpecificationByOffset specifications; - - AbstractOriginByOffset origins; -}; - -DwarfCUToModule::FileContext::FileContext(const string &filename, - Module *module, - bool handle_inter_cu_refs) - : filename_(filename), - module_(module), - handle_inter_cu_refs_(handle_inter_cu_refs), - file_private_(new FilePrivate()) { -} - -DwarfCUToModule::FileContext::~FileContext() { -} - -void DwarfCUToModule::FileContext::AddSectionToSectionMap( - const string& name, const uint8_t *contents, uint64 length) { - section_map_[name] = std::make_pair(contents, length); -} - -void DwarfCUToModule::FileContext::ClearSectionMapForTest() { - section_map_.clear(); -} - -const dwarf2reader::SectionMap& -DwarfCUToModule::FileContext::section_map() const { - return section_map_; -} - -void DwarfCUToModule::FileContext::ClearSpecifications() { - if (!handle_inter_cu_refs_) - file_private_->specifications.clear(); -} - -bool DwarfCUToModule::FileContext::IsUnhandledInterCUReference( - uint64 offset, uint64 compilation_unit_start) const { - if (handle_inter_cu_refs_) - return false; - return offset < compilation_unit_start; -} - -// Information global to the particular compilation unit we're -// parsing. This is for data shared across the CU's entire DIE tree, -// and parameters from the code invoking the CU parser. -struct DwarfCUToModule::CUContext { - CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg) - : file_context(file_context_arg), - reporter(reporter_arg), - language(Language::CPlusPlus) {} - - ~CUContext() { - for (vector<Module::Function *>::iterator it = functions.begin(); - it != functions.end(); ++it) { - delete *it; - } - }; - - // The DWARF-bearing file into which this CU was incorporated. - FileContext *file_context; - - // For printing error messages. - WarningReporter *reporter; - - // The source language of this compilation unit. - const Language *language; - - // The functions defined in this compilation unit. We accumulate - // them here during parsing. Then, in DwarfCUToModule::Finish, we - // assign them lines and add them to file_context->module. - // - // Destroying this destroys all the functions this vector points to. - vector<Module::Function *> functions; -}; - -// Information about the context of a particular DIE. This is for -// information that changes as we descend the tree towards the leaves: -// the containing classes/namespaces, etc. -struct DwarfCUToModule::DIEContext { - // The fully-qualified name of the context. For example, for a - // tree like: - // - // DW_TAG_namespace Foo - // DW_TAG_class Bar - // DW_TAG_subprogram Baz - // - // in a C++ compilation unit, the DIEContext's name for the - // DW_TAG_subprogram DIE would be "Foo::Bar". The DIEContext's - // name for the DW_TAG_namespace DIE would be "". - string name; -}; - -// An abstract base class for all the dumper's DIE handlers. -class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler { - public: - // Create a handler for the DIE at OFFSET whose compilation unit is - // described by CU_CONTEXT, and whose immediate context is described - // by PARENT_CONTEXT. - GenericDIEHandler(CUContext *cu_context, DIEContext *parent_context, - uint64 offset) - : cu_context_(cu_context), - parent_context_(parent_context), - offset_(offset), - declaration_(false), - specification_(NULL) { } - - // Derived classes' ProcessAttributeUnsigned can defer to this to - // handle DW_AT_declaration, or simply not override it. - void ProcessAttributeUnsigned(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - - // Derived classes' ProcessAttributeReference can defer to this to - // handle DW_AT_specification, or simply not override it. - void ProcessAttributeReference(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - - // Derived classes' ProcessAttributeReference can defer to this to - // handle DW_AT_specification, or simply not override it. - void ProcessAttributeString(enum DwarfAttribute attr, - enum DwarfForm form, - const string &data); - - protected: - // Compute and return the fully-qualified name of the DIE. If this - // DIE is a declaration DIE, to be cited by other DIEs' - // DW_AT_specification attributes, record its enclosing name and - // unqualified name in the specification table. - // - // Use this from EndAttributes member functions, not ProcessAttribute* - // functions; only the former can be sure that all the DIE's attributes - // have been seen. - string ComputeQualifiedName(); - - CUContext *cu_context_; - DIEContext *parent_context_; - uint64 offset_; - - // Place the name in the global set of strings. Even though this looks - // like a copy, all the major std::string implementations use reference - // counting internally, so the effect is to have all the data structures - // share copies of strings whenever possible. - // FIXME: Should this return something like a string_ref to avoid the - // assumption about how strings are implemented? - string AddStringToPool(const string &str); - - // If this DIE has a DW_AT_declaration attribute, this is its value. - // It is false on DIEs with no DW_AT_declaration attribute. - bool declaration_; - - // If this DIE has a DW_AT_specification attribute, this is the - // Specification structure for the DIE the attribute refers to. - // Otherwise, this is NULL. - Specification *specification_; - - // The value of the DW_AT_name attribute, or the empty string if the - // DIE has no such attribute. - string name_attribute_; - - // The demangled value of the DW_AT_MIPS_linkage_name attribute, or the empty - // string if the DIE has no such attribute or its content could not be - // demangled. - string demangled_name_; -}; - -void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned( - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - switch (attr) { - case dwarf2reader::DW_AT_declaration: declaration_ = (data != 0); break; - default: break; - } -} - -void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference( - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - switch (attr) { - case dwarf2reader::DW_AT_specification: { - FileContext *file_context = cu_context_->file_context; - if (file_context->IsUnhandledInterCUReference( - data, cu_context_->reporter->cu_offset())) { - cu_context_->reporter->UnhandledInterCUReference(offset_, data); - break; - } - // Find the Specification to which this attribute refers, and - // set specification_ appropriately. We could do more processing - // here, but it's better to leave the real work to our - // EndAttribute member function, at which point we know we have - // seen all the DIE's attributes. - SpecificationByOffset *specifications = - &file_context->file_private_->specifications; - SpecificationByOffset::iterator spec = specifications->find(data); - if (spec != specifications->end()) { - specification_ = &spec->second; - } else { - // Technically, there's no reason a DW_AT_specification - // couldn't be a forward reference, but supporting that would - // be a lot of work (changing to a two-pass structure), and I - // don't think any producers we care about ever emit such - // things. - cu_context_->reporter->UnknownSpecification(offset_, data); - } - break; - } - default: break; - } -} - -string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) { - pair<unordered_set<string>::iterator, bool> result = - cu_context_->file_context->file_private_->common_strings.insert(str); - return *result.first; -} - -void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString( - enum DwarfAttribute attr, - enum DwarfForm form, - const string &data) { - switch (attr) { - case dwarf2reader::DW_AT_name: - name_attribute_ = AddStringToPool(data); - break; - case dwarf2reader::DW_AT_MIPS_linkage_name: { - char* demangled = NULL; - int status = -1; -#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle. - demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, &status); -#endif - if (status != 0) { - cu_context_->reporter->DemangleError(data, status); - demangled_name_ = ""; - break; - } - if (demangled) { - demangled_name_ = AddStringToPool(demangled); - free(reinterpret_cast<void*>(demangled)); - } - break; - } - default: break; - } -} - -string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() { - // Use the demangled name, if one is available. Demangled names are - // preferable to those inferred from the DWARF structure because they - // include argument types. - const string *qualified_name = NULL; - if (!demangled_name_.empty()) { - // Found it is this DIE. - qualified_name = &demangled_name_; - } else if (specification_ && !specification_->qualified_name.empty()) { - // Found it on the specification. - qualified_name = &specification_->qualified_name; - } - - const string *unqualified_name = NULL; - const string *enclosing_name; - if (!qualified_name) { - // Find the unqualified name. If the DIE has its own DW_AT_name - // attribute, then use that; otherwise, check the specification. - if (!name_attribute_.empty()) - unqualified_name = &name_attribute_; - else if (specification_) - unqualified_name = &specification_->unqualified_name; - - // Find the name of the enclosing context. If this DIE has a - // specification, it's the specification's enclosing context that - // counts; otherwise, use this DIE's context. - if (specification_) - enclosing_name = &specification_->enclosing_name; - else - enclosing_name = &parent_context_->name; - } - - // Prepare the return value before upcoming mutations possibly invalidate the - // existing pointers. - string return_value; - if (qualified_name) { - return_value = *qualified_name; - } else if (unqualified_name && enclosing_name) { - // Combine the enclosing name and unqualified name to produce our - // own fully-qualified name. - return_value = cu_context_->language->MakeQualifiedName(*enclosing_name, - *unqualified_name); - } - - // If this DIE was marked as a declaration, record its names in the - // specification table. - if ((declaration_ && qualified_name) || - (unqualified_name && enclosing_name)) { - Specification spec; - if (qualified_name) { - spec.qualified_name = *qualified_name; - } else { - spec.enclosing_name = *enclosing_name; - spec.unqualified_name = *unqualified_name; - } - cu_context_->file_context->file_private_->specifications[offset_] = spec; - } - - return return_value; -} - -// A handler class for DW_TAG_subprogram DIEs. -class DwarfCUToModule::FuncHandler: public GenericDIEHandler { - public: - FuncHandler(CUContext *cu_context, DIEContext *parent_context, - uint64 offset) - : GenericDIEHandler(cu_context, parent_context, offset), - low_pc_(0), high_pc_(0), high_pc_form_(dwarf2reader::DW_FORM_addr), - abstract_origin_(NULL), inline_(false) { } - void ProcessAttributeUnsigned(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - void ProcessAttributeSigned(enum DwarfAttribute attr, - enum DwarfForm form, - int64 data); - void ProcessAttributeReference(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - - bool EndAttributes(); - void Finish(); - - private: - // The fully-qualified name, as derived from name_attribute_, - // specification_, parent_context_. Computed in EndAttributes. - string name_; - uint64 low_pc_, high_pc_; // DW_AT_low_pc, DW_AT_high_pc - DwarfForm high_pc_form_; // DW_AT_high_pc can be length or address. - const AbstractOrigin* abstract_origin_; - bool inline_; -}; - -void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned( - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - switch (attr) { - // If this attribute is present at all --- even if its value is - // DW_INL_not_inlined --- then GCC may cite it as someone else's - // DW_AT_abstract_origin attribute. - case dwarf2reader::DW_AT_inline: inline_ = true; break; - - case dwarf2reader::DW_AT_low_pc: low_pc_ = data; break; - case dwarf2reader::DW_AT_high_pc: - high_pc_form_ = form; - high_pc_ = data; - break; - - default: - GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data); - break; - } -} - -void DwarfCUToModule::FuncHandler::ProcessAttributeSigned( - enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { - switch (attr) { - // If this attribute is present at all --- even if its value is - // DW_INL_not_inlined --- then GCC may cite it as someone else's - // DW_AT_abstract_origin attribute. - case dwarf2reader::DW_AT_inline: inline_ = true; break; - - default: - break; - } -} - -void DwarfCUToModule::FuncHandler::ProcessAttributeReference( - enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - switch (attr) { - case dwarf2reader::DW_AT_abstract_origin: { - const AbstractOriginByOffset& origins = - cu_context_->file_context->file_private_->origins; - AbstractOriginByOffset::const_iterator origin = origins.find(data); - if (origin != origins.end()) { - abstract_origin_ = &(origin->second); - } else { - cu_context_->reporter->UnknownAbstractOrigin(offset_, data); - } - break; - } - default: - GenericDIEHandler::ProcessAttributeReference(attr, form, data); - break; - } -} - -bool DwarfCUToModule::FuncHandler::EndAttributes() { - // Compute our name, and record a specification, if appropriate. - name_ = ComputeQualifiedName(); - if (name_.empty() && abstract_origin_) { - name_ = abstract_origin_->name; - } - return true; -} - -void DwarfCUToModule::FuncHandler::Finish() { - // Make high_pc_ an address, if it isn't already. - if (high_pc_form_ != dwarf2reader::DW_FORM_addr) { - high_pc_ += low_pc_; - } - - // Did we collect the information we need? Not all DWARF function - // entries have low and high addresses (for example, inlined - // functions that were never used), but all the ones we're - // interested in cover a non-empty range of bytes. - if (low_pc_ < high_pc_) { - // Malformed DWARF may omit the name, but all Module::Functions must - // have names. - string name; - if (!name_.empty()) { - name = name_; - } else { - cu_context_->reporter->UnnamedFunction(offset_); - name = "<name omitted>"; - } - - // Create a Module::Function based on the data we've gathered, and - // add it to the functions_ list. - scoped_ptr<Module::Function> func(new Module::Function(name, low_pc_)); - func->size = high_pc_ - low_pc_; - func->parameter_size = 0; - if (func->address) { - // If the function address is zero this is a sign that this function - // description is just empty debug data and should just be discarded. - cu_context_->functions.push_back(func.release()); - } - } else if (inline_) { - AbstractOrigin origin(name_); - cu_context_->file_context->file_private_->origins[offset_] = origin; - } -} - -// A handler for DIEs that contain functions and contribute a -// component to their names: namespaces, classes, etc. -class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler { - public: - NamedScopeHandler(CUContext *cu_context, DIEContext *parent_context, - uint64 offset) - : GenericDIEHandler(cu_context, parent_context, offset) { } - bool EndAttributes(); - DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag); - - private: - DIEContext child_context_; // A context for our children. -}; - -bool DwarfCUToModule::NamedScopeHandler::EndAttributes() { - child_context_.name = ComputeQualifiedName(); - return true; -} - -dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler( - uint64 offset, - enum DwarfTag tag) { - switch (tag) { - case dwarf2reader::DW_TAG_subprogram: - return new FuncHandler(cu_context_, &child_context_, offset); - case dwarf2reader::DW_TAG_namespace: - case dwarf2reader::DW_TAG_class_type: - case dwarf2reader::DW_TAG_structure_type: - case dwarf2reader::DW_TAG_union_type: - return new NamedScopeHandler(cu_context_, &child_context_, offset); - default: - return NULL; - } -} - -void DwarfCUToModule::WarningReporter::CUHeading() { - if (printed_cu_header_) - return; - fprintf(stderr, "%s: in compilation unit '%s' (offset 0x%llx):\n", - filename_.c_str(), cu_name_.c_str(), cu_offset_); - printed_cu_header_ = true; -} - -void DwarfCUToModule::WarningReporter::UnknownSpecification(uint64 offset, - uint64 target) { - CUHeading(); - fprintf(stderr, "%s: the DIE at offset 0x%llx has a DW_AT_specification" - " attribute referring to the die at offset 0x%llx, which either" - " was not marked as a declaration, or comes later in the file\n", - filename_.c_str(), offset, target); -} - -void DwarfCUToModule::WarningReporter::UnknownAbstractOrigin(uint64 offset, - uint64 target) { - CUHeading(); - fprintf(stderr, "%s: the DIE at offset 0x%llx has a DW_AT_abstract_origin" - " attribute referring to the die at offset 0x%llx, which either" - " was not marked as an inline, or comes later in the file\n", - filename_.c_str(), offset, target); -} - -void DwarfCUToModule::WarningReporter::MissingSection(const string &name) { - CUHeading(); - fprintf(stderr, "%s: warning: couldn't find DWARF '%s' section\n", - filename_.c_str(), name.c_str()); -} - -void DwarfCUToModule::WarningReporter::BadLineInfoOffset(uint64 offset) { - CUHeading(); - fprintf(stderr, "%s: warning: line number data offset beyond end" - " of '.debug_line' section\n", - filename_.c_str()); -} - -void DwarfCUToModule::WarningReporter::UncoveredHeading() { - if (printed_unpaired_header_) - return; - CUHeading(); - fprintf(stderr, "%s: warning: skipping unpaired lines/functions:\n", - filename_.c_str()); - printed_unpaired_header_ = true; -} - -void DwarfCUToModule::WarningReporter::UncoveredFunction( - const Module::Function &function) { - if (!uncovered_warnings_enabled_) - return; - UncoveredHeading(); - fprintf(stderr, " function%s: %s\n", - function.size == 0 ? " (zero-length)" : "", - function.name.c_str()); -} - -void DwarfCUToModule::WarningReporter::UncoveredLine(const Module::Line &line) { - if (!uncovered_warnings_enabled_) - return; - UncoveredHeading(); - fprintf(stderr, " line%s: %s:%d at 0x%" PRIx64 "\n", - (line.size == 0 ? " (zero-length)" : ""), - line.file->name.c_str(), line.number, line.address); -} - -void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) { - CUHeading(); - fprintf(stderr, "%s: warning: function at offset 0x%llx has no name\n", - filename_.c_str(), offset); -} - -void DwarfCUToModule::WarningReporter::DemangleError( - const string &input, int error) { - CUHeading(); - fprintf(stderr, "%s: warning: failed to demangle %s with error %d\n", - filename_.c_str(), input.c_str(), error); -} - -void DwarfCUToModule::WarningReporter::UnhandledInterCUReference( - uint64 offset, uint64 target) { - CUHeading(); - fprintf(stderr, "%s: warning: the DIE at offset 0x%llx has a " - "DW_FORM_ref_addr attribute with an inter-CU reference to " - "0x%llx, but inter-CU reference handling is turned off.\n", - filename_.c_str(), offset, target); -} - -DwarfCUToModule::DwarfCUToModule(FileContext *file_context, - LineToModuleHandler *line_reader, - WarningReporter *reporter) - : line_reader_(line_reader), - cu_context_(new CUContext(file_context, reporter)), - child_context_(new DIEContext()), - has_source_line_info_(false) { -} - -DwarfCUToModule::~DwarfCUToModule() { -} - -void DwarfCUToModule::ProcessAttributeSigned(enum DwarfAttribute attr, - enum DwarfForm form, - int64 data) { - switch (attr) { - case dwarf2reader::DW_AT_language: // source language of this CU - SetLanguage(static_cast<DwarfLanguage>(data)); - break; - default: - break; - } -} - -void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data) { - switch (attr) { - case dwarf2reader::DW_AT_stmt_list: // Line number information. - has_source_line_info_ = true; - source_line_offset_ = data; - break; - case dwarf2reader::DW_AT_language: // source language of this CU - SetLanguage(static_cast<DwarfLanguage>(data)); - break; - default: - break; - } -} - -void DwarfCUToModule::ProcessAttributeString(enum DwarfAttribute attr, - enum DwarfForm form, - const string &data) { - switch (attr) { - case dwarf2reader::DW_AT_name: - cu_context_->reporter->SetCUName(data); - break; - case dwarf2reader::DW_AT_comp_dir: - line_reader_->StartCompilationUnit(data); - break; - default: - break; - } -} - -bool DwarfCUToModule::EndAttributes() { - return true; -} - -dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler( - uint64 offset, - enum DwarfTag tag) { - switch (tag) { - case dwarf2reader::DW_TAG_subprogram: - return new FuncHandler(cu_context_.get(), child_context_.get(), offset); - case dwarf2reader::DW_TAG_namespace: - case dwarf2reader::DW_TAG_class_type: - case dwarf2reader::DW_TAG_structure_type: - case dwarf2reader::DW_TAG_union_type: - return new NamedScopeHandler(cu_context_.get(), child_context_.get(), - offset); - default: - return NULL; - } -} - -void DwarfCUToModule::SetLanguage(DwarfLanguage language) { - switch (language) { - case dwarf2reader::DW_LANG_Java: - cu_context_->language = Language::Java; - break; - - // DWARF has no generic language code for assembly language; this is - // what the GNU toolchain uses. - case dwarf2reader::DW_LANG_Mips_Assembler: - cu_context_->language = Language::Assembler; - break; - - // C++ covers so many cases that it probably has some way to cope - // with whatever the other languages throw at us. So make it the - // default. - // - // Objective C and Objective C++ seem to create entries for - // methods whose DW_AT_name values are already fully-qualified: - // "-[Classname method:]". These appear at the top level. - // - // DWARF data for C should never include namespaces or functions - // nested in struct types, but if it ever does, then C++'s - // notation is probably not a bad choice for that. - default: - case dwarf2reader::DW_LANG_ObjC: - case dwarf2reader::DW_LANG_ObjC_plus_plus: - case dwarf2reader::DW_LANG_C: - case dwarf2reader::DW_LANG_C89: - case dwarf2reader::DW_LANG_C99: - case dwarf2reader::DW_LANG_C_plus_plus: - cu_context_->language = Language::CPlusPlus; - break; - } -} - -void DwarfCUToModule::ReadSourceLines(uint64 offset) { - const dwarf2reader::SectionMap §ion_map - = cu_context_->file_context->section_map(); - dwarf2reader::SectionMap::const_iterator map_entry - = section_map.find(".debug_line"); - // Mac OS X puts DWARF data in sections whose names begin with "__" - // instead of ".". - if (map_entry == section_map.end()) - map_entry = section_map.find("__debug_line"); - if (map_entry == section_map.end()) { - cu_context_->reporter->MissingSection(".debug_line"); - return; - } - const uint8_t *section_start = map_entry->second.first; - uint64 section_length = map_entry->second.second; - if (offset >= section_length) { - cu_context_->reporter->BadLineInfoOffset(offset); - return; - } - line_reader_->ReadProgram(section_start + offset, section_length - offset, - cu_context_->file_context->module_, &lines_); -} - -namespace { -// Return true if ADDRESS falls within the range of ITEM. -template <class T> -inline bool within(const T &item, Module::Address address) { - // Because Module::Address is unsigned, and unsigned arithmetic - // wraps around, this will be false if ADDRESS falls before the - // start of ITEM, or if it falls after ITEM's end. - return address - item.address < item.size; -} -} - -void DwarfCUToModule::AssignLinesToFunctions() { - vector<Module::Function *> *functions = &cu_context_->functions; - WarningReporter *reporter = cu_context_->reporter; - - // This would be simpler if we assumed that source line entries - // don't cross function boundaries. However, there's no real reason - // to assume that (say) a series of function definitions on the same - // line wouldn't get coalesced into one line number entry. The - // DWARF spec certainly makes no such promises. - // - // So treat the functions and lines as peers, and take the trouble - // to compute their ranges' intersections precisely. In any case, - // the hair here is a constant factor for performance; the - // complexity from here on out is linear. - - // Put both our functions and lines in order by address. - std::sort(functions->begin(), functions->end(), - Module::Function::CompareByAddress); - std::sort(lines_.begin(), lines_.end(), Module::Line::CompareByAddress); - - // The last line that we used any piece of. We use this only for - // generating warnings. - const Module::Line *last_line_used = NULL; - - // The last function and line we warned about --- so we can avoid - // doing so more than once. - const Module::Function *last_function_cited = NULL; - const Module::Line *last_line_cited = NULL; - - // Make a single pass through both vectors from lower to higher - // addresses, populating each Function's lines vector with lines - // from our lines_ vector that fall within the function's address - // range. - vector<Module::Function *>::iterator func_it = functions->begin(); - vector<Module::Line>::const_iterator line_it = lines_.begin(); - - Module::Address current; - - // Pointers to the referents of func_it and line_it, or NULL if the - // iterator is at the end of the sequence. - Module::Function *func; - const Module::Line *line; - - // Start current at the beginning of the first line or function, - // whichever is earlier. - if (func_it != functions->end() && line_it != lines_.end()) { - func = *func_it; - line = &*line_it; - current = std::min(func->address, line->address); - } else if (line_it != lines_.end()) { - func = NULL; - line = &*line_it; - current = line->address; - } else if (func_it != functions->end()) { - func = *func_it; - line = NULL; - current = (*func_it)->address; - } else { - return; - } - - while (func || line) { - // This loop has two invariants that hold at the top. - // - // First, at least one of the iterators is not at the end of its - // sequence, and those that are not refer to the earliest - // function or line that contains or starts after CURRENT. - // - // Note that every byte is in one of four states: it is covered - // or not covered by a function, and, independently, it is - // covered or not covered by a line. - // - // The second invariant is that CURRENT refers to a byte whose - // state is different from its predecessor, or it refers to the - // first byte in the address space. In other words, CURRENT is - // always the address of a transition. - // - // Note that, although each iteration advances CURRENT from one - // transition address to the next in each iteration, it might - // not advance the iterators. Suppose we have a function that - // starts with a line, has a gap, and then a second line, and - // suppose that we enter an iteration with CURRENT at the end of - // the first line. The next transition address is the start of - // the second line, after the gap, so the iteration should - // advance CURRENT to that point. At the head of that iteration, - // the invariants require that the line iterator be pointing at - // the second line. But this is also true at the head of the - // next. And clearly, the iteration must not change the function - // iterator. So neither iterator moves. - - // Assert the first invariant (see above). - assert(!func || current < func->address || within(*func, current)); - assert(!line || current < line->address || within(*line, current)); - - // The next transition after CURRENT. - Module::Address next_transition; - - // Figure out which state we're in, add lines or warn, and compute - // the next transition address. - if (func && current >= func->address) { - if (line && current >= line->address) { - // Covered by both a line and a function. - Module::Address func_left = func->size - (current - func->address); - Module::Address line_left = line->size - (current - line->address); - // This may overflow, but things work out. - next_transition = current + std::min(func_left, line_left); - Module::Line l = *line; - l.address = current; - l.size = next_transition - current; - func->lines.push_back(l); - last_line_used = line; - } else { - // Covered by a function, but no line. - if (func != last_function_cited) { - reporter->UncoveredFunction(*func); - last_function_cited = func; - } - if (line && within(*func, line->address)) - next_transition = line->address; - else - // If this overflows, we'll catch it below. - next_transition = func->address + func->size; - } - } else { - if (line && current >= line->address) { - // Covered by a line, but no function. - // - // If GCC emits padding after one function to align the start - // of the next, then it will attribute the padding - // instructions to the last source line of function (to reduce - // the size of the line number info), but omit it from the - // DW_AT_{low,high}_pc range given in .debug_info (since it - // costs nothing to be precise there). If we did use at least - // some of the line we're about to skip, and it ends at the - // start of the next function, then assume this is what - // happened, and don't warn. - if (line != last_line_cited - && !(func - && line == last_line_used - && func->address - line->address == line->size)) { - reporter->UncoveredLine(*line); - last_line_cited = line; - } - if (func && within(*line, func->address)) - next_transition = func->address; - else - // If this overflows, we'll catch it below. - next_transition = line->address + line->size; - } else { - // Covered by neither a function nor a line. By the invariant, - // both func and line begin after CURRENT. The next transition - // is the start of the next function or next line, whichever - // is earliest. - assert(func || line); - if (func && line) - next_transition = std::min(func->address, line->address); - else if (func) - next_transition = func->address; - else - next_transition = line->address; - } - } - - // If a function or line abuts the end of the address space, then - // next_transition may end up being zero, in which case we've completed - // our pass. Handle that here, instead of trying to deal with it in - // each place we compute next_transition. - if (!next_transition) - break; - - // Advance iterators as needed. If lines overlap or functions overlap, - // then we could go around more than once. We don't worry too much - // about what result we produce in that case, just as long as we don't - // hang or crash. - while (func_it != functions->end() - && next_transition >= (*func_it)->address - && !within(**func_it, next_transition)) - func_it++; - func = (func_it != functions->end()) ? *func_it : NULL; - while (line_it != lines_.end() - && next_transition >= line_it->address - && !within(*line_it, next_transition)) - line_it++; - line = (line_it != lines_.end()) ? &*line_it : NULL; - - // We must make progress. - assert(next_transition > current); - current = next_transition; - } -} - -void DwarfCUToModule::Finish() { - // Assembly language files have no function data, and that gives us - // no place to store our line numbers (even though the GNU toolchain - // will happily produce source line info for assembly language - // files). To avoid spurious warnings about lines we can't assign - // to functions, skip CUs in languages that lack functions. - if (!cu_context_->language->HasFunctions()) - return; - - // Read source line info, if we have any. - if (has_source_line_info_) - ReadSourceLines(source_line_offset_); - - vector<Module::Function *> *functions = &cu_context_->functions; - - // Dole out lines to the appropriate functions. - AssignLinesToFunctions(); - - // Add our functions, which now have source lines assigned to them, - // to module_. - cu_context_->file_context->module_->AddFunctions(functions->begin(), - functions->end()); - - // Ownership of the function objects has shifted from cu_context to - // the Module. - functions->clear(); - - cu_context_->file_context->ClearSpecifications(); -} - -bool DwarfCUToModule::StartCompilationUnit(uint64 offset, - uint8 address_size, - uint8 offset_size, - uint64 cu_length, - uint8 dwarf_version) { - return dwarf_version >= 2; -} - -bool DwarfCUToModule::StartRootDIE(uint64 offset, enum DwarfTag tag) { - // We don't deal with partial compilation units (the only other tag - // likely to be used for root DIE). - return tag == dwarf2reader::DW_TAG_compile_unit; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.h deleted file mode 100644 index fca92710e..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module.h +++ /dev/null @@ -1,320 +0,0 @@ -// -*- mode: c++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// Add DWARF debugging information to a Breakpad symbol file. This -// file defines the DwarfCUToModule class, which accepts parsed DWARF -// data and populates a google_breakpad::Module with the results; the -// Module can then write its contents as a Breakpad symbol file. - -#ifndef COMMON_LINUX_DWARF_CU_TO_MODULE_H__ -#define COMMON_LINUX_DWARF_CU_TO_MODULE_H__ - -#include <stdint.h> - -#include <string> - -#include "common/language.h" -#include "common/module.h" -#include "common/dwarf/bytereader.h" -#include "common/dwarf/dwarf2diehandler.h" -#include "common/dwarf/dwarf2reader.h" -#include "common/scoped_ptr.h" -#include "common/using_std_string.h" - -namespace google_breakpad { - -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfLanguage; -using dwarf2reader::DwarfTag; - -// Populate a google_breakpad::Module with DWARF debugging information. -// -// An instance of this class can be provided as a handler to a -// dwarf2reader::DIEDispatcher, which can in turn be a handler for a -// dwarf2reader::CompilationUnit DWARF parser. The handler uses the results -// of parsing to populate a google_breakpad::Module with source file, -// function, and source line information. -class DwarfCUToModule: public dwarf2reader::RootDIEHandler { - struct FilePrivate; - public: - // Information global to the DWARF-bearing file we are processing, - // for use by DwarfCUToModule. Each DwarfCUToModule instance deals - // with a single compilation unit within the file, but information - // global to the whole file is held here. The client is responsible - // for filling it in appropriately (except for the 'file_private' - // field, which the constructor and destructor take care of), and - // then providing it to the DwarfCUToModule instance for each - // compilation unit we process in that file. Set HANDLE_INTER_CU_REFS - // to true to handle debugging symbols with DW_FORM_ref_addr entries. - class FileContext { - public: - FileContext(const string &filename, - Module *module, - bool handle_inter_cu_refs); - ~FileContext(); - - // Add CONTENTS of size LENGTH to the section map as NAME. - void AddSectionToSectionMap(const string& name, - const uint8_t *contents, - uint64 length); - - // Clear the section map for testing. - void ClearSectionMapForTest(); - - const dwarf2reader::SectionMap& section_map() const; - - private: - friend class DwarfCUToModule; - - // Clears all the Specifications if HANDLE_INTER_CU_REFS_ is false. - void ClearSpecifications(); - - // Given an OFFSET and a CU that starts at COMPILATION_UNIT_START, returns - // true if this is an inter-compilation unit reference that is not being - // handled. - bool IsUnhandledInterCUReference(uint64 offset, - uint64 compilation_unit_start) const; - - // The name of this file, for use in error messages. - const string filename_; - - // A map of this file's sections, used for finding other DWARF - // sections that the .debug_info section may refer to. - dwarf2reader::SectionMap section_map_; - - // The Module to which we're contributing definitions. - Module *module_; - - // True if we are handling references between compilation units. - const bool handle_inter_cu_refs_; - - // Inter-compilation unit data used internally by the handlers. - scoped_ptr<FilePrivate> file_private_; - }; - - // An abstract base class for handlers that handle DWARF line data - // for DwarfCUToModule. DwarfCUToModule could certainly just use - // dwarf2reader::LineInfo itself directly, but decoupling things - // this way makes unit testing a little easier. - class LineToModuleHandler { - public: - LineToModuleHandler() { } - virtual ~LineToModuleHandler() { } - - // Called at the beginning of a new compilation unit, prior to calling - // ReadProgram(). compilation_dir will indicate the path that the - // current compilation unit was compiled in, consistent with the - // DW_AT_comp_dir DIE. - virtual void StartCompilationUnit(const string& compilation_dir) = 0; - - // Populate MODULE and LINES with source file names and code/line - // mappings, given a pointer to some DWARF line number data - // PROGRAM, and an overestimate of its size. Add no zero-length - // lines to LINES. - virtual void ReadProgram(const uint8_t *program, uint64 length, - Module *module, vector<Module::Line> *lines) = 0; - }; - - // The interface DwarfCUToModule uses to report warnings. The member - // function definitions for this class write messages to stderr, but - // you can override them if you'd like to detect or report these - // conditions yourself. - class WarningReporter { - public: - // Warn about problems in the DWARF file FILENAME, in the - // compilation unit at OFFSET. - WarningReporter(const string &filename, uint64 cu_offset) - : filename_(filename), cu_offset_(cu_offset), printed_cu_header_(false), - printed_unpaired_header_(false), - uncovered_warnings_enabled_(false) { } - virtual ~WarningReporter() { } - - // Set the name of the compilation unit we're processing to NAME. - virtual void SetCUName(const string &name) { cu_name_ = name; } - - // Accessor and setter for uncovered_warnings_enabled_. - // UncoveredFunction and UncoveredLine only report a problem if that is - // true. By default, these warnings are disabled, because those - // conditions occur occasionally in healthy code. - virtual bool uncovered_warnings_enabled() const { - return uncovered_warnings_enabled_; - } - virtual void set_uncovered_warnings_enabled(bool value) { - uncovered_warnings_enabled_ = value; - } - - // A DW_AT_specification in the DIE at OFFSET refers to a DIE we - // haven't processed yet, or that wasn't marked as a declaration, - // at TARGET. - virtual void UnknownSpecification(uint64 offset, uint64 target); - - // A DW_AT_abstract_origin in the DIE at OFFSET refers to a DIE we - // haven't processed yet, or that wasn't marked as inline, at TARGET. - virtual void UnknownAbstractOrigin(uint64 offset, uint64 target); - - // We were unable to find the DWARF section named SECTION_NAME. - virtual void MissingSection(const string §ion_name); - - // The CU's DW_AT_stmt_list offset OFFSET is bogus. - virtual void BadLineInfoOffset(uint64 offset); - - // FUNCTION includes code covered by no line number data. - virtual void UncoveredFunction(const Module::Function &function); - - // Line number NUMBER in LINE_FILE, of length LENGTH, includes code - // covered by no function. - virtual void UncoveredLine(const Module::Line &line); - - // The DW_TAG_subprogram DIE at OFFSET has no name specified directly - // in the DIE, nor via a DW_AT_specification or DW_AT_abstract_origin - // link. - virtual void UnnamedFunction(uint64 offset); - - // __cxa_demangle() failed to demangle INPUT. - virtual void DemangleError(const string &input, int error); - - // The DW_FORM_ref_addr at OFFSET to TARGET was not handled because - // FilePrivate did not retain the inter-CU specification data. - virtual void UnhandledInterCUReference(uint64 offset, uint64 target); - - uint64 cu_offset() const { - return cu_offset_; - } - - protected: - const string filename_; - const uint64 cu_offset_; - string cu_name_; - bool printed_cu_header_; - bool printed_unpaired_header_; - bool uncovered_warnings_enabled_; - - private: - // Print a per-CU heading, once. - void CUHeading(); - // Print an unpaired function/line heading, once. - void UncoveredHeading(); - }; - - // Create a DWARF debugging info handler for a compilation unit - // within FILE_CONTEXT. This uses information received from the - // dwarf2reader::CompilationUnit DWARF parser to populate - // FILE_CONTEXT->module. Use LINE_READER to handle the compilation - // unit's line number data. Use REPORTER to report problems with the - // data we find. - DwarfCUToModule(FileContext *file_context, - LineToModuleHandler *line_reader, - WarningReporter *reporter); - ~DwarfCUToModule(); - - void ProcessAttributeSigned(enum DwarfAttribute attr, - enum DwarfForm form, - int64 data); - void ProcessAttributeUnsigned(enum DwarfAttribute attr, - enum DwarfForm form, - uint64 data); - void ProcessAttributeString(enum DwarfAttribute attr, - enum DwarfForm form, - const string &data); - bool EndAttributes(); - DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag); - - // Assign all our source Lines to the Functions that cover their - // addresses, and then add them to module_. - void Finish(); - - bool StartCompilationUnit(uint64 offset, uint8 address_size, - uint8 offset_size, uint64 cu_length, - uint8 dwarf_version); - bool StartRootDIE(uint64 offset, enum DwarfTag tag); - - private: - // Used internally by the handler. Full definitions are in - // dwarf_cu_to_module.cc. - struct CUContext; - struct DIEContext; - struct Specification; - class GenericDIEHandler; - class FuncHandler; - class NamedScopeHandler; - - // A map from section offsets to specifications. - typedef map<uint64, Specification> SpecificationByOffset; - - // Set this compilation unit's source language to LANGUAGE. - void SetLanguage(DwarfLanguage language); - - // Read source line information at OFFSET in the .debug_line - // section. Record source files in module_, but record source lines - // in lines_; we apportion them to functions in - // AssignLinesToFunctions. - void ReadSourceLines(uint64 offset); - - // Assign the lines in lines_ to the individual line lists of the - // functions in functions_. (DWARF line information maps an entire - // compilation unit at a time, and gives no indication of which - // lines belong to which functions, beyond their addresses.) - void AssignLinesToFunctions(); - - // The only reason cu_context_ and child_context_ are pointers is - // that we want to keep their definitions private to - // dwarf_cu_to_module.cc, instead of listing them all here. They are - // owned by this DwarfCUToModule: the constructor sets them, and the - // destructor deletes them. - - // The handler to use to handle line number data. - LineToModuleHandler *line_reader_; - - // This compilation unit's context. - scoped_ptr<CUContext> cu_context_; - - // A context for our children. - scoped_ptr<DIEContext> child_context_; - - // True if this compilation unit has source line information. - bool has_source_line_info_; - - // The offset of this compilation unit's line number information in - // the .debug_line section. - uint64 source_line_offset_; - - // The line numbers we have seen thus far. We accumulate these here - // during parsing. Then, in Finish, we call AssignLinesToFunctions - // to dole them out to the appropriate functions. - vector<Module::Line> lines_; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_DWARF_CU_TO_MODULE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module_unittest.cc deleted file mode 100644 index 619e90a2e..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf_cu_to_module_unittest.cc +++ /dev/null @@ -1,1804 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf_cu_to_module.cc: Unit tests for google_breakpad::DwarfCUToModule. - -#include <stdint.h> - -#include <string> -#include <utility> -#include <vector> - -#include "breakpad_googletest_includes.h" -#include "common/dwarf_cu_to_module.h" -#include "common/using_std_string.h" - -using std::make_pair; -using std::vector; - -using dwarf2reader::DIEHandler; -using dwarf2reader::DwarfTag; -using dwarf2reader::DwarfAttribute; -using dwarf2reader::DwarfForm; -using dwarf2reader::DwarfInline; -using dwarf2reader::RootDIEHandler; -using google_breakpad::DwarfCUToModule; -using google_breakpad::Module; - -using ::testing::_; -using ::testing::AtMost; -using ::testing::Invoke; -using ::testing::Return; -using ::testing::Test; -using ::testing::TestWithParam; -using ::testing::Values; -using ::testing::ValuesIn; - -// Mock classes. - -class MockLineToModuleHandler: public DwarfCUToModule::LineToModuleHandler { - public: - MOCK_METHOD1(StartCompilationUnit, void(const string& compilation_dir)); - MOCK_METHOD4(ReadProgram, void(const uint8_t *program, uint64 length, - Module *module, vector<Module::Line> *lines)); -}; - -class MockWarningReporter: public DwarfCUToModule::WarningReporter { - public: - MockWarningReporter(const string &filename, uint64 cu_offset) - : DwarfCUToModule::WarningReporter(filename, cu_offset) { } - MOCK_METHOD1(SetCUName, void(const string &name)); - MOCK_METHOD2(UnknownSpecification, void(uint64 offset, uint64 target)); - MOCK_METHOD2(UnknownAbstractOrigin, void(uint64 offset, uint64 target)); - MOCK_METHOD1(MissingSection, void(const string §ion_name)); - MOCK_METHOD1(BadLineInfoOffset, void(uint64 offset)); - MOCK_METHOD1(UncoveredFunction, void(const Module::Function &function)); - MOCK_METHOD1(UncoveredLine, void(const Module::Line &line)); - MOCK_METHOD1(UnnamedFunction, void(uint64 offset)); - MOCK_METHOD2(DemangleError, void(const string &input, int error)); - MOCK_METHOD2(UnhandledInterCUReference, void(uint64 offset, uint64 target)); -}; - -// A fixture class including all the objects needed to handle a -// compilation unit, and their entourage. It includes member functions -// for doing common kinds of setup and tests. -class CUFixtureBase { - public: - // If we have: - // - // vector<Module::Line> lines; - // AppendLinesFunctor appender(lines); - // - // then doing: - // - // appender(line_program, length, module, line_vector); - // - // will append lines to the end of line_vector. We can use this with - // MockLineToModuleHandler like this: - // - // MockLineToModuleHandler l2m; - // EXPECT_CALL(l2m, ReadProgram(_,_,_,_)) - // .WillOnce(DoAll(Invoke(appender), Return())); - // - // in which case calling l2m with some line vector will append lines. - class AppendLinesFunctor { - public: - explicit AppendLinesFunctor( - const vector<Module::Line> *lines) : lines_(lines) { } - void operator()(const uint8_t *program, uint64 length, - Module *module, vector<Module::Line> *lines) { - lines->insert(lines->end(), lines_->begin(), lines_->end()); - } - private: - const vector<Module::Line> *lines_; - }; - - CUFixtureBase() - : module_("module-name", "module-os", "module-arch", "module-id"), - file_context_("dwarf-filename", &module_, true), - language_(dwarf2reader::DW_LANG_none), - language_signed_(false), - appender_(&lines_), - reporter_("dwarf-filename", 0xcf8f9bb6443d29b5LL), - root_handler_(&file_context_, &line_reader_, &reporter_), - functions_filled_(false) { - // By default, expect no warnings to be reported, and expect the - // compilation unit's name to be provided. The test can override - // these expectations. - EXPECT_CALL(reporter_, SetCUName("compilation-unit-name")).Times(1); - EXPECT_CALL(reporter_, UnknownSpecification(_, _)).Times(0); - EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, _)).Times(0); - EXPECT_CALL(reporter_, MissingSection(_)).Times(0); - EXPECT_CALL(reporter_, BadLineInfoOffset(_)).Times(0); - EXPECT_CALL(reporter_, UncoveredFunction(_)).Times(0); - EXPECT_CALL(reporter_, UncoveredLine(_)).Times(0); - EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(0); - EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(0); - - // By default, expect the line program reader not to be invoked. We - // may override this in StartCU. - EXPECT_CALL(line_reader_, StartCompilationUnit(_)).Times(0); - EXPECT_CALL(line_reader_, ReadProgram(_,_,_,_)).Times(0); - - // The handler will consult this section map to decide what to - // pass to our line reader. - file_context_.AddSectionToSectionMap(".debug_line", - dummy_line_program_, - dummy_line_size_); - } - - // Add a line with the given address, size, filename, and line - // number to the end of the statement list the handler will receive - // when it invokes its LineToModuleHandler. Call this before calling - // StartCU. - void PushLine(Module::Address address, Module::Address size, - const string &filename, int line_number); - - // Use LANGUAGE for the compilation unit. More precisely, arrange - // for StartCU to pass the compilation unit's root DIE a - // DW_AT_language attribute whose value is LANGUAGE. - void SetLanguage(dwarf2reader::DwarfLanguage language) { - language_ = language; - } - - // If SIGNED true, have StartCU report DW_AT_language as a signed - // attribute; if false, have it report it as unsigned. - void SetLanguageSigned(bool is_signed) { language_signed_ = is_signed; } - - // Call the handler this.root_handler_'s StartCompilationUnit and - // StartRootDIE member functions, passing it appropriate attributes as - // determined by prior calls to PushLine and SetLanguage. Leave - // this.root_handler_ ready to hear about children: call - // this.root_handler_.EndAttributes, but not this.root_handler_.Finish. - void StartCU(); - - // Have HANDLER process some strange attribute/form/value triples. - void ProcessStrangeAttributes(dwarf2reader::DIEHandler *handler); - - // Start a child DIE of PARENT with the given tag and name. Leave - // the handler ready to hear about children: call EndAttributes, but - // not Finish. - DIEHandler *StartNamedDIE(DIEHandler *parent, DwarfTag tag, - const string &name); - - // Start a child DIE of PARENT with the given tag and a - // DW_AT_specification attribute whose value is SPECIFICATION. Leave - // the handler ready to hear about children: call EndAttributes, but - // not Finish. If NAME is non-zero, use it as the DW_AT_name - // attribute. - DIEHandler *StartSpecifiedDIE(DIEHandler *parent, DwarfTag tag, - uint64 specification, const char *name = NULL); - - // Define a function as a child of PARENT with the given name, address, and - // size. If high_pc_form is DW_FORM_addr then the DW_AT_high_pc attribute - // will be written as an address; otherwise it will be written as the - // function's size. Call EndAttributes and Finish; one cannot define - // children of the defined function's DIE. - void DefineFunction(DIEHandler *parent, const string &name, - Module::Address address, Module::Address size, - const char* mangled_name, - DwarfForm high_pc_form = dwarf2reader::DW_FORM_addr); - - // Create a declaration DIE as a child of PARENT with the given - // offset, tag and name. If NAME is the empty string, don't provide - // a DW_AT_name attribute. Call EndAttributes and Finish. - void DeclarationDIE(DIEHandler *parent, uint64 offset, - DwarfTag tag, const string &name, - const string &mangled_name); - - // Create a definition DIE as a child of PARENT with the given tag - // that refers to the declaration DIE at offset SPECIFICATION as its - // specification. If NAME is non-empty, pass it as the DW_AT_name - // attribute. If SIZE is non-zero, record ADDRESS and SIZE as - // low_pc/high_pc attributes. - void DefinitionDIE(DIEHandler *parent, DwarfTag tag, - uint64 specification, const string &name, - Module::Address address = 0, Module::Address size = 0); - - // Create an inline DW_TAG_subprogram DIE as a child of PARENT. If - // SPECIFICATION is non-zero, then the DIE refers to the declaration DIE at - // offset SPECIFICATION as its specification. If Name is non-empty, pass it - // as the DW_AT_name attribute. - void AbstractInstanceDIE(DIEHandler *parent, uint64 offset, - DwarfInline type, uint64 specification, - const string &name, - DwarfForm form = dwarf2reader::DW_FORM_data1); - - // Create a DW_TAG_subprogram DIE as a child of PARENT that refers to - // ORIGIN in its DW_AT_abstract_origin attribute. If NAME is the empty - // string, don't provide a DW_AT_name attribute. - void DefineInlineInstanceDIE(DIEHandler *parent, const string &name, - uint64 origin, Module::Address address, - Module::Address size); - - // The following Test* functions should be called after calling - // this.root_handler_.Finish. After that point, no further calls - // should be made on the handler. - - // Test that the number of functions defined in the module this.module_ is - // equal to EXPECTED. - void TestFunctionCount(size_t expected); - - // Test that the I'th function (ordered by address) in the module - // this.module_ has the given name, address, and size, and that its - // parameter size is zero. - void TestFunction(int i, const string &name, - Module::Address address, Module::Address size); - - // Test that the number of source lines owned by the I'th function - // in the module this.module_ is equal to EXPECTED. - void TestLineCount(int i, size_t expected); - - // Test that the J'th line (ordered by address) of the I'th function - // (again, by address) has the given address, size, filename, and - // line number. - void TestLine(int i, int j, Module::Address address, Module::Address size, - const string &filename, int number); - - // Actual objects under test. - Module module_; - DwarfCUToModule::FileContext file_context_; - - // If this is not DW_LANG_none, we'll pass it as a DW_AT_language - // attribute to the compilation unit. This defaults to DW_LANG_none. - dwarf2reader::DwarfLanguage language_; - - // If this is true, report DW_AT_language as a signed value; if false, - // report it as an unsigned value. - bool language_signed_; - - // If this is not empty, we'll give the CU a DW_AT_comp_dir attribute that - // indicates the path that this compilation unit was compiled in. - string compilation_dir_; - - // If this is not empty, we'll give the CU a DW_AT_stmt_list - // attribute that, when passed to line_reader_, adds these lines to the - // provided lines array. - vector<Module::Line> lines_; - - // Mock line program reader. - MockLineToModuleHandler line_reader_; - AppendLinesFunctor appender_; - static const uint8_t dummy_line_program_[]; - static const size_t dummy_line_size_; - - MockWarningReporter reporter_; - DwarfCUToModule root_handler_; - - private: - // Fill functions_, if we haven't already. - void FillFunctions(); - - // If functions_filled_ is true, this is a table of functions we've - // extracted from module_, sorted by address. - vector<Module::Function *> functions_; - // True if we have filled the above vector with this.module_'s function list. - bool functions_filled_; -}; - -const uint8_t CUFixtureBase::dummy_line_program_[] = "lots of fun data"; -const size_t CUFixtureBase::dummy_line_size_ = - sizeof(CUFixtureBase::dummy_line_program_); - -void CUFixtureBase::PushLine(Module::Address address, Module::Address size, - const string &filename, int line_number) { - Module::Line l; - l.address = address; - l.size = size; - l.file = module_.FindFile(filename); - l.number = line_number; - lines_.push_back(l); -} - -void CUFixtureBase::StartCU() { - if (!compilation_dir_.empty()) - EXPECT_CALL(line_reader_, - StartCompilationUnit(compilation_dir_)).Times(1); - - // If we have lines, make the line reader expect to be invoked at - // most once. (Hey, if the handler can pass its tests without - // bothering to read the line number data, that's great.) - // Have it add the lines passed to PushLine. Otherwise, leave the - // initial expectation (no calls) in force. - if (!lines_.empty()) - EXPECT_CALL(line_reader_, - ReadProgram(&dummy_line_program_[0], dummy_line_size_, - &module_, _)) - .Times(AtMost(1)) - .WillOnce(DoAll(Invoke(appender_), Return())); - - ASSERT_TRUE(root_handler_ - .StartCompilationUnit(0x51182ec307610b51ULL, 0x81, 0x44, - 0x4241b4f33720dd5cULL, 3)); - { - ASSERT_TRUE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL, - dwarf2reader::DW_TAG_compile_unit)); - } - root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - "compilation-unit-name"); - if (!compilation_dir_.empty()) - root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_comp_dir, - dwarf2reader::DW_FORM_strp, - compilation_dir_); - if (!lines_.empty()) - root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list, - dwarf2reader::DW_FORM_ref4, - 0); - if (language_ != dwarf2reader::DW_LANG_none) { - if (language_signed_) - root_handler_.ProcessAttributeSigned(dwarf2reader::DW_AT_language, - dwarf2reader::DW_FORM_sdata, - language_); - else - root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_language, - dwarf2reader::DW_FORM_udata, - language_); - } - ASSERT_TRUE(root_handler_.EndAttributes()); -} - -void CUFixtureBase::ProcessStrangeAttributes( - dwarf2reader::DIEHandler *handler) { - handler->ProcessAttributeUnsigned((DwarfAttribute) 0xf560dead, - (DwarfForm) 0x4106e4db, - 0xa592571997facda1ULL); - handler->ProcessAttributeSigned((DwarfAttribute) 0x85380095, - (DwarfForm) 0x0f16fe87, - 0x12602a4e3bf1f446LL); - handler->ProcessAttributeReference((DwarfAttribute) 0xf7f7480f, - (DwarfForm) 0x829e038a, - 0x50fddef44734fdecULL); - static const uint8_t buffer[10] = "frobynode"; - handler->ProcessAttributeBuffer((DwarfAttribute) 0xa55ffb51, - (DwarfForm) 0x2f43b041, - buffer, sizeof(buffer)); - handler->ProcessAttributeString((DwarfAttribute) 0x2f43b041, - (DwarfForm) 0x895ffa23, - "strange string"); -} - -DIEHandler *CUFixtureBase::StartNamedDIE(DIEHandler *parent, - DwarfTag tag, - const string &name) { - dwarf2reader::DIEHandler *handler - = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag); - if (!handler) - return NULL; - handler->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - ProcessStrangeAttributes(handler); - if (!handler->EndAttributes()) { - handler->Finish(); - delete handler; - return NULL; - } - - return handler; -} - -DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent, - DwarfTag tag, - uint64 specification, - const char *name) { - dwarf2reader::DIEHandler *handler - = parent->FindChildHandler(0x8f4c783c0467c989ULL, tag); - if (!handler) - return NULL; - if (name) - handler->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - handler->ProcessAttributeReference(dwarf2reader::DW_AT_specification, - dwarf2reader::DW_FORM_ref4, - specification); - if (!handler->EndAttributes()) { - handler->Finish(); - delete handler; - return NULL; - } - - return handler; -} - -void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent, - const string &name, Module::Address address, - Module::Address size, - const char* mangled_name, - DwarfForm high_pc_form) { - dwarf2reader::DIEHandler *func - = parent->FindChildHandler(0xe34797c7e68590a8LL, - dwarf2reader::DW_TAG_subprogram); - ASSERT_TRUE(func != NULL); - func->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, - address); - - Module::Address high_pc = size; - if (high_pc_form == dwarf2reader::DW_FORM_addr) { - high_pc += address; - } - func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, - high_pc_form, - high_pc); - - if (mangled_name) - func->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name, - dwarf2reader::DW_FORM_strp, - mangled_name); - - ProcessStrangeAttributes(func); - EXPECT_TRUE(func->EndAttributes()); - func->Finish(); - delete func; -} - -void CUFixtureBase::DeclarationDIE(DIEHandler *parent, uint64 offset, - DwarfTag tag, - const string &name, - const string &mangled_name) { - dwarf2reader::DIEHandler *die = parent->FindChildHandler(offset, tag); - ASSERT_TRUE(die != NULL); - if (!name.empty()) - die->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - if (!mangled_name.empty()) - die->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name, - dwarf2reader::DW_FORM_strp, - mangled_name); - - die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_declaration, - dwarf2reader::DW_FORM_flag, - 1); - EXPECT_TRUE(die->EndAttributes()); - die->Finish(); - delete die; -} - -void CUFixtureBase::DefinitionDIE(DIEHandler *parent, - DwarfTag tag, - uint64 specification, - const string &name, - Module::Address address, - Module::Address size) { - dwarf2reader::DIEHandler *die - = parent->FindChildHandler(0x6ccfea031a9e6cc9ULL, tag); - ASSERT_TRUE(die != NULL); - die->ProcessAttributeReference(dwarf2reader::DW_AT_specification, - dwarf2reader::DW_FORM_ref4, - specification); - if (!name.empty()) - die->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - if (size) { - die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, - address); - die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, - dwarf2reader::DW_FORM_addr, - address + size); - } - EXPECT_TRUE(die->EndAttributes()); - die->Finish(); - delete die; -} - -void CUFixtureBase::AbstractInstanceDIE(DIEHandler *parent, - uint64 offset, - DwarfInline type, - uint64 specification, - const string &name, - DwarfForm form) { - dwarf2reader::DIEHandler *die - = parent->FindChildHandler(offset, dwarf2reader::DW_TAG_subprogram); - ASSERT_TRUE(die != NULL); - if (specification != 0ULL) - die->ProcessAttributeReference(dwarf2reader::DW_AT_specification, - dwarf2reader::DW_FORM_ref4, - specification); - if (form == dwarf2reader::DW_FORM_sdata) { - die->ProcessAttributeSigned(dwarf2reader::DW_AT_inline, form, type); - } else { - die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_inline, form, type); - } - if (!name.empty()) - die->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - - EXPECT_TRUE(die->EndAttributes()); - die->Finish(); - delete die; -} - -void CUFixtureBase::DefineInlineInstanceDIE(DIEHandler *parent, - const string &name, - uint64 origin, - Module::Address address, - Module::Address size) { - dwarf2reader::DIEHandler *func - = parent->FindChildHandler(0x11c70f94c6e87ccdLL, - dwarf2reader::DW_TAG_subprogram); - ASSERT_TRUE(func != NULL); - if (!name.empty()) { - func->ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - name); - } - func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_low_pc, - dwarf2reader::DW_FORM_addr, - address); - func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc, - dwarf2reader::DW_FORM_addr, - address + size); - func->ProcessAttributeReference(dwarf2reader::DW_AT_abstract_origin, - dwarf2reader::DW_FORM_ref4, - origin); - ProcessStrangeAttributes(func); - EXPECT_TRUE(func->EndAttributes()); - func->Finish(); - delete func; -} - -void CUFixtureBase::FillFunctions() { - if (functions_filled_) - return; - module_.GetFunctions(&functions_, functions_.end()); - sort(functions_.begin(), functions_.end(), - Module::Function::CompareByAddress); - functions_filled_ = true; -} - -void CUFixtureBase::TestFunctionCount(size_t expected) { - FillFunctions(); - ASSERT_EQ(expected, functions_.size()); -} - -void CUFixtureBase::TestFunction(int i, const string &name, - Module::Address address, - Module::Address size) { - FillFunctions(); - ASSERT_LT((size_t) i, functions_.size()); - - Module::Function *function = functions_[i]; - EXPECT_EQ(name, function->name); - EXPECT_EQ(address, function->address); - EXPECT_EQ(size, function->size); - EXPECT_EQ(0U, function->parameter_size); -} - -void CUFixtureBase::TestLineCount(int i, size_t expected) { - FillFunctions(); - ASSERT_LT((size_t) i, functions_.size()); - - ASSERT_EQ(expected, functions_[i]->lines.size()); -} - -void CUFixtureBase::TestLine(int i, int j, - Module::Address address, Module::Address size, - const string &filename, int number) { - FillFunctions(); - ASSERT_LT((size_t) i, functions_.size()); - ASSERT_LT((size_t) j, functions_[i]->lines.size()); - - Module::Line *line = &functions_[i]->lines[j]; - EXPECT_EQ(address, line->address); - EXPECT_EQ(size, line->size); - EXPECT_EQ(filename, line->file->name.c_str()); - EXPECT_EQ(number, line->number); -} - -// Include caller locations for our test subroutines. -#define TRACE(call) do { SCOPED_TRACE("called from here"); call; } while (0) -#define PushLine(a,b,c,d) TRACE(PushLine((a),(b),(c),(d))) -#define SetLanguage(a) TRACE(SetLanguage(a)) -#define StartCU() TRACE(StartCU()) -#define DefineFunction(a,b,c,d,e) TRACE(DefineFunction((a),(b),(c),(d),(e))) -// (DefineFunction) instead of DefineFunction to avoid macro expansion. -#define DefineFunction6(a,b,c,d,e,f) \ - TRACE((DefineFunction)((a),(b),(c),(d),(e),(f))) -#define DeclarationDIE(a,b,c,d,e) TRACE(DeclarationDIE((a),(b),(c),(d),(e))) -#define DefinitionDIE(a,b,c,d,e,f) \ - TRACE(DefinitionDIE((a),(b),(c),(d),(e),(f))) -#define TestFunctionCount(a) TRACE(TestFunctionCount(a)) -#define TestFunction(a,b,c,d) TRACE(TestFunction((a),(b),(c),(d))) -#define TestLineCount(a,b) TRACE(TestLineCount((a),(b))) -#define TestLine(a,b,c,d,e,f) TRACE(TestLine((a),(b),(c),(d),(e),(f))) - -class SimpleCU: public CUFixtureBase, public Test { -}; - -TEST_F(SimpleCU, CompilationDir) { - compilation_dir_ = "/src/build/"; - - StartCU(); - root_handler_.Finish(); -} - -TEST_F(SimpleCU, OneFunc) { - PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772); - - StartCU(); - DefineFunction(&root_handler_, "function1", - 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); - TestLineCount(0, 1); - TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", - 246571772); -} - -// As above, only DW_AT_high_pc is a length rather than an address. -TEST_F(SimpleCU, OneFuncHighPcIsLength) { - PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772); - - StartCU(); - DefineFunction6(&root_handler_, "function1", - 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL, - dwarf2reader::DW_FORM_udata); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "function1", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); - TestLineCount(0, 1); - TestLine(0, 0, 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", - 246571772); -} - -TEST_F(SimpleCU, MangledName) { - PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772); - - StartCU(); - DefineFunction(&root_handler_, "function1", - 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "_ZN1n1fEi"); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "n::f(int)", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL); -} - -TEST_F(SimpleCU, IrrelevantRootChildren) { - StartCU(); - EXPECT_FALSE(root_handler_ - .FindChildHandler(0x7db32bff4e2dcfb1ULL, - dwarf2reader::DW_TAG_lexical_block)); -} - -TEST_F(SimpleCU, IrrelevantNamedScopeChildren) { - StartCU(); - DIEHandler *class_A_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); - EXPECT_TRUE(class_A_handler != NULL); - EXPECT_FALSE(class_A_handler - ->FindChildHandler(0x02e55999b865e4e9ULL, - dwarf2reader::DW_TAG_lexical_block)); - delete class_A_handler; -} - -// Verify that FileContexts can safely be deleted unused. -TEST_F(SimpleCU, UnusedFileContext) { - Module m("module-name", "module-os", "module-arch", "module-id"); - DwarfCUToModule::FileContext fc("dwarf-filename", &m, true); - - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); -} - -TEST_F(SimpleCU, InlineFunction) { - PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); - - StartCU(); - AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0, "inline-name"); - DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "inline-name", - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); -} - -TEST_F(SimpleCU, InlineFunctionSignedAttribute) { - PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); - - StartCU(); - AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0, "inline-name", - dwarf2reader::DW_FORM_sdata); - DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "inline-name", - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); -} - -// Any DIE with an DW_AT_inline attribute can be cited by -// DW_AT_abstract_origin attributes --- even if the value of the -// DW_AT_inline attribute is DW_INL_not_inlined. -TEST_F(SimpleCU, AbstractOriginNotInlined) { - PushLine(0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL, "line-file", 6111581); - - StartCU(); - AbstractInstanceDIE(&root_handler_, 0x93e9cdad52826b39ULL, - dwarf2reader::DW_INL_not_inlined, 0, "abstract-instance"); - DefineInlineInstanceDIE(&root_handler_, "", 0x93e9cdad52826b39ULL, - 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "abstract-instance", - 0x2805c4531be6ca0eULL, 0x686b52155a8d4d2cULL); -} - -TEST_F(SimpleCU, UnknownAbstractOrigin) { - EXPECT_CALL(reporter_, UnknownAbstractOrigin(_, 1ULL)).WillOnce(Return()); - EXPECT_CALL(reporter_, UnnamedFunction(0x11c70f94c6e87ccdLL)) - .WillOnce(Return()); - PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); - - StartCU(); - AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0, "inline-name"); - DefineInlineInstanceDIE(&root_handler_, "", 1ULL, - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "<name omitted>", - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); -} - -TEST_F(SimpleCU, UnnamedFunction) { - EXPECT_CALL(reporter_, UnnamedFunction(0xe34797c7e68590a8LL)) - .WillOnce(Return()); - PushLine(0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, "line-file", 14044850); - - StartCU(); - DefineFunction(&root_handler_, "", - 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, NULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "<name omitted>", - 0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL); -} - -// An address range. -struct Range { - Module::Address start, end; -}; - -// Test data for pairing functions and lines. -struct Situation { - // Two function intervals, and two line intervals. - Range functions[2], lines[2]; - - // The number of lines we expect to be assigned to each of the - // functions, and the address ranges. - int paired_count[2]; - Range paired[2][2]; - - // The number of functions that are not entirely covered by lines, - // and vice versa. - int uncovered_functions, uncovered_lines; -}; - -#define PAIRING(func1_start, func1_end, func2_start, func2_end, \ - line1_start, line1_end, line2_start, line2_end, \ - func1_num_lines, func2_num_lines, \ - func1_line1_start, func1_line1_end, \ - func1_line2_start, func1_line2_end, \ - func2_line1_start, func2_line1_end, \ - func2_line2_start, func2_line2_end, \ - uncovered_functions, uncovered_lines) \ - { { { func1_start, func1_end }, { func2_start, func2_end } }, \ - { { line1_start, line1_end }, { line2_start, line2_end } }, \ - { func1_num_lines, func2_num_lines }, \ - { { { func1_line1_start, func1_line1_end }, \ - { func1_line2_start, func1_line2_end } }, \ - { { func2_line1_start, func2_line1_end }, \ - { func2_line2_start, func2_line2_end } } }, \ - uncovered_functions, uncovered_lines }, - -Situation situations[] = { -#include "common/testdata/func-line-pairing.h" -}; - -#undef PAIRING - -class FuncLinePairing: public CUFixtureBase, - public TestWithParam<Situation> { }; - -INSTANTIATE_TEST_CASE_P(AllSituations, FuncLinePairing, - ValuesIn(situations)); - -TEST_P(FuncLinePairing, Pairing) { - const Situation &s = GetParam(); - PushLine(s.lines[0].start, - s.lines[0].end - s.lines[0].start, - "line-file", 67636963); - PushLine(s.lines[1].start, - s.lines[1].end - s.lines[1].start, - "line-file", 67636963); - if (s.uncovered_functions) - EXPECT_CALL(reporter_, UncoveredFunction(_)) - .Times(s.uncovered_functions) - .WillRepeatedly(Return()); - if (s.uncovered_lines) - EXPECT_CALL(reporter_, UncoveredLine(_)) - .Times(s.uncovered_lines) - .WillRepeatedly(Return()); - - StartCU(); - DefineFunction(&root_handler_, "function1", - s.functions[0].start, - s.functions[0].end - s.functions[0].start, NULL); - DefineFunction(&root_handler_, "function2", - s.functions[1].start, - s.functions[1].end - s.functions[1].start, NULL); - root_handler_.Finish(); - - TestFunctionCount(2); - TestFunction(0, "function1", - s.functions[0].start, - s.functions[0].end - s.functions[0].start); - TestLineCount(0, s.paired_count[0]); - for (int i = 0; i < s.paired_count[0]; i++) - TestLine(0, i, s.paired[0][i].start, - s.paired[0][i].end - s.paired[0][i].start, - "line-file", 67636963); - TestFunction(1, "function2", - s.functions[1].start, - s.functions[1].end - s.functions[1].start); - TestLineCount(1, s.paired_count[1]); - for (int i = 0; i < s.paired_count[1]; i++) - TestLine(1, i, s.paired[1][i].start, - s.paired[1][i].end - s.paired[1][i].start, - "line-file", 67636963); -} - -TEST_F(FuncLinePairing, EmptyCU) { - StartCU(); - root_handler_.Finish(); - - TestFunctionCount(0); -} - -TEST_F(FuncLinePairing, LinesNoFuncs) { - PushLine(40, 2, "line-file", 82485646); - EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); - - StartCU(); - root_handler_.Finish(); - - TestFunctionCount(0); -} - -TEST_F(FuncLinePairing, FuncsNoLines) { - EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); - - StartCU(); - DefineFunction(&root_handler_, "function1", 0x127da12ffcf5c51fULL, 0x1000U, - NULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "function1", 0x127da12ffcf5c51fULL, 0x1000U); -} - -TEST_F(FuncLinePairing, GapThenFunction) { - PushLine(20, 2, "line-file-2", 174314698); - PushLine(10, 2, "line-file-1", 263008005); - - StartCU(); - DefineFunction(&root_handler_, "function1", 10, 2, NULL); - DefineFunction(&root_handler_, "function2", 20, 2, NULL); - root_handler_.Finish(); - - TestFunctionCount(2); - TestFunction(0, "function1", 10, 2); - TestLineCount(0, 1); - TestLine(0, 0, 10, 2, "line-file-1", 263008005); - TestFunction(1, "function2", 20, 2); - TestLineCount(1, 1); - TestLine(1, 0, 20, 2, "line-file-2", 174314698); -} - -// If GCC emits padding after one function to align the start of -// the next, then it will attribute the padding instructions to -// the last source line of function (to reduce the size of the -// line number info), but omit it from the DW_AT_{low,high}_pc -// range given in .debug_info (since it costs nothing to be -// precise there). If we did use at least some of the line -// we're about to skip, then assume this is what happened, and -// don't warn. -TEST_F(FuncLinePairing, GCCAlignmentStretch) { - PushLine(10, 10, "line-file", 63351048); - PushLine(20, 10, "line-file", 61661044); - - StartCU(); - DefineFunction(&root_handler_, "function1", 10, 5, NULL); - // five-byte gap between functions, covered by line 63351048. - // This should not elicit a warning. - DefineFunction(&root_handler_, "function2", 20, 10, NULL); - root_handler_.Finish(); - - TestFunctionCount(2); - TestFunction(0, "function1", 10, 5); - TestLineCount(0, 1); - TestLine(0, 0, 10, 5, "line-file", 63351048); - TestFunction(1, "function2", 20, 10); - TestLineCount(1, 1); - TestLine(1, 0, 20, 10, "line-file", 61661044); -} - -// Unfortunately, neither the DWARF parser's handler interface nor the -// DIEHandler interface is capable of expressing a function that abuts -// the end of the address space: the high_pc value looks like zero. - -TEST_F(FuncLinePairing, LineAtEndOfAddressSpace) { - PushLine(0xfffffffffffffff0ULL, 16, "line-file", 63351048); - EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); - - StartCU(); - DefineFunction(&root_handler_, "function1", 0xfffffffffffffff0ULL, 6, NULL); - DefineFunction(&root_handler_, "function2", 0xfffffffffffffffaULL, 5, NULL); - root_handler_.Finish(); - - TestFunctionCount(2); - TestFunction(0, "function1", 0xfffffffffffffff0ULL, 6); - TestLineCount(0, 1); - TestLine(0, 0, 0xfffffffffffffff0ULL, 6, "line-file", 63351048); - TestFunction(1, "function2", 0xfffffffffffffffaULL, 5); - TestLineCount(1, 1); - TestLine(1, 0, 0xfffffffffffffffaULL, 5, "line-file", 63351048); -} - -// A function with more than one uncovered area should only be warned -// about once. -TEST_F(FuncLinePairing, WarnOnceFunc) { - PushLine(20, 1, "line-file-2", 262951329); - PushLine(11, 1, "line-file-1", 219964021); - EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); - - StartCU(); - DefineFunction(&root_handler_, "function", 10, 11, NULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "function", 10, 11); - TestLineCount(0, 2); - TestLine(0, 0, 11, 1, "line-file-1", 219964021); - TestLine(0, 1, 20, 1, "line-file-2", 262951329); -} - -// A line with more than one uncovered area should only be warned -// about once. -TEST_F(FuncLinePairing, WarnOnceLine) { - PushLine(10, 20, "filename1", 118581871); - EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return()); - - StartCU(); - DefineFunction(&root_handler_, "function1", 11, 1, NULL); - DefineFunction(&root_handler_, "function2", 13, 1, NULL); - root_handler_.Finish(); - - TestFunctionCount(2); - TestFunction(0, "function1", 11, 1); - TestLineCount(0, 1); - TestLine(0, 0, 11, 1, "filename1", 118581871); - TestFunction(1, "function2", 13, 1); - TestLineCount(1, 1); - TestLine(1, 0, 13, 1, "filename1", 118581871); -} - -class CXXQualifiedNames: public CUFixtureBase, - public TestWithParam<DwarfTag> { }; - -INSTANTIATE_TEST_CASE_P(VersusEnclosures, CXXQualifiedNames, - Values(dwarf2reader::DW_TAG_class_type, - dwarf2reader::DW_TAG_structure_type, - dwarf2reader::DW_TAG_union_type, - dwarf2reader::DW_TAG_namespace)); - -TEST_P(CXXQualifiedNames, TwoFunctions) { - DwarfTag tag = GetParam(); - - SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); - PushLine(10, 1, "filename1", 69819327); - PushLine(20, 1, "filename2", 95115701); - - StartCU(); - DIEHandler *enclosure_handler = StartNamedDIE(&root_handler_, tag, - "Enclosure"); - EXPECT_TRUE(enclosure_handler != NULL); - DefineFunction(enclosure_handler, "func_B", 10, 1, NULL); - DefineFunction(enclosure_handler, "func_C", 20, 1, NULL); - enclosure_handler->Finish(); - delete enclosure_handler; - root_handler_.Finish(); - - TestFunctionCount(2); - TestFunction(0, "Enclosure::func_B", 10, 1); - TestFunction(1, "Enclosure::func_C", 20, 1); -} - -TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) { - DwarfTag tag = GetParam(); - - SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); - PushLine(10, 1, "line-file", 69819327); - - StartCU(); - DIEHandler *namespace_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, - "Namespace"); - EXPECT_TRUE(namespace_handler != NULL); - DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag, - "Enclosure"); - EXPECT_TRUE(enclosure_handler != NULL); - DefineFunction(enclosure_handler, "function", 10, 1, NULL); - enclosure_handler->Finish(); - delete enclosure_handler; - namespace_handler->Finish(); - delete namespace_handler; - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "Namespace::Enclosure::function", 10, 1); -} - -TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) { - SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); - PushLine(10, 1, "filename1", 69819327); - - StartCU(); - DIEHandler *namespace_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, - "namespace_A"); - EXPECT_TRUE(namespace_handler != NULL); - DIEHandler *struct_handler - = StartNamedDIE(namespace_handler, dwarf2reader::DW_TAG_structure_type, - "struct_B"); - EXPECT_TRUE(struct_handler != NULL); - DIEHandler *class_handler - = StartNamedDIE(struct_handler, dwarf2reader::DW_TAG_class_type, - "class_C"); - DefineFunction(class_handler, "function_D", 10, 1, NULL); - class_handler->Finish(); - delete class_handler; - struct_handler->Finish(); - delete struct_handler; - namespace_handler->Finish(); - delete namespace_handler; - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "namespace_A::struct_B::class_C::function_D", 10, 1); -} - -struct LanguageAndQualifiedName { - dwarf2reader::DwarfLanguage language; - const char *name; -}; - -const LanguageAndQualifiedName LanguageAndQualifiedNameCases[] = { - { dwarf2reader::DW_LANG_none, "class_A::function_B" }, - { dwarf2reader::DW_LANG_C, "class_A::function_B" }, - { dwarf2reader::DW_LANG_C89, "class_A::function_B" }, - { dwarf2reader::DW_LANG_C99, "class_A::function_B" }, - { dwarf2reader::DW_LANG_C_plus_plus, "class_A::function_B" }, - { dwarf2reader::DW_LANG_Java, "class_A.function_B" }, - { dwarf2reader::DW_LANG_Cobol74, "class_A::function_B" }, - { dwarf2reader::DW_LANG_Mips_Assembler, NULL } -}; - -class QualifiedForLanguage - : public CUFixtureBase, - public TestWithParam<LanguageAndQualifiedName> { }; - -INSTANTIATE_TEST_CASE_P(LanguageAndQualifiedName, QualifiedForLanguage, - ValuesIn(LanguageAndQualifiedNameCases)); - -TEST_P(QualifiedForLanguage, MemberFunction) { - const LanguageAndQualifiedName ¶m = GetParam(); - - PushLine(10, 1, "line-file", 212966758); - SetLanguage(param.language); - - StartCU(); - DIEHandler *class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - "class_A"); - DefineFunction(class_handler, "function_B", 10, 1, NULL); - class_handler->Finish(); - delete class_handler; - root_handler_.Finish(); - - if (param.name) { - TestFunctionCount(1); - TestFunction(0, param.name, 10, 1); - } else { - TestFunctionCount(0); - } -} - -TEST_P(QualifiedForLanguage, MemberFunctionSignedLanguage) { - const LanguageAndQualifiedName ¶m = GetParam(); - - PushLine(10, 1, "line-file", 212966758); - SetLanguage(param.language); - SetLanguageSigned(true); - - StartCU(); - DIEHandler *class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - "class_A"); - DefineFunction(class_handler, "function_B", 10, 1, NULL); - class_handler->Finish(); - delete class_handler; - root_handler_.Finish(); - - if (param.name) { - TestFunctionCount(1); - TestFunction(0, param.name, 10, 1); - } else { - TestFunctionCount(0); - } -} - -class Specifications: public CUFixtureBase, public Test { }; - -TEST_F(Specifications, Function) { - PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661); - - StartCU(); - DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, - dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0xcd3c51b946fb1eeeLL, "", - 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "declaration-name", - 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); -} - -TEST_F(Specifications, MangledName) { - PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661); - - StartCU(); - DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, - dwarf2reader::DW_TAG_subprogram, "declaration-name", - "_ZN1C1fEi"); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0xcd3c51b946fb1eeeLL, "", - 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "C::f(int)", - 0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL); -} - -TEST_F(Specifications, MemberFunction) { - PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691); - - StartCU(); - DIEHandler *class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A"); - DeclarationDIE(class_handler, 0x7d83028c431406e8ULL, - dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); - class_handler->Finish(); - delete class_handler; - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0x7d83028c431406e8ULL, "", - 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "class_A::declaration-name", - 0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL); -} - -// This case should gather the name from both the definition and the -// declaration's parent. -TEST_F(Specifications, FunctionDeclarationParent) { - PushLine(0x463c9ddf405be227ULL, 0x6a47774af5049680ULL, "line-file", 70254922); - - StartCU(); - { - DIEHandler *class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - "class_A"); - ASSERT_TRUE(class_handler != NULL); - DeclarationDIE(class_handler, 0x0e0e877c8404544aULL, - dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); - class_handler->Finish(); - delete class_handler; - } - - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0x0e0e877c8404544aULL, "definition-name", - 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL); - - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "class_A::definition-name", - 0x463c9ddf405be227ULL, 0x6a47774af5049680ULL); -} - -// Named scopes should also gather enclosing name components from -// their declarations. -TEST_F(Specifications, NamedScopeDeclarationParent) { - PushLine(0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, "line-file", 77392604); - - StartCU(); - { - DIEHandler *space_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, - "space_A"); - ASSERT_TRUE(space_handler != NULL); - DeclarationDIE(space_handler, 0x419bb1d12f9a73a2ULL, - dwarf2reader::DW_TAG_class_type, "class-declaration-name", - ""); - space_handler->Finish(); - delete space_handler; - } - - { - DIEHandler *class_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - 0x419bb1d12f9a73a2ULL, "class-definition-name"); - ASSERT_TRUE(class_handler != NULL); - DefineFunction(class_handler, "function", - 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, NULL); - class_handler->Finish(); - delete class_handler; - } - - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "space_A::class-definition-name::function", - 0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL); -} - -// This test recreates bug 364. -TEST_F(Specifications, InlineFunction) { - PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); - - StartCU(); - DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL, - dwarf2reader::DW_TAG_subprogram, "inline-name", ""); - AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, ""); - DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL, - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "inline-name", - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); -} - -// An inline function in a namespace should correctly derive its -// name from its abstract origin, and not just the namespace name. -TEST_F(Specifications, InlineFunctionInNamespace) { - PushLine(0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL, "line-file", 75173118); - - StartCU(); - DIEHandler* space_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, - "Namespace"); - ASSERT_TRUE(space_handler != NULL); - AbstractInstanceDIE(space_handler, 0x1e8dac5d507ed7abULL, - dwarf2reader::DW_INL_inlined, 0LL, "func-name"); - DefineInlineInstanceDIE(space_handler, "", 0x1e8dac5d507ed7abULL, - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); - space_handler->Finish(); - delete space_handler; - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "Namespace::func-name", - 0x1758a0f941b71efbULL, 0x1cf154f1f545e146ULL); -} - -// Check name construction for a long chain containing each combination of: -// - struct, union, class, namespace -// - direct and definition -TEST_F(Specifications, LongChain) { - PushLine(0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL, "line-file", 21192926); - SetLanguage(dwarf2reader::DW_LANG_C_plus_plus); - - StartCU(); - // The structure we're building here is: - // space_A full definition - // space_B declaration - // space_B definition - // struct_C full definition - // struct_D declaration - // struct_D definition - // union_E full definition - // union_F declaration - // union_F definition - // class_G full definition - // class_H declaration - // class_H definition - // func_I declaration - // func_I definition - // - // So: - // - space_A, struct_C, union_E, and class_G don't use specifications; - // - space_B, struct_D, union_F, and class_H do. - // - func_I uses a specification. - // - // The full name for func_I is thus: - // - // space_A::space_B::struct_C::struct_D::union_E::union_F:: - // class_G::class_H::func_I - { - DIEHandler *space_A_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, - "space_A"); - DeclarationDIE(space_A_handler, 0x2e111126496596e2ULL, - dwarf2reader::DW_TAG_namespace, "space_B", ""); - space_A_handler->Finish(); - delete space_A_handler; - } - - { - DIEHandler *space_B_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace, - 0x2e111126496596e2ULL); - DIEHandler *struct_C_handler - = StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type, - "struct_C"); - DeclarationDIE(struct_C_handler, 0x20cd423bf2a25a4cULL, - dwarf2reader::DW_TAG_structure_type, "struct_D", ""); - struct_C_handler->Finish(); - delete struct_C_handler; - space_B_handler->Finish(); - delete space_B_handler; - } - - { - DIEHandler *struct_D_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_structure_type, - 0x20cd423bf2a25a4cULL); - DIEHandler *union_E_handler - = StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type, - "union_E"); - DeclarationDIE(union_E_handler, 0xe25c84805aa58c32ULL, - dwarf2reader::DW_TAG_union_type, "union_F", ""); - union_E_handler->Finish(); - delete union_E_handler; - struct_D_handler->Finish(); - delete struct_D_handler; - } - - { - DIEHandler *union_F_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_union_type, - 0xe25c84805aa58c32ULL); - DIEHandler *class_G_handler - = StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type, - "class_G"); - DeclarationDIE(class_G_handler, 0xb70d960dcc173b6eULL, - dwarf2reader::DW_TAG_class_type, "class_H", ""); - class_G_handler->Finish(); - delete class_G_handler; - union_F_handler->Finish(); - delete union_F_handler; - } - - { - DIEHandler *class_H_handler - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - 0xb70d960dcc173b6eULL); - DeclarationDIE(class_H_handler, 0x27ff829e3bf69f37ULL, - dwarf2reader::DW_TAG_subprogram, "func_I", ""); - class_H_handler->Finish(); - delete class_H_handler; - } - - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0x27ff829e3bf69f37ULL, "", - 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "space_A::space_B::struct_C::struct_D::union_E::union_F" - "::class_G::class_H::func_I", - 0x5a0dd6bb85db754cULL, 0x3bccb213d08c7fd3ULL); -} - -TEST_F(Specifications, InterCU) { - Module m("module-name", "module-os", "module-arch", "module-id"); - DwarfCUToModule::FileContext fc("dwarf-filename", &m, true); - EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); - MockLineToModuleHandler lr; - EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0); - - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); - - // First CU. Declares class_A. - { - DwarfCUToModule root1_handler(&fc, &lr, &reporter_); - ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); - ASSERT_TRUE(root1_handler.StartRootDIE(1, - dwarf2reader::DW_TAG_compile_unit)); - ProcessStrangeAttributes(&root1_handler); - ASSERT_TRUE(root1_handler.EndAttributes()); - DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL, - dwarf2reader::DW_TAG_class_type, "class_A", ""); - root1_handler.Finish(); - } - - // Second CU. Defines class_A, declares member_func_B. - { - DwarfCUToModule root2_handler(&fc, &lr, &reporter_); - ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); - ASSERT_TRUE(root2_handler.StartRootDIE(1, - dwarf2reader::DW_TAG_compile_unit)); - ASSERT_TRUE(root2_handler.EndAttributes()); - DIEHandler *class_A_handler - = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type, - 0xb8fbfdd5f0b26fceULL); - DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL, - dwarf2reader::DW_TAG_subprogram, "member_func_B", ""); - class_A_handler->Finish(); - delete class_A_handler; - root2_handler.Finish(); - } - - // Third CU. Defines member_func_B. - { - DwarfCUToModule root3_handler(&fc, &lr, &reporter_); - ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); - ASSERT_TRUE(root3_handler.StartRootDIE(1, - dwarf2reader::DW_TAG_compile_unit)); - ASSERT_TRUE(root3_handler.EndAttributes()); - DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram, - 0xb01fef8b380bd1a2ULL, "", - 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL); - root3_handler.Finish(); - } - - vector<Module::Function *> functions; - m.GetFunctions(&functions, functions.end()); - EXPECT_EQ(1U, functions.size()); - EXPECT_STREQ("class_A::member_func_B", functions[0]->name.c_str()); -} - -TEST_F(Specifications, UnhandledInterCU) { - Module m("module-name", "module-os", "module-arch", "module-id"); - DwarfCUToModule::FileContext fc("dwarf-filename", &m, false); - EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return()); - MockLineToModuleHandler lr; - EXPECT_CALL(lr, ReadProgram(_,_,_,_)).Times(0); - - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); - - // First CU. Declares class_A. - { - DwarfCUToModule root1_handler(&fc, &lr, &reporter_); - ASSERT_TRUE(root1_handler.StartCompilationUnit(0, 1, 2, 3, 3)); - ASSERT_TRUE(root1_handler.StartRootDIE(1, - dwarf2reader::DW_TAG_compile_unit)); - ProcessStrangeAttributes(&root1_handler); - ASSERT_TRUE(root1_handler.EndAttributes()); - DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL, - dwarf2reader::DW_TAG_class_type, "class_A", ""); - root1_handler.Finish(); - } - - // Second CU. Defines class_A, declares member_func_B. - { - DwarfCUToModule root2_handler(&fc, &lr, &reporter_); - ASSERT_TRUE(root2_handler.StartCompilationUnit(0, 1, 2, 3, 3)); - ASSERT_TRUE(root2_handler.StartRootDIE(1, - dwarf2reader::DW_TAG_compile_unit)); - ASSERT_TRUE(root2_handler.EndAttributes()); - EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1); - DIEHandler *class_A_handler - = StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type, - 0xb8fbfdd5f0b26fceULL); - DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL, - dwarf2reader::DW_TAG_subprogram, "member_func_B", ""); - class_A_handler->Finish(); - delete class_A_handler; - root2_handler.Finish(); - } - - // Third CU. Defines member_func_B. - { - DwarfCUToModule root3_handler(&fc, &lr, &reporter_); - ASSERT_TRUE(root3_handler.StartCompilationUnit(0, 1, 2, 3, 3)); - ASSERT_TRUE(root3_handler.StartRootDIE(1, - dwarf2reader::DW_TAG_compile_unit)); - ASSERT_TRUE(root3_handler.EndAttributes()); - EXPECT_CALL(reporter_, UnhandledInterCUReference(_, _)).Times(1); - EXPECT_CALL(reporter_, UnnamedFunction(_)).Times(1); - DefinitionDIE(&root3_handler, dwarf2reader::DW_TAG_subprogram, - 0xb01fef8b380bd1a2ULL, "", - 0x2618f00a1a711e53ULL, 0x4fd94b76d7c2caf5ULL); - root3_handler.Finish(); - } -} - -TEST_F(Specifications, BadOffset) { - PushLine(0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL, "line-file", 56636272); - EXPECT_CALL(reporter_, UnknownSpecification(_, 0x2be953efa6f9a996ULL)) - .WillOnce(Return()); - - StartCU(); - DeclarationDIE(&root_handler_, 0xefd7f7752c27b7e4ULL, - dwarf2reader::DW_TAG_subprogram, "", ""); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0x2be953efa6f9a996ULL, "function", - 0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL); - root_handler_.Finish(); -} - -TEST_F(Specifications, FunctionDefinitionHasOwnName) { - PushLine(0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL, "line-file", 56792403); - - StartCU(); - DeclarationDIE(&root_handler_, 0xc34ff4786cae78bdULL, - dwarf2reader::DW_TAG_subprogram, "declaration-name", ""); - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0xc34ff4786cae78bdULL, "definition-name", - 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL); - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "definition-name", - 0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL); -} - -TEST_F(Specifications, ClassDefinitionHasOwnName) { - PushLine(0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL, "line-file", 57119241); - - StartCU(); - DeclarationDIE(&root_handler_, 0xd0fe467ec2f1a58cULL, - dwarf2reader::DW_TAG_class_type, "class-declaration-name", ""); - - dwarf2reader::DIEHandler *class_definition - = StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - 0xd0fe467ec2f1a58cULL, "class-definition-name"); - ASSERT_TRUE(class_definition); - DeclarationDIE(class_definition, 0x6d028229c15623dbULL, - dwarf2reader::DW_TAG_subprogram, - "function-declaration-name", ""); - class_definition->Finish(); - delete class_definition; - - DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram, - 0x6d028229c15623dbULL, "function-definition-name", - 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL); - - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "class-definition-name::function-definition-name", - 0x1d0f5e0f6ce309bdULL, 0x654e1852ec3599e7ULL); -} - -// DIEs that cite a specification should prefer the specification's -// parents over their own when choosing qualified names. In this test, -// we take the name from our definition but the enclosing scope name -// from our declaration. I don't see why they'd ever be different, but -// we want to verify what DwarfCUToModule is looking at. -TEST_F(Specifications, PreferSpecificationParents) { - PushLine(0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL, "line-file", 79488694); - - StartCU(); - { - dwarf2reader::DIEHandler *declaration_class_handler = - StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - "declaration-class"); - DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL, - dwarf2reader::DW_TAG_subprogram, "function-declaration", - ""); - declaration_class_handler->Finish(); - delete declaration_class_handler; - } - { - dwarf2reader::DIEHandler *definition_class_handler - = StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, - "definition-class"); - DefinitionDIE(definition_class_handler, dwarf2reader::DW_TAG_subprogram, - 0x9ddb35517455ef7aULL, "function-definition", - 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL); - definition_class_handler->Finish(); - delete definition_class_handler; - } - root_handler_.Finish(); - - TestFunctionCount(1); - TestFunction(0, "declaration-class::function-definition", - 0xbbd9d54dce3b95b7ULL, 0x39188b7b52b0899fULL); -} - -class CUErrors: public CUFixtureBase, public Test { }; - -TEST_F(CUErrors, BadStmtList) { - EXPECT_CALL(reporter_, BadLineInfoOffset(dummy_line_size_ + 10)).Times(1); - - ASSERT_TRUE(root_handler_ - .StartCompilationUnit(0xc591d5b037543d7cULL, 0x11, 0xcd, - 0x2d7d19546cf6590cULL, 3)); - ASSERT_TRUE(root_handler_.StartRootDIE(0xae789dc102cfca54ULL, - dwarf2reader::DW_TAG_compile_unit)); - root_handler_.ProcessAttributeString(dwarf2reader::DW_AT_name, - dwarf2reader::DW_FORM_strp, - "compilation-unit-name"); - root_handler_.ProcessAttributeUnsigned(dwarf2reader::DW_AT_stmt_list, - dwarf2reader::DW_FORM_ref4, - dummy_line_size_ + 10); - root_handler_.EndAttributes(); - root_handler_.Finish(); -} - -TEST_F(CUErrors, NoLineSection) { - EXPECT_CALL(reporter_, MissingSection(".debug_line")).Times(1); - PushLine(0x88507fb678052611ULL, 0x42c8e9de6bbaa0faULL, "line-file", 64472290); - // Delete the entry for .debug_line added by the fixture class's constructor. - file_context_.ClearSectionMapForTest(); - - StartCU(); - root_handler_.Finish(); -} - -TEST_F(CUErrors, BadDwarfVersion1) { - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); - - ASSERT_FALSE(root_handler_ - .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, - 0xc9de224ccb99ac3eULL, 1)); -} - -TEST_F(CUErrors, GoodDwarfVersion2) { - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); - - ASSERT_TRUE(root_handler_ - .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, - 0xc9de224ccb99ac3eULL, 2)); -} - -TEST_F(CUErrors, GoodDwarfVersion3) { - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); - - ASSERT_TRUE(root_handler_ - .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, - 0xc9de224ccb99ac3eULL, 3)); -} - -TEST_F(CUErrors, BadCURootDIETag) { - // Kludge: satisfy reporter_'s expectation. - reporter_.SetCUName("compilation-unit-name"); - - ASSERT_TRUE(root_handler_ - .StartCompilationUnit(0xadf6e0eb71e2b0d9ULL, 0x4d, 0x90, - 0xc9de224ccb99ac3eULL, 3)); - - ASSERT_FALSE(root_handler_.StartRootDIE(0x02e56bfbda9e7337ULL, - dwarf2reader::DW_TAG_subprogram)); -} - -// Tests for DwarfCUToModule::Reporter. These just produce (or fail to -// produce) output, so their results need to be checked by hand. -struct Reporter: public Test { - Reporter() - : reporter("filename", 0x123456789abcdef0ULL), - function("function name", 0x19c45c30770c1eb0ULL), - file("source file name") { - reporter.SetCUName("compilation-unit-name"); - - function.size = 0x89808a5bdfa0a6a3ULL; - function.parameter_size = 0x6a329f18683dcd51ULL; - - line.address = 0x3606ac6267aebeccULL; - line.size = 0x5de482229f32556aULL; - line.file = &file; - line.number = 93400201; - } - - DwarfCUToModule::WarningReporter reporter; - Module::Function function; - Module::File file; - Module::Line line; -}; - -TEST_F(Reporter, UnknownSpecification) { - reporter.UnknownSpecification(0x123456789abcdef1ULL, 0x323456789abcdef2ULL); -} - -TEST_F(Reporter, UnknownAbstractOrigin) { - reporter.UnknownAbstractOrigin(0x123456789abcdef1ULL, 0x323456789abcdef2ULL); -} - -TEST_F(Reporter, MissingSection) { - reporter.MissingSection("section name"); -} - -TEST_F(Reporter, BadLineInfoOffset) { - reporter.BadLineInfoOffset(0x123456789abcdef1ULL); -} - -TEST_F(Reporter, UncoveredFunctionDisabled) { - reporter.UncoveredFunction(function); - EXPECT_FALSE(reporter.uncovered_warnings_enabled()); -} - -TEST_F(Reporter, UncoveredFunctionEnabled) { - reporter.set_uncovered_warnings_enabled(true); - reporter.UncoveredFunction(function); - EXPECT_TRUE(reporter.uncovered_warnings_enabled()); -} - -TEST_F(Reporter, UncoveredLineDisabled) { - reporter.UncoveredLine(line); - EXPECT_FALSE(reporter.uncovered_warnings_enabled()); -} - -TEST_F(Reporter, UncoveredLineEnabled) { - reporter.set_uncovered_warnings_enabled(true); - reporter.UncoveredLine(line); - EXPECT_TRUE(reporter.uncovered_warnings_enabled()); -} - -TEST_F(Reporter, UnnamedFunction) { - reporter.UnnamedFunction(0x90c0baff9dedb2d9ULL); -} - -// Would be nice to also test: -// - overlapping lines, functions diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.cc deleted file mode 100644 index 258b0b603..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.cc +++ /dev/null @@ -1,143 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf_line_to_module.cc: Implementation of DwarfLineToModule class. -// See dwarf_line_to_module.h for details. - -#include <stdio.h> - -#include <string> - -#include "common/dwarf_line_to_module.h" -#include "common/using_std_string.h" - -// Trying to support Windows paths in a reasonable way adds a lot of -// variations to test; it would be better to just put off dealing with -// it until we actually have to deal with DWARF on Windows. - -// Return true if PATH is an absolute path, false if it is relative. -static bool PathIsAbsolute(const string &path) { - return (path.size() >= 1 && path[0] == '/'); -} - -static bool HasTrailingSlash(const string &path) { - return (path.size() >= 1 && path[path.size() - 1] == '/'); -} - -// If PATH is an absolute path, return PATH. If PATH is a relative path, -// treat it as relative to BASE and return the combined path. -static string ExpandPath(const string &path, - const string &base) { - if (PathIsAbsolute(path) || base.empty()) - return path; - return base + (HasTrailingSlash(base) ? "" : "/") + path; -} - -namespace google_breakpad { - -void DwarfLineToModule::DefineDir(const string &name, uint32 dir_num) { - // Directory number zero is reserved to mean the compilation - // directory. Silently ignore attempts to redefine it. - if (dir_num != 0) - directories_[dir_num] = ExpandPath(name, compilation_dir_); -} - -void DwarfLineToModule::DefineFile(const string &name, int32 file_num, - uint32 dir_num, uint64 mod_time, - uint64 length) { - if (file_num == -1) - file_num = ++highest_file_number_; - else if (file_num > highest_file_number_) - highest_file_number_ = file_num; - - string dir_name; - if (dir_num == 0) { - // Directory number zero is the compilation directory, and is stored as - // an attribute on the compilation unit, rather than in the program table. - dir_name = compilation_dir_; - } else { - DirectoryTable::const_iterator directory_it = directories_.find(dir_num); - if (directory_it != directories_.end()) { - dir_name = directory_it->second; - } else { - if (!warned_bad_directory_number_) { - fprintf(stderr, "warning: DWARF line number data refers to undefined" - " directory numbers\n"); - warned_bad_directory_number_ = true; - } - } - } - - string full_name = ExpandPath(name, dir_name); - - // Find a Module::File object of the given name, and add it to the - // file table. - files_[file_num] = module_->FindFile(full_name); -} - -void DwarfLineToModule::AddLine(uint64 address, uint64 length, - uint32 file_num, uint32 line_num, - uint32 column_num) { - if (length == 0) - return; - - // Clip lines not to extend beyond the end of the address space. - if (address + length < address) - length = -address; - - // Should we omit this line? (See the comments for omitted_line_end_.) - if (address == 0 || address == omitted_line_end_) { - omitted_line_end_ = address + length; - return; - } else { - omitted_line_end_ = 0; - } - - // Find the source file being referred to. - Module::File *file = files_[file_num]; - if (!file) { - if (!warned_bad_file_number_) { - fprintf(stderr, "warning: DWARF line number data refers to " - "undefined file numbers\n"); - warned_bad_file_number_ = true; - } - return; - } - Module::Line line; - line.address = address; - // We set the size when we get the next line or the EndSequence call. - line.size = length; - line.file = file; - line.number = line_num; - lines_->push_back(line); -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.h deleted file mode 100644 index 1fdd4cb71..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module.h +++ /dev/null @@ -1,188 +0,0 @@ -// -*- mode: c++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// The DwarfLineToModule class accepts line number information from a -// DWARF parser and adds it to a google_breakpad::Module. The Module -// can write that data out as a Breakpad symbol file. - -#ifndef COMMON_LINUX_DWARF_LINE_TO_MODULE_H -#define COMMON_LINUX_DWARF_LINE_TO_MODULE_H - -#include <string> - -#include "common/module.h" -#include "common/dwarf/dwarf2reader.h" -#include "common/using_std_string.h" - -namespace google_breakpad { - -// A class for producing a vector of google_breakpad::Module::Line -// instances from parsed DWARF line number data. -// -// An instance of this class can be provided as a handler to a -// dwarf2reader::LineInfo DWARF line number information parser. The -// handler accepts source location information from the parser and -// uses it to produce a vector of google_breakpad::Module::Line -// objects, referring to google_breakpad::Module::File objects added -// to a particular google_breakpad::Module. -// -// GNU toolchain omitted sections support: -// ====================================== -// -// Given the right options, the GNU toolchain will omit unreferenced -// functions from the final executable. Unfortunately, when it does so, it -// does not remove the associated portions of the DWARF line number -// program; instead, it gives the DW_LNE_set_address instructions referring -// to the now-deleted code addresses of zero. Given this input, the DWARF -// line parser will call AddLine with a series of lines starting at address -// zero. For example, here is the output from 'readelf -wl' for a program -// with four functions, the first three of which have been omitted: -// -// Line Number Statements: -// Extended opcode 2: set Address to 0x0 -// Advance Line by 14 to 15 -// Copy -// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 16 -// Special opcode 119: advance Address by 8 to 0xb and Line by 2 to 18 -// Advance PC by 2 to 0xd -// Extended opcode 1: End of Sequence -// -// Extended opcode 2: set Address to 0x0 -// Advance Line by 14 to 15 -// Copy -// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 16 -// Special opcode 119: advance Address by 8 to 0xb and Line by 2 to 18 -// Advance PC by 2 to 0xd -// Extended opcode 1: End of Sequence -// -// Extended opcode 2: set Address to 0x0 -// Advance Line by 19 to 20 -// Copy -// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 21 -// Special opcode 76: advance Address by 5 to 0x8 and Line by 1 to 22 -// Advance PC by 2 to 0xa -// Extended opcode 1: End of Sequence -// -// Extended opcode 2: set Address to 0x80483a4 -// Advance Line by 23 to 24 -// Copy -// Special opcode 202: advance Address by 14 to 0x80483b2 and Line by 1 to 25 -// Special opcode 76: advance Address by 5 to 0x80483b7 and Line by 1 to 26 -// Advance PC by 6 to 0x80483bd -// Extended opcode 1: End of Sequence -// -// Instead of collecting runs of lines describing code that is not there, -// we try to recognize and drop them. Since the linker doesn't explicitly -// distinguish references to dropped sections from genuine references to -// code at address zero, we must use a heuristic. We have chosen: -// -// - If a line starts at address zero, omit it. (On the platforms -// breakpad targets, it is extremely unlikely that there will be code -// at address zero.) -// -// - If a line starts immediately after an omitted line, omit it too. -class DwarfLineToModule: public dwarf2reader::LineInfoHandler { - public: - // As the DWARF line info parser passes us line records, add source - // files to MODULE, and add all lines to the end of LINES. LINES - // need not be empty. If the parser hands us a zero-length line, we - // omit it. If the parser hands us a line that extends beyond the - // end of the address space, we clip it. It's up to our client to - // sort out which lines belong to which functions; we don't add them - // to any particular function in MODULE ourselves. - DwarfLineToModule(Module *module, const string& compilation_dir, - vector<Module::Line> *lines) - : module_(module), - compilation_dir_(compilation_dir), - lines_(lines), - highest_file_number_(-1), - omitted_line_end_(0), - warned_bad_file_number_(false), - warned_bad_directory_number_(false) { } - - ~DwarfLineToModule() { } - - void DefineDir(const string &name, uint32 dir_num); - void DefineFile(const string &name, int32 file_num, - uint32 dir_num, uint64 mod_time, - uint64 length); - void AddLine(uint64 address, uint64 length, - uint32 file_num, uint32 line_num, uint32 column_num); - - private: - - typedef std::map<uint32, string> DirectoryTable; - typedef std::map<uint32, Module::File *> FileTable; - - // The module we're contributing debugging info to. Owned by our - // client. - Module *module_; - - // The compilation directory for the current compilation unit whose - // lines are being accumulated. - string compilation_dir_; - - // The vector of lines we're accumulating. Owned by our client. - // - // In a Module, as in a breakpad symbol file, lines belong to - // specific functions, but DWARF simply assigns lines to addresses; - // one must infer the line/function relationship using the - // functions' beginning and ending addresses. So we can't add these - // to the appropriate function from module_ until we've read the - // function info as well. Instead, we accumulate lines here, and let - // whoever constructed this sort it all out. - vector<Module::Line> *lines_; - - // A table mapping directory numbers to paths. - DirectoryTable directories_; - - // A table mapping file numbers to Module::File pointers. - FileTable files_; - - // The highest file number we've seen so far, or -1 if we've seen - // none. Used for dynamically defined file numbers. - int32 highest_file_number_; - - // This is the ending address of the last line we omitted, or zero if we - // didn't omit the previous line. It is zero before we have received any - // AddLine calls. - uint64 omitted_line_end_; - - // True if we've warned about: - bool warned_bad_file_number_; // bad file numbers - bool warned_bad_directory_number_; // bad directory numbers -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_DWARF_LINE_TO_MODULE_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module_unittest.cc deleted file mode 100644 index 7c0fcfd35..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/dwarf_line_to_module_unittest.cc +++ /dev/null @@ -1,391 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dwarf_line_to_module.cc: Unit tests for google_breakpad::DwarfLineToModule. - -#include <vector> - -#include "breakpad_googletest_includes.h" -#include "common/dwarf_line_to_module.h" - -using std::vector; - -using google_breakpad::DwarfLineToModule; -using google_breakpad::Module; -using google_breakpad::Module; - -TEST(SimpleModule, One) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineFile("file1", 0x30bf0f27, 0, 0, 0); - h.AddLine(0x6fd126fbf74f2680LL, 0x63c9a14cf556712bLL, 0x30bf0f27, - 0x4c090cbf, 0x1cf9fe0d); - - vector<Module::File *> files; - m.GetFiles(&files); - EXPECT_EQ(1U, files.size()); - EXPECT_STREQ("/file1", files[0]->name.c_str()); - - EXPECT_EQ(1U, lines.size()); - EXPECT_EQ(0x6fd126fbf74f2680ULL, lines[0].address); - EXPECT_EQ(0x63c9a14cf556712bULL, lines[0].size); - EXPECT_TRUE(lines[0].file == files[0]); - EXPECT_EQ(0x4c090cbf, lines[0].number); -} - -TEST(SimpleModule, Many) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineDir("directory1", 0x838299ab); - h.DefineDir("directory2", 0xf85de023); - h.DefineFile("file1", 0x2b80377a, 0x838299ab, 0, 0); - h.DefineFile("file1", 0x63beb4a4, 0xf85de023, 0, 0); - h.DefineFile("file2", 0x1d161d56, 0x838299ab, 0, 0); - h.DefineFile("file2", 0x1e7a667c, 0xf85de023, 0, 0); - h.AddLine(0x69900c5d553b7274ULL, 0x90fded183f0d0d3cULL, 0x2b80377a, - 0x15b0f0a9U, 0x3ff5abd6U); - h.AddLine(0x45811219a39b7101ULL, 0x25a5e6a924afc41fULL, 0x63beb4a4, - 0x4d259ce9U, 0x41c5ee32U); - h.AddLine(0xfa90514c1dc9704bULL, 0x0063efeabc02f313ULL, 0x1d161d56, - 0x1ee9fa4fU, 0xbf70e46aU); - h.AddLine(0x556b55fb6a647b10ULL, 0x3f3089ca2bfd80f5ULL, 0x1e7a667c, - 0x77fc280eU, 0x2c4a728cU); - h.DefineFile("file3", -1, 0, 0, 0); - h.AddLine(0xe2d72a37f8d9403aULL, 0x034dfab5b0d4d236ULL, 0x63beb4a5, - 0x75047044U, 0xb6a0016cU); - - vector<Module::File *> files; - m.GetFiles(&files); - ASSERT_EQ(5U, files.size()); - EXPECT_STREQ("/directory1/file1", files[0]->name.c_str()); - EXPECT_STREQ("/directory1/file2", files[1]->name.c_str()); - EXPECT_STREQ("/directory2/file1", files[2]->name.c_str()); - EXPECT_STREQ("/directory2/file2", files[3]->name.c_str()); - EXPECT_STREQ("/file3", files[4]->name.c_str()); - - ASSERT_EQ(5U, lines.size()); - - EXPECT_EQ(0x69900c5d553b7274ULL, lines[0].address); - EXPECT_EQ(0x90fded183f0d0d3cULL, lines[0].size); - EXPECT_TRUE(lines[0].file == files[0]); - EXPECT_EQ(0x15b0f0a9, lines[0].number); - - EXPECT_EQ(0x45811219a39b7101ULL, lines[1].address); - EXPECT_EQ(0x25a5e6a924afc41fULL, lines[1].size); - EXPECT_TRUE(lines[1].file == files[2]); - EXPECT_EQ(0x4d259ce9, lines[1].number); - - EXPECT_EQ(0xfa90514c1dc9704bULL, lines[2].address); - EXPECT_EQ(0x0063efeabc02f313ULL, lines[2].size); - EXPECT_TRUE(lines[2].file == files[1]); - EXPECT_EQ(0x1ee9fa4f, lines[2].number); - - EXPECT_EQ(0x556b55fb6a647b10ULL, lines[3].address); - EXPECT_EQ(0x3f3089ca2bfd80f5ULL, lines[3].size); - EXPECT_TRUE(lines[3].file == files[3]); - EXPECT_EQ(0x77fc280e, lines[3].number); - - EXPECT_EQ(0xe2d72a37f8d9403aULL, lines[4].address); - EXPECT_EQ(0x034dfab5b0d4d236ULL, lines[4].size); - EXPECT_TRUE(lines[4].file == files[4]); - EXPECT_EQ(0x75047044, lines[4].number); -} - -TEST(Filenames, Absolute) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineDir("directory1", 1); - h.DefineFile("/absolute", 1, 1, 0, 0); - - h.AddLine(1, 1, 1, 0, 0); - - vector<Module::File *> files; - m.GetFiles(&files); - ASSERT_EQ(1U, files.size()); - EXPECT_STREQ("/absolute", files[0]->name.c_str()); - ASSERT_EQ(1U, lines.size()); - EXPECT_TRUE(lines[0].file == files[0]); -} - -TEST(Filenames, Relative) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineDir("directory1", 1); - h.DefineFile("relative", 1, 1, 0, 0); - - h.AddLine(1, 1, 1, 0, 0); - - vector<Module::File *> files; - m.GetFiles(&files); - ASSERT_EQ(1U, files.size()); - EXPECT_STREQ("/directory1/relative", files[0]->name.c_str()); - ASSERT_EQ(1U, lines.size()); - EXPECT_TRUE(lines[0].file == files[0]); -} - -TEST(Filenames, StrangeFile) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineDir("directory1", 1); - h.DefineFile("", 1, 1, 0, 0); - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("/directory1/", lines[0].file->name.c_str()); -} - -TEST(Filenames, StrangeDirectory) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineDir("", 1); - h.DefineFile("file1", 1, 1, 0, 0); - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("/file1", lines[0].file->name.c_str()); -} - -TEST(Filenames, StrangeDirectoryAndFile) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineDir("", 1); - h.DefineFile("", 1, 1, 0, 0); - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("/", lines[0].file->name.c_str()); -} - -// We should use the compilation directory when encountering a file for -// directory number zero. -TEST(Filenames, DirectoryZeroFileIsRelativeToCompilationDir) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "src/build", &lines); - - h.DefineDir("Dir", 1); - h.DefineFile("File", 1, 0, 0, 0); - - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("src/build/File", lines[0].file->name.c_str()); -} - -// We should treat non-absolute directories as relative to the compilation -// directory. -TEST(Filenames, IncludeDirectoryRelativeToDirectoryZero) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "src/build", &lines); - - h.DefineDir("Dir", 1); - h.DefineFile("File", 1, 1, 0, 0); - - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("src/build/Dir/File", lines[0].file->name.c_str()); -} - -// We should treat absolute directories as absolute, and not relative to -// the compilation dir. -TEST(Filenames, IncludeDirectoryAbsolute) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "src/build", &lines); - - h.DefineDir("/Dir", 1); - h.DefineFile("File", 1, 1, 0, 0); - - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("/Dir/File", lines[0].file->name.c_str()); -} - -// We should silently ignore attempts to define directory number zero, -// since that is always the compilation directory. -TEST(ModuleErrors, DirectoryZero) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineDir("directory0", 0); // should be ignored - h.DefineFile("relative", 1, 0, 0, 0); - - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("/relative", lines[0].file->name.c_str()); -} - -// We should refuse to add lines with bogus file numbers. We should -// produce only one warning, however. -TEST(ModuleErrors, BadFileNumber) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineFile("relative", 1, 0, 0, 0); - h.AddLine(1, 1, 2, 0, 0); // bad file number - h.AddLine(2, 1, 2, 0, 0); // bad file number (no duplicate warning) - - EXPECT_EQ(0U, lines.size()); -} - -// We should treat files with bogus directory numbers as relative to -// the compilation unit. -TEST(ModuleErrors, BadDirectoryNumber) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineDir("directory1", 1); - h.DefineFile("baddirnumber1", 1, 2, 0, 0); // bad directory number - h.DefineFile("baddirnumber2", 2, 2, 0, 0); // bad dir number (no warning) - h.AddLine(1, 1, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_STREQ("baddirnumber1", lines[0].file->name.c_str()); -} - -// We promise not to report empty lines. -TEST(ModuleErrors, EmptyLine) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineFile("filename1", 1, 0, 0, 0); - h.AddLine(1, 0, 1, 0, 0); - - ASSERT_EQ(0U, lines.size()); -} - -// We are supposed to clip lines that extend beyond the end of the -// address space. -TEST(ModuleErrors, BigLine) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineFile("filename1", 1, 0, 0, 0); - h.AddLine(0xffffffffffffffffULL, 2, 1, 0, 0); - - ASSERT_EQ(1U, lines.size()); - EXPECT_EQ(1U, lines[0].size); -} - -// The 'Omitted' tests verify that we correctly omit line information -// for code in sections that the linker has dropped. See "GNU -// toolchain omitted sections support" at the top of the -// DwarfLineToModule class. - -TEST(Omitted, DroppedThenGood) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineFile("filename1", 1, 0, 0, 0); - h.AddLine(0, 10, 1, 83816211, 0); // should be omitted - h.AddLine(20, 10, 1, 13059195, 0); // should be recorded - - ASSERT_EQ(1U, lines.size()); - EXPECT_EQ(13059195, lines[0].number); -} - -TEST(Omitted, GoodThenDropped) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineFile("filename1", 1, 0, 0, 0); - h.AddLine(0x9dd6a372, 10, 1, 41454594, 0); // should be recorded - h.AddLine(0, 10, 1, 44793413, 0); // should be omitted - - ASSERT_EQ(1U, lines.size()); - EXPECT_EQ(41454594, lines[0].number); -} - -TEST(Omitted, Mix1) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineFile("filename1", 1, 0, 0, 0); - h.AddLine(0x679ed72f, 10, 1, 58932642, 0); // should be recorded - h.AddLine(0xdfb5a72d, 10, 1, 39847385, 0); // should be recorded - h.AddLine(0, 0x78, 1, 23053829, 0); // should be omitted - h.AddLine(0x78, 0x6a, 1, 65317783, 0); // should be omitted - h.AddLine(0x78 + 0x6a, 0x2a, 1, 77601423, 0); // should be omitted - h.AddLine(0x9fe0cea5, 10, 1, 91806582, 0); // should be recorded - h.AddLine(0x7e41a109, 10, 1, 56169221, 0); // should be recorded - - ASSERT_EQ(4U, lines.size()); - EXPECT_EQ(58932642, lines[0].number); - EXPECT_EQ(39847385, lines[1].number); - EXPECT_EQ(91806582, lines[2].number); - EXPECT_EQ(56169221, lines[3].number); -} - -TEST(Omitted, Mix2) { - Module m("name", "os", "architecture", "id"); - vector<Module::Line> lines; - DwarfLineToModule h(&m, "/", &lines); - - h.DefineFile("filename1", 1, 0, 0, 0); - h.AddLine(0, 0xf2, 1, 58802211, 0); // should be omitted - h.AddLine(0xf2, 0xb9, 1, 78958222, 0); // should be omitted - h.AddLine(0xf2 + 0xb9, 0xf7, 1, 64861892, 0); // should be omitted - h.AddLine(0x4e4d271e, 9, 1, 67355743, 0); // should be recorded - h.AddLine(0xdfb5a72d, 30, 1, 23365776, 0); // should be recorded - h.AddLine(0, 0x64, 1, 76196762, 0); // should be omitted - h.AddLine(0x64, 0x33, 1, 71066611, 0); // should be omitted - h.AddLine(0x64 + 0x33, 0xe3, 1, 61749337, 0); // should be omitted - - ASSERT_EQ(2U, lines.size()); - EXPECT_EQ(67355743, lines[0].number); - EXPECT_EQ(23365776, lines[1].number); -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/language.cc b/toolkit/crashreporter/google-breakpad/src/common/language.cc deleted file mode 100644 index c2fd81f64..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/language.cc +++ /dev/null @@ -1,83 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// language.cc: Subclasses and singletons for google_breakpad::Language. -// See language.h for details. - -#include "common/language.h" - -namespace google_breakpad { - -// C++ language-specific operations. -class CPPLanguage: public Language { - public: - CPPLanguage() {} - string MakeQualifiedName(const string &parent_name, - const string &name) const { - if (parent_name.empty()) - return name; - else - return parent_name + "::" + name; - } -}; - -CPPLanguage CPPLanguageSingleton; - -// Java language-specific operations. -class JavaLanguage: public Language { - public: - string MakeQualifiedName(const string &parent_name, - const string &name) const { - if (parent_name.empty()) - return name; - else - return parent_name + "." + name; - } -}; - -JavaLanguage JavaLanguageSingleton; - -// Assembler language-specific operations. -class AssemblerLanguage: public Language { - bool HasFunctions() const { return false; } - string MakeQualifiedName(const string &parent_name, - const string &name) const { - return name; - } -}; - -AssemblerLanguage AssemblerLanguageSingleton; - -const Language * const Language::CPlusPlus = &CPPLanguageSingleton; -const Language * const Language::Java = &JavaLanguageSingleton; -const Language * const Language::Assembler = &AssemblerLanguageSingleton; - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/language.h b/toolkit/crashreporter/google-breakpad/src/common/language.h deleted file mode 100644 index bbe303347..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/language.h +++ /dev/null @@ -1,88 +0,0 @@ -// -*- mode: c++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// language.h: Define google_breakpad::Language. Instances of -// subclasses of this class provide language-appropriate operations -// for the Breakpad symbol dumper. - -#ifndef COMMON_LINUX_LANGUAGE_H__ -#define COMMON_LINUX_LANGUAGE_H__ - -#include <string> - -#include "common/using_std_string.h" - -namespace google_breakpad { - -// An abstract base class for language-specific operations. We choose -// an instance of a subclass of this when we find the CU's language. -// This class's definitions are appropriate for CUs with no specified -// language. -class Language { - public: - // A base class destructor should be either public and virtual, - // or protected and nonvirtual. - virtual ~Language() {} - - // Return true if this language has functions to which we can assign - // line numbers. (Debugging info for assembly language, for example, - // can have source location information, but does not have functions - // recorded using DW_TAG_subprogram DIEs.) - virtual bool HasFunctions() const { return true; } - - // Construct a fully-qualified, language-appropriate form of NAME, - // given that PARENT_NAME is the name of the construct enclosing - // NAME. If PARENT_NAME is the empty string, then NAME is a - // top-level name. - // - // This API sort of assumes that a fully-qualified name is always - // some simple textual composition of the unqualified name and its - // parent's name, and that we don't need to know anything else about - // the parent or the child (say, their DIEs' tags) to do the job. - // This is true for the languages we support at the moment, and - // keeps things concrete. Perhaps a more refined operation would - // take into account the parent and child DIE types, allow languages - // to use their own data type for complex parent names, etc. But if - // C++ doesn't need all that, who would? - virtual string MakeQualifiedName (const string &parent_name, - const string &name) const = 0; - - // Instances for specific languages. - static const Language * const CPlusPlus, - * const Java, - * const Assembler; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_LANGUAGE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/crc32.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/crc32.cc deleted file mode 100644 index 8df636ce4..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/crc32.cc +++ /dev/null @@ -1,70 +0,0 @@ -// 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/toolkit/crashreporter/google-breakpad/src/common/linux/crc32.h b/toolkit/crashreporter/google-breakpad/src/common/linux/crc32.h deleted file mode 100644 index e3d9db92b..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/crc32.h +++ /dev/null @@ -1,53 +0,0 @@ -// 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/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc deleted file mode 100644 index cd99bee66..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc +++ /dev/null @@ -1,1159 +0,0 @@ -// 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 <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/arm_ex_reader.h" -#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/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.h" -#include "common/module.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" - -#ifndef SHT_ARM_EXIDX -// bionic and older glibc don't define this -# define SHT_ARM_EXIDX (SHT_LOPROC + 1) -#endif - -// 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::ElfClass; -using google_breakpad::ElfClass32; -using google_breakpad::ElfClass64; -using google_breakpad::FileID; -using google_breakpad::FindElfSectionByName; -using google_breakpad::GetOffset; -using google_breakpad::IsValidElf; -using google_breakpad::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 - -// Define SHT_ANDROID_REL and SHT_ANDROID_RELA if not defined by the host. -// Sections with this type contain Android packed relocations. -#ifndef SHT_ANDROID_REL -#define SHT_ANDROID_REL (SHT_LOOS + 1) -#endif -#ifndef SHT_ANDROID_RELA -#define SHT_ANDROID_RELA (SHT_LOOS + 2) -#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; -} - -#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 line-to-module loader that accepts line number info parsed by -// dwarf2reader::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(dwarf2reader::ByteReader *byte_reader) - : byte_reader_(byte_reader) { } - void StartCompilationUnit(const string& compilation_dir) { - compilation_dir_ = compilation_dir; - } - void ReadProgram(const uint8_t *program, uint64 length, - Module* module, std::vector<Module::Line>* lines) { - DwarfLineToModule handler(module, compilation_dir_, lines); - dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler); - parser.Start(); - } - private: - string compilation_dir_; - dwarf2reader::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, - Module* module) { - typedef typename ElfClass::Shdr Shdr; - - const dwarf2reader::Endianness endianness = big_endian ? - dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE; - dwarf2reader::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); - } - - // Parse all the compilation units in the .debug_info section. - DumperLineToModule line_to_module(&byte_reader); - dwarf2reader::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>& 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 debug_info_length = debug_info_section.second; - for (uint64 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, &reporter); - // Make a Dwarf2Handler that drives the DIEHandler. - dwarf2reader::DIEDispatcher die_dispatcher(&root_handler); - // Make a DWARF parser for the compilation unit at OFFSET. - dwarf2reader::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 dwarf2reader::Endianness endianness = big_endian ? - dwarf2reader::ENDIANNESS_BIG : dwarf2reader::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); - dwarf2reader::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); - - dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename, - section_name); - dwarf2reader::CallFrameInfo parser(cfi, cfi_size, - &byte_reader, &handler, &dwarf_reporter, - eh_frame); - parser.Start(); - return true; -} - -template<typename ElfClass> -bool LoadARMexidx(const typename ElfClass::Ehdr* elf_header, - const typename ElfClass::Shdr* exidx_section, - const typename ElfClass::Shdr* extab_section, - uint32_t loading_addr, - Module* module) { - // To do this properly we need to know: - // * the bounds of the .ARM.exidx section in the mapped image - // * the bounds of the .ARM.extab section in the mapped image - // * the vma of the last byte in the text section associated with the .exidx - // The first two are easy. The third is a bit tricky. If we can't - // figure out what it is, just pass in zero. - const char *exidx_img - = GetOffset<ElfClass, char>(elf_header, exidx_section->sh_offset); - size_t exidx_size = exidx_section->sh_size; - const char *extab_img - = GetOffset<ElfClass, char>(elf_header, extab_section->sh_offset); - size_t extab_size = extab_section->sh_size; - - // The sh_link field of the exidx section gives the section number - // for the associated text section. - uint32_t exidx_text_last_svma = 0; - int exidx_text_sno = exidx_section->sh_link; - typedef typename ElfClass::Shdr Shdr; - // |sections| points to the section header table - const Shdr* sections - = GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff); - const int num_sections = elf_header->e_shnum; - if (exidx_text_sno >= 0 && exidx_text_sno < num_sections) { - const Shdr* exidx_text_shdr = §ions[exidx_text_sno]; - if (exidx_text_shdr->sh_size > 0) { - exidx_text_last_svma - = exidx_text_shdr->sh_addr + exidx_text_shdr->sh_size - 1; - } - } - - arm_ex_to_module::ARMExToModule handler(module); - arm_ex_reader::ExceptionTableInfo - parser(exidx_img, exidx_size, extab_img, extab_size, exidx_text_last_svma, - &handler, - reinterpret_cast<const char*>(elf_header), - loading_addr); - 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 dwarf2reader::Endianness endianness = big_endian ? - dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE; - dwarf2reader::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 §ion) { - 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; - typedef typename ElfClass::Word Word; - - 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); - - Word debug_section_type = - elf_header->e_machine == EM_MIPS ? SHT_MIPS_DWARF : SHT_PROGBITS; - 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; - - // Reject files that contain Android packed relocations. The pre-packed - // version of the file should be symbolized; the packed version is only - // intended for use on the target system. - if (FindElfSectionByName<ElfClass>(".rel.dyn", SHT_ANDROID_REL, - sections, names, - names_end, elf_header->e_shnum)) { - fprintf(stderr, "%s: file contains a \".rel.dyn\" section " - "with type SHT_ANDROID_REL\n", obj_file.c_str()); - fprintf(stderr, "Files containing Android packed relocations " - "may not be symbolized.\n"); - return false; - } - if (FindElfSectionByName<ElfClass>(".rela.dyn", SHT_ANDROID_RELA, - sections, names, - names_end, elf_header->e_shnum)) { - fprintf(stderr, "%s: file contains a \".rela.dyn\" section " - "with type SHT_ANDROID_RELA\n", obj_file.c_str()); - fprintf(stderr, "Files containing Android packed relocations " - "may not be symbolized.\n"); - return false; - } - - if (options.symbol_data != ONLY_CFI) { -#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 - - // Look for DWARF debugging information, and load it if present. - const Shdr* dwarf_section = - FindElfSectionByName<ElfClass>(".debug_info", debug_section_type, - 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, module)) { - fprintf(stderr, "%s: \".debug_info\" section found, but failed to load " - "DWARF debugging information\n", obj_file.c_str()); - } - } - - // 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; - } - } - } - - if (options.symbol_data != NO_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", debug_section_type, - 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; - } - } - - // ARM has special unwind tables that can be used. - const Shdr* arm_exidx_section = - FindElfSectionByName<ElfClass>(".ARM.exidx", SHT_ARM_EXIDX, - sections, names, names_end, - elf_header->e_shnum); - const Shdr* arm_extab_section = - FindElfSectionByName<ElfClass>(".ARM.extab", SHT_PROGBITS, - sections, names, names_end, - elf_header->e_shnum); - // Load information from these sections even if there is - // .debug_info, because some functions (e.g., hand-written or - // script-generated assembly) could have exidx entries but no DWARF. - // (For functions with both, the DWARF info that has already been - // parsed will take precedence.) - if (arm_exidx_section && arm_extab_section && options.symbol_data != NO_CFI) { - info->LoadedSection(".ARM.exidx"); - info->LoadedSection(".ARM.extab"); - bool result = LoadARMexidx<ElfClass>(elf_header, - arm_exidx_section, arm_extab_section, - loading_addr, 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; - } -} - -// Return the non-directory portion of FILENAME: the portion after the -// last slash, or the whole filename if there are no slashes. -string BaseFileName(const string &filename) { - // Lots of copies! basename's behavior is less than ideal. - char* c_filename = strdup(filename.c_str()); - string base = basename(c_filename); - free(c_filename); - return base; -} - -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, - 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; - } - - string name = BaseFileName(obj_filename); - string os = "Linux"; - // 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, os, architecture, id, code_id)); - - return true; -} - -template<typename ElfClass> -bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header, - const string& obj_filename, - 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, 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 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, debug_dirs, - options, module); - } - if (elfclass == ELFCLASS64) { - return ReadSymbolDataElfClass<ElfClass64>( - reinterpret_cast<const Elf64_Ehdr*>(obj_file), obj_filename, debug_dirs, - options, module); - } - - return false; -} - -bool WriteSymbolFile(const string &obj_file, - const std::vector<string>& debug_dirs, - const DumpOptions& options, - std::ostream &sym_stream) { - Module* module; - if (!ReadSymbolData(obj_file, 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& obj_file, - std::ostream &sym_stream) { - MmapWrapper map_wrapper; - void* elf_header = NULL; - if (!LoadELF(obj_file, &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, 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, 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& obj_file, - const std::vector<string>& debug_dirs, - const DumpOptions& options, - Module** module) { - MmapWrapper map_wrapper; - void* elf_header = NULL; - if (!LoadELF(obj_file, &map_wrapper, &elf_header)) - return false; - - return ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(elf_header), - obj_file, debug_dirs, options, module); -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h deleted file mode 100644 index 1f204cbad..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.h +++ /dev/null @@ -1,86 +0,0 @@ -// -*- 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 &obj_file, - 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. -bool WriteSymbolFileHeader(const string& obj_file, - 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& obj_file, - const std::vector<string>& debug_dirs, - const DumpOptions& options, - Module** module); - -} // namespace google_breakpad - -#endif // COMMON_LINUX_DUMP_SYMBOLS_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols_unittest.cc deleted file mode 100644 index bb7b20076..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols_unittest.cc +++ /dev/null @@ -1,204 +0,0 @@ -// 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> - -// dump_symbols_unittest.cc: -// Unittests for google_breakpad::DumpSymbols - -#include <elf.h> -#include <link.h> -#include <stdio.h> - -#include <sstream> -#include <vector> - -#include "breakpad_googletest_includes.h" -#include "common/linux/elf_gnu_compat.h" -#include "common/linux/elfutils.h" -#include "common/linux/dump_symbols.h" -#include "common/linux/synth_elf.h" -#include "common/module.h" -#include "common/using_std_string.h" - -namespace google_breakpad { - -bool ReadSymbolDataInternal(const uint8_t* obj_file, - const string& obj_filename, - const std::vector<string>& debug_dir, - const DumpOptions& options, - Module** module); - -using google_breakpad::synth_elf::ELF; -using google_breakpad::synth_elf::Notes; -using google_breakpad::synth_elf::StringTable; -using google_breakpad::synth_elf::SymbolTable; -using google_breakpad::test_assembler::kLittleEndian; -using google_breakpad::test_assembler::Section; -using std::stringstream; -using std::vector; -using ::testing::Test; -using ::testing::Types; - -template<typename ElfClass> -class DumpSymbols : public Test { - public: - void GetElfContents(ELF& elf) { - string contents; - ASSERT_TRUE(elf.GetContents(&contents)); - ASSERT_LT(0U, contents.size()); - - elfdata_v.clear(); - elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end()); - elfdata = &elfdata_v[0]; - } - - vector<uint8_t> elfdata_v; - uint8_t* elfdata; -}; - -typedef Types<ElfClass32, ElfClass64> ElfClasses; - -TYPED_TEST_CASE(DumpSymbols, ElfClasses); - -TYPED_TEST(DumpSymbols, Invalid) { - Elf32_Ehdr header; - memset(&header, 0, sizeof(header)); - Module* module; - DumpOptions options(ALL_SYMBOL_DATA, true); - EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header), - "foo", - vector<string>(), - options, - &module)); -} - -TYPED_TEST(DumpSymbols, SimplePublic) { - ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian); - // Zero out text section for simplicity. - Section text(kLittleEndian); - text.Append(4096, 0); - elf.AddSection(".text", text, SHT_PROGBITS); - - // Add a public symbol. - StringTable table(kLittleEndian); - SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table); - syms.AddSymbol("superfunc", - (typename TypeParam::Addr)0x1000, - (typename TypeParam::Addr)0x10, - // ELF32_ST_INFO works for 32-or 64-bit. - ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), - SHN_UNDEF + 1); - int index = elf.AddSection(".dynstr", table, SHT_STRTAB); - elf.AddSection(".dynsym", syms, - SHT_DYNSYM, // type - SHF_ALLOC, // flags - 0, // addr - index, // link - sizeof(typename TypeParam::Sym)); // entsize - - elf.Finish(); - this->GetElfContents(elf); - - Module* module; - DumpOptions options(ALL_SYMBOL_DATA, true); - EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, - "foo", - vector<string>(), - options, - &module)); - - stringstream s; - module->Write(s, ALL_SYMBOL_DATA); - const string expected = - string("MODULE Linux ") + TypeParam::kMachineName - + " 000000000000000000000000000000000 foo\n" - "INFO CODE_ID 00000000000000000000000000000000\n" - "PUBLIC 1000 0 superfunc\n"; - EXPECT_EQ(expected, s.str()); - delete module; -} - -TYPED_TEST(DumpSymbols, SimpleBuildID) { - ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian); - // Zero out text section for simplicity. - Section text(kLittleEndian); - text.Append(4096, 0); - elf.AddSection(".text", text, SHT_PROGBITS); - - // Add a Build ID - const uint8_t kExpectedIdentifierBytes[] = - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13}; - Notes notes(kLittleEndian); - notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, - sizeof(kExpectedIdentifierBytes)); - elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE); - - // Add a public symbol. - StringTable table(kLittleEndian); - SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table); - syms.AddSymbol("superfunc", - (typename TypeParam::Addr)0x1000, - (typename TypeParam::Addr)0x10, - // ELF32_ST_INFO works for 32-or 64-bit. - ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), - SHN_UNDEF + 1); - int index = elf.AddSection(".dynstr", table, SHT_STRTAB); - elf.AddSection(".dynsym", syms, - SHT_DYNSYM, // type - SHF_ALLOC, // flags - 0, // addr - index, // link - sizeof(typename TypeParam::Sym)); // entsize - - elf.Finish(); - this->GetElfContents(elf); - - Module* module; - DumpOptions options(ALL_SYMBOL_DATA, true); - EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata, - "foo", - vector<string>(), - options, - &module)); - - stringstream s; - module->Write(s, ALL_SYMBOL_DATA); - const string expected = - string("MODULE Linux ") + TypeParam::kMachineName - + " 030201000504070608090A0B0C0D0E0F0 foo\n" - "INFO CODE_ID 000102030405060708090A0B0C0D0E0F10111213\n" - "PUBLIC 1000 0 superfunc\n"; - EXPECT_EQ(expected, s.str()); - delete module; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/eintr_wrapper.h b/toolkit/crashreporter/google-breakpad/src/common/linux/eintr_wrapper.h deleted file mode 100644 index 3f1d18481..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/eintr_wrapper.h +++ /dev/null @@ -1,58 +0,0 @@ -// 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/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.cc deleted file mode 100644 index 0e7db7b1f..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.cc +++ /dev/null @@ -1,179 +0,0 @@ -// 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> - -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() {} - -ElfCoreDump::ElfCoreDump(const MemoryRange& content) - : content_(content) { -} - -void ElfCoreDump::SetContent(const MemoryRange& content) { - content_ = content; -} - -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; - } - } - } - 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/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.h b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.h deleted file mode 100644 index d03c7a88d..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump.h +++ /dev/null @@ -1,148 +0,0 @@ -// 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 <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 value of __WORDSIZE. - typedef ElfW(Ehdr) Ehdr; - typedef ElfW(Nhdr) Nhdr; - typedef ElfW(Phdr) Phdr; - typedef ElfW(Word) Word; - typedef ElfW(Addr) Addr; -#if __WORDSIZE == 32 - static const int kClass = ELFCLASS32; -#elif __WORDSIZE == 64 - static const int kClass = ELFCLASS64; -#else -#error "Unsupported __WORDSIZE 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); - - // 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; - - private: - // Core dump content. - MemoryRange content_; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_ELF_CORE_DUMP_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump_unittest.cc deleted file mode 100644 index 9b41dceee..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_core_dump_unittest.cc +++ /dev/null @@ -1,256 +0,0 @@ -// 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_unittest.cc: Unit tests for google_breakpad::ElfCoreDump. - -#include <sys/procfs.h> - -#include <set> -#include <string> - -#include "breakpad_googletest_includes.h" -#include "common/linux/elf_core_dump.h" -#include "common/linux/memory_mapped_file.h" -#include "common/tests/file_utils.h" -#include "common/linux/tests/crash_generator.h" -#include "common/using_std_string.h" - -using google_breakpad::AutoTempDir; -using google_breakpad::CrashGenerator; -using google_breakpad::ElfCoreDump; -using google_breakpad::MemoryMappedFile; -using google_breakpad::MemoryRange; -using google_breakpad::WriteFile; -using std::set; - -TEST(ElfCoreDumpTest, DefaultConstructor) { - ElfCoreDump core; - EXPECT_FALSE(core.IsValid()); - EXPECT_EQ(NULL, core.GetHeader()); - EXPECT_EQ(0U, core.GetProgramHeaderCount()); - EXPECT_EQ(NULL, core.GetProgramHeader(0)); - EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD)); - EXPECT_FALSE(core.GetFirstNote().IsValid()); -} - -TEST(ElfCoreDumpTest, TestElfHeader) { - ElfCoreDump::Ehdr header; - memset(&header, 0, sizeof(header)); - - AutoTempDir temp_dir; - string core_path = temp_dir.path() + "/core"; - const char* core_file = core_path.c_str(); - MemoryMappedFile mapped_core_file; - ElfCoreDump core; - - ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header) - 1)); - ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); - core.SetContent(mapped_core_file.content()); - EXPECT_FALSE(core.IsValid()); - EXPECT_EQ(NULL, core.GetHeader()); - EXPECT_EQ(0U, core.GetProgramHeaderCount()); - EXPECT_EQ(NULL, core.GetProgramHeader(0)); - EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD)); - EXPECT_FALSE(core.GetFirstNote().IsValid()); - - ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); - ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); - core.SetContent(mapped_core_file.content()); - EXPECT_FALSE(core.IsValid()); - - header.e_ident[0] = ELFMAG0; - ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); - ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); - core.SetContent(mapped_core_file.content()); - EXPECT_FALSE(core.IsValid()); - - header.e_ident[1] = ELFMAG1; - ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); - ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); - core.SetContent(mapped_core_file.content()); - EXPECT_FALSE(core.IsValid()); - - header.e_ident[2] = ELFMAG2; - ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); - ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); - core.SetContent(mapped_core_file.content()); - EXPECT_FALSE(core.IsValid()); - - header.e_ident[3] = ELFMAG3; - ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); - ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); - core.SetContent(mapped_core_file.content()); - EXPECT_FALSE(core.IsValid()); - - header.e_ident[4] = ElfCoreDump::kClass; - ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); - ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); - core.SetContent(mapped_core_file.content()); - EXPECT_FALSE(core.IsValid()); - - header.e_version = EV_CURRENT; - ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); - ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); - core.SetContent(mapped_core_file.content()); - EXPECT_FALSE(core.IsValid()); - - header.e_type = ET_CORE; - ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header))); - ASSERT_TRUE(mapped_core_file.Map(core_file, 0)); - core.SetContent(mapped_core_file.content()); - EXPECT_TRUE(core.IsValid()); -} - -TEST(ElfCoreDumpTest, ValidCoreFile) { - CrashGenerator crash_generator; - if (!crash_generator.HasDefaultCorePattern()) { - fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped " - "due to non-default core pattern"); - return; - } - - const unsigned kNumOfThreads = 3; - const unsigned kCrashThread = 1; - const int kCrashSignal = SIGABRT; - ASSERT_TRUE(crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread, - kCrashSignal, NULL)); - pid_t expected_crash_thread_id = crash_generator.GetThreadId(kCrashThread); - set<pid_t> expected_thread_ids; - for (unsigned i = 0; i < kNumOfThreads; ++i) { - expected_thread_ids.insert(crash_generator.GetThreadId(i)); - } - -#if defined(__ANDROID__) - struct stat st; - if (stat(crash_generator.GetCoreFilePath().c_str(), &st) != 0) { - fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped " - "due to no core file being generated"); - return; - } -#endif - - MemoryMappedFile mapped_core_file; - ASSERT_TRUE( - mapped_core_file.Map(crash_generator.GetCoreFilePath().c_str(), 0)); - - ElfCoreDump core; - core.SetContent(mapped_core_file.content()); - EXPECT_TRUE(core.IsValid()); - - // Based on write_note_info() in linux/kernel/fs/binfmt_elf.c, notes are - // ordered as follows (NT_PRXFPREG and NT_386_TLS are i386 specific): - // Thread Name Type - // ------------------------------------------------------------------- - // 1st thread CORE NT_PRSTATUS - // process-wide CORE NT_PRPSINFO - // process-wide CORE NT_AUXV - // 1st thread CORE NT_FPREGSET - // 1st thread LINUX NT_PRXFPREG - // 1st thread LINUX NT_386_TLS - // - // 2nd thread CORE NT_PRSTATUS - // 2nd thread CORE NT_FPREGSET - // 2nd thread LINUX NT_PRXFPREG - // 2nd thread LINUX NT_386_TLS - // - // 3rd thread CORE NT_PRSTATUS - // 3rd thread CORE NT_FPREGSET - // 3rd thread LINUX NT_PRXFPREG - // 3rd thread LINUX NT_386_TLS - - size_t num_nt_prpsinfo = 0; - size_t num_nt_prstatus = 0; - size_t num_pr_fpvalid = 0; -#if defined(__i386__) || defined(__x86_64__) - size_t num_nt_fpregset = 0; -#endif -#if defined(__i386__) - size_t num_nt_prxfpreg = 0; -#endif - set<pid_t> actual_thread_ids; - ElfCoreDump::Note note = core.GetFirstNote(); - while (note.IsValid()) { - MemoryRange name = note.GetName(); - MemoryRange description = note.GetDescription(); - EXPECT_FALSE(name.IsEmpty()); - EXPECT_FALSE(description.IsEmpty()); - - switch (note.GetType()) { - case NT_PRPSINFO: { - EXPECT_TRUE(description.data() != NULL); - EXPECT_EQ(sizeof(elf_prpsinfo), description.length()); - ++num_nt_prpsinfo; - break; - } - case NT_PRSTATUS: { - EXPECT_TRUE(description.data() != NULL); - EXPECT_EQ(sizeof(elf_prstatus), description.length()); - const elf_prstatus* status = description.GetData<elf_prstatus>(0); - actual_thread_ids.insert(status->pr_pid); - if (num_nt_prstatus == 0) { - EXPECT_EQ(expected_crash_thread_id, status->pr_pid); - EXPECT_EQ(kCrashSignal, status->pr_info.si_signo); - } - ++num_nt_prstatus; - if (status->pr_fpvalid) - ++num_pr_fpvalid; - break; - } -#if defined(__i386__) || defined(__x86_64__) - case NT_FPREGSET: { - EXPECT_TRUE(description.data() != NULL); - EXPECT_EQ(sizeof(user_fpregs_struct), description.length()); - ++num_nt_fpregset; - break; - } -#endif -#if defined(__i386__) - case NT_PRXFPREG: { - EXPECT_TRUE(description.data() != NULL); - EXPECT_EQ(sizeof(user_fpxregs_struct), description.length()); - ++num_nt_prxfpreg; - break; - } -#endif - default: - break; - } - note = note.GetNextNote(); - } - - EXPECT_TRUE(expected_thread_ids == actual_thread_ids); - EXPECT_EQ(1U, num_nt_prpsinfo); - EXPECT_EQ(kNumOfThreads, num_nt_prstatus); -#if defined(__i386__) || defined(__x86_64__) - EXPECT_EQ(num_pr_fpvalid, num_nt_fpregset); -#endif -#if defined(__i386__) - EXPECT_EQ(num_pr_fpvalid, num_nt_prxfpreg); -#endif -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_gnu_compat.h b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_gnu_compat.h deleted file mode 100644 index f870cbc7d..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_gnu_compat.h +++ /dev/null @@ -1,46 +0,0 @@ -// -*- 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 - -#endif // COMMON_LINUX_ELF_GNU_COMPAT_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.cc deleted file mode 100644 index 562875e11..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.cc +++ /dev/null @@ -1,178 +0,0 @@ -// -*- 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/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.h deleted file mode 100644 index 2e7c09715..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module.h +++ /dev/null @@ -1,58 +0,0 @@ -// -*- 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/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc deleted file mode 100644 index 8984449ab..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/elf_symbols_to_module_unittest.cc +++ /dev/null @@ -1,370 +0,0 @@ -// 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_unittest.cc: -// Unittests for google_breakpad::ELFSymbolsToModule - -#include <elf.h> - -#include <string> -#include <vector> - -#include "breakpad_googletest_includes.h" -#include "common/linux/elf_symbols_to_module.h" -#include "common/linux/synth_elf.h" -#include "common/module.h" -#include "common/test_assembler.h" -#include "common/using_std_string.h" - -using google_breakpad::Module; -using google_breakpad::synth_elf::StringTable; -using google_breakpad::test_assembler::Endianness; -using google_breakpad::test_assembler::kBigEndian; -using google_breakpad::test_assembler::kLittleEndian; -using google_breakpad::test_assembler::Label; -using google_breakpad::test_assembler::Section; -using ::testing::Test; -using ::testing::TestWithParam; -using std::vector; - -class ELFSymbolsToModuleTestFixture { -public: - ELFSymbolsToModuleTestFixture(Endianness endianness, - size_t value_size) : module("a", "b", "c", "d"), - section(endianness), - table(endianness), - value_size(value_size) {} - - bool ProcessSection() { - string section_contents, table_contents; - section.GetContents(§ion_contents); - table.GetContents(&table_contents); - - bool ret = ELFSymbolsToModule(reinterpret_cast<const uint8_t*>(section_contents.data()), - section_contents.size(), - reinterpret_cast<const uint8_t*>(table_contents.data()), - table_contents.size(), - section.endianness() == kBigEndian, - value_size, - &module); - module.GetExterns(&externs, externs.end()); - return ret; - } - - Module module; - Section section; - StringTable table; - string section_contents; - // 4 or 8 (bytes) - size_t value_size; - - vector<Module::Extern *> externs; -}; - -class ELFSymbolsToModuleTest32 : public ELFSymbolsToModuleTestFixture, - public TestWithParam<Endianness> { -public: - ELFSymbolsToModuleTest32() : ELFSymbolsToModuleTestFixture(GetParam(), 4) {} - - void AddElf32Sym(const string& name, uint32_t value, - uint32_t size, unsigned info, uint16_t shndx) { - section - .D32(table.Add(name)) - .D32(value) - .D32(size) - .D8(info) - .D8(0) // other - .D16(shndx); - } -}; - -TEST_P(ELFSymbolsToModuleTest32, NoFuncs) { - ProcessSection(); - - ASSERT_EQ((size_t)0, externs.size()); -} - -TEST_P(ELFSymbolsToModuleTest32, OneFunc) { - const string kFuncName = "superfunc"; - const uint32_t kFuncAddr = 0x1000; - const uint32_t kFuncSize = 0x10; - - AddElf32Sym(kFuncName, kFuncAddr, kFuncSize, - ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), - // Doesn't really matter, just can't be SHN_UNDEF. - SHN_UNDEF + 1); - - ProcessSection(); - - ASSERT_EQ((size_t)1, externs.size()); - Module::Extern *extern1 = externs[0]; - EXPECT_EQ(kFuncName, extern1->name); - EXPECT_EQ((Module::Address)kFuncAddr, extern1->address); -} - -TEST_P(ELFSymbolsToModuleTest32, NameOutOfBounds) { - const string kFuncName = ""; - const uint32_t kFuncAddr = 0x1000; - const uint32_t kFuncSize = 0x10; - - table.Add("Foo"); - table.Add("Bar"); - // Can't use AddElf32Sym because it puts in a valid string offset. - section - .D32((uint32_t)table.Here().Value() + 1) - .D32(kFuncAddr) - .D32(kFuncSize) - .D8(ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)) - .D8(0) // other - .D16(SHN_UNDEF + 1); - - ProcessSection(); - - ASSERT_EQ((size_t)1, externs.size()); - Module::Extern *extern1 = externs[0]; - EXPECT_EQ(kFuncName, extern1->name); - EXPECT_EQ((Module::Address)kFuncAddr, extern1->address); -} - -TEST_P(ELFSymbolsToModuleTest32, NonTerminatedStringTable) { - const string kFuncName = ""; - const uint32_t kFuncAddr = 0x1000; - const uint32_t kFuncSize = 0x10; - - table.Add("Foo"); - table.Add("Bar"); - // Add a non-null-terminated string to the end of the string table - Label l; - table - .Mark(&l) - .Append("Unterminated"); - // Can't use AddElf32Sym because it puts in a valid string offset. - section - .D32((uint32_t)l.Value()) - .D32(kFuncAddr) - .D32(kFuncSize) - .D8(ELF32_ST_INFO(STB_GLOBAL, STT_FUNC)) - .D8(0) // other - .D16(SHN_UNDEF + 1); - - ProcessSection(); - - ASSERT_EQ((size_t)1, externs.size()); - Module::Extern *extern1 = externs[0]; - EXPECT_EQ(kFuncName, extern1->name); - EXPECT_EQ((Module::Address)kFuncAddr, extern1->address); -} - -TEST_P(ELFSymbolsToModuleTest32, MultipleFuncs) { - const string kFuncName1 = "superfunc"; - const uint32_t kFuncAddr1 = 0x10001000; - const uint32_t kFuncSize1 = 0x10; - const string kFuncName2 = "awesomefunc"; - const uint32_t kFuncAddr2 = 0x20002000; - const uint32_t kFuncSize2 = 0x2f; - const string kFuncName3 = "megafunc"; - const uint32_t kFuncAddr3 = 0x30003000; - const uint32_t kFuncSize3 = 0x3c; - - AddElf32Sym(kFuncName1, kFuncAddr1, kFuncSize1, - ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), - // Doesn't really matter, just can't be SHN_UNDEF. - SHN_UNDEF + 1); - AddElf32Sym(kFuncName2, kFuncAddr2, kFuncSize2, - ELF32_ST_INFO(STB_LOCAL, STT_FUNC), - // Doesn't really matter, just can't be SHN_UNDEF. - SHN_UNDEF + 2); - AddElf32Sym(kFuncName3, kFuncAddr3, kFuncSize3, - ELF32_ST_INFO(STB_LOCAL, STT_FUNC), - // Doesn't really matter, just can't be SHN_UNDEF. - SHN_UNDEF + 3); - - ProcessSection(); - - ASSERT_EQ((size_t)3, externs.size()); - Module::Extern *extern1 = externs[0]; - EXPECT_EQ(kFuncName1, extern1->name); - EXPECT_EQ((Module::Address)kFuncAddr1, extern1->address); - Module::Extern *extern2 = externs[1]; - EXPECT_EQ(kFuncName2, extern2->name); - EXPECT_EQ((Module::Address)kFuncAddr2, extern2->address); - Module::Extern *extern3 = externs[2]; - EXPECT_EQ(kFuncName3, extern3->name); - EXPECT_EQ((Module::Address)kFuncAddr3, extern3->address); -} - -TEST_P(ELFSymbolsToModuleTest32, SkipStuff) { - const string kFuncName = "superfunc"; - const uint32_t kFuncAddr = 0x1000; - const uint32_t kFuncSize = 0x10; - - // Should skip functions in SHN_UNDEF - AddElf32Sym("skipme", 0xFFFF, 0x10, - ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), - SHN_UNDEF); - AddElf32Sym(kFuncName, kFuncAddr, kFuncSize, - ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), - // Doesn't really matter, just can't be SHN_UNDEF. - SHN_UNDEF + 1); - // Should skip non-STT_FUNC entries. - AddElf32Sym("skipmetoo", 0xAAAA, 0x10, - ELF32_ST_INFO(STB_GLOBAL, STT_FILE), - SHN_UNDEF + 1); - - ProcessSection(); - - ASSERT_EQ((size_t)1, externs.size()); - Module::Extern *extern1 = externs[0]; - EXPECT_EQ(kFuncName, extern1->name); - EXPECT_EQ((Module::Address)kFuncAddr, extern1->address); -} - -// Run all the 32-bit tests with both endianness -INSTANTIATE_TEST_CASE_P(Endian, - ELFSymbolsToModuleTest32, - ::testing::Values(kLittleEndian, kBigEndian)); - -// Similar tests, but with 64-bit values. Ostensibly this could be -// shoehorned into the parameterization by using ::testing::Combine, -// but that would make it difficult to get the types right since these -// actual test cases aren't parameterized. This could also be written -// as a type-parameterized test, but combining that with a value-parameterized -// test seemed really ugly, and also makes it harder to test 64-bit -// values. -class ELFSymbolsToModuleTest64 : public ELFSymbolsToModuleTestFixture, - public TestWithParam<Endianness> { -public: - ELFSymbolsToModuleTest64() : ELFSymbolsToModuleTestFixture(GetParam(), 8) {} - - void AddElf64Sym(const string& name, uint64_t value, - uint64_t size, unsigned info, uint16_t shndx) { - section - .D32(table.Add(name)) - .D8(info) - .D8(0) // other - .D16(shndx) - .D64(value) - .D64(size); - } -}; - -TEST_P(ELFSymbolsToModuleTest64, NoFuncs) { - ProcessSection(); - - ASSERT_EQ((size_t)0, externs.size()); -} - -TEST_P(ELFSymbolsToModuleTest64, OneFunc) { - const string kFuncName = "superfunc"; - const uint64_t kFuncAddr = 0x1000200030004000ULL; - const uint64_t kFuncSize = 0x1000; - - AddElf64Sym(kFuncName, kFuncAddr, kFuncSize, - ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), - // Doesn't really matter, just can't be SHN_UNDEF. - SHN_UNDEF + 1); - - ProcessSection(); - - ASSERT_EQ((size_t)1, externs.size()); - Module::Extern *extern1 = externs[0]; - EXPECT_EQ(kFuncName, extern1->name); - EXPECT_EQ((Module::Address)kFuncAddr, extern1->address); -} - -TEST_P(ELFSymbolsToModuleTest64, MultipleFuncs) { - const string kFuncName1 = "superfunc"; - const uint64_t kFuncAddr1 = 0x1000100010001000ULL; - const uint64_t kFuncSize1 = 0x1000; - const string kFuncName2 = "awesomefunc"; - const uint64_t kFuncAddr2 = 0x2000200020002000ULL; - const uint64_t kFuncSize2 = 0x2f00; - const string kFuncName3 = "megafunc"; - const uint64_t kFuncAddr3 = 0x3000300030003000ULL; - const uint64_t kFuncSize3 = 0x3c00; - - AddElf64Sym(kFuncName1, kFuncAddr1, kFuncSize1, - ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), - // Doesn't really matter, just can't be SHN_UNDEF. - SHN_UNDEF + 1); - AddElf64Sym(kFuncName2, kFuncAddr2, kFuncSize2, - ELF64_ST_INFO(STB_LOCAL, STT_FUNC), - // Doesn't really matter, just can't be SHN_UNDEF. - SHN_UNDEF + 2); - AddElf64Sym(kFuncName3, kFuncAddr3, kFuncSize3, - ELF64_ST_INFO(STB_LOCAL, STT_FUNC), - // Doesn't really matter, just can't be SHN_UNDEF. - SHN_UNDEF + 3); - - ProcessSection(); - - ASSERT_EQ((size_t)3, externs.size()); - Module::Extern *extern1 = externs[0]; - EXPECT_EQ(kFuncName1, extern1->name); - EXPECT_EQ((Module::Address)kFuncAddr1, extern1->address); - Module::Extern *extern2 = externs[1]; - EXPECT_EQ(kFuncName2, extern2->name); - EXPECT_EQ((Module::Address)kFuncAddr2, extern2->address); - Module::Extern *extern3 = externs[2]; - EXPECT_EQ(kFuncName3, extern3->name); - EXPECT_EQ((Module::Address)kFuncAddr3, extern3->address); -} - -TEST_P(ELFSymbolsToModuleTest64, SkipStuff) { - const string kFuncName = "superfunc"; - const uint64_t kFuncAddr = 0x1000100010001000ULL; - const uint64_t kFuncSize = 0x1000; - - // Should skip functions in SHN_UNDEF - AddElf64Sym("skipme", 0xFFFF, 0x10, - ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), - SHN_UNDEF); - AddElf64Sym(kFuncName, kFuncAddr, kFuncSize, - ELF64_ST_INFO(STB_GLOBAL, STT_FUNC), - // Doesn't really matter, just can't be SHN_UNDEF. - SHN_UNDEF + 1); - // Should skip non-STT_FUNC entries. - AddElf64Sym("skipmetoo", 0xAAAA, 0x10, - ELF64_ST_INFO(STB_GLOBAL, STT_FILE), - SHN_UNDEF + 1); - - ProcessSection(); - - ASSERT_EQ((size_t)1, externs.size()); - Module::Extern *extern1 = externs[0]; - EXPECT_EQ(kFuncName, extern1->name); - EXPECT_EQ((Module::Address)kFuncAddr, extern1->address); -} - -// Run all the 64-bit tests with both endianness -INSTANTIATE_TEST_CASE_P(Endian, - ELFSymbolsToModuleTest64, - ::testing::Values(kLittleEndian, kBigEndian)); diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils-inl.h b/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils-inl.h deleted file mode 100644 index e56b37a9f..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils-inl.h +++ /dev/null @@ -1,74 +0,0 @@ -// 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/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc deleted file mode 100644 index a79391c13..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.cc +++ /dev/null @@ -1,194 +0,0 @@ -// 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); - - 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, - const void **segment_start, - size_t *segment_size) { - typedef typename ElfClass::Ehdr Ehdr; - typedef typename ElfClass::Phdr Phdr; - - assert(elf_base); - assert(segment_start); - assert(segment_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); - - 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) { - *segment_start = elf_base + phdrs[i].p_offset; - *segment_size = phdrs[i].p_filesz; - return; - } - } -} - -} // 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, - int *elfclass) { - 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); - if (elfclass) { - *elfclass = cls; - } - - 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 FindElfSegment(const void *elf_mapped_base, - uint32_t segment_type, - const void **segment_start, - size_t *segment_size, - int *elfclass) { - assert(elf_mapped_base); - assert(segment_start); - assert(segment_size); - - *segment_start = NULL; - *segment_size = 0; - - if (!IsValidElf(elf_mapped_base)) - return false; - - int cls = ElfClass(elf_mapped_base); - if (elfclass) { - *elfclass = cls; - } - - const char* elf_base = - static_cast<const char*>(elf_mapped_base); - - if (cls == ELFCLASS32) { - FindElfClassSegment<ElfClass32>(elf_base, segment_type, - segment_start, segment_size); - return *segment_start != NULL; - } else if (cls == ELFCLASS64) { - FindElfClassSegment<ElfClass64>(elf_base, segment_type, - segment_start, segment_size); - return *segment_start != NULL; - } - - return false; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.h b/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.h deleted file mode 100644 index f34ba8314..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/elfutils.h +++ /dev/null @@ -1,126 +0,0 @@ -// 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> - -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_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_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. If |elfclass| -// is not NULL, set |*elfclass| to the ELF file class. -bool FindElfSection(const void *elf_mapped_base, - const char *section_name, - uint32_t section_type, - const void **section_start, - size_t *section_size, - int *elfclass); - -// 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); - -// Attempt to find the first segment of type |segment_type| in the ELF -// binary data at |elf_mapped_base|. On success, returns true and sets -// |*segment_start| to point to the start of the segment data, and -// and |*segment_size| to the size of the segment's data. If |elfclass| -// is not NULL, set |*elfclass| to the ELF file class. -bool FindElfSegment(const void *elf_mapped_base, - uint32_t segment_type, - const void **segment_start, - size_t *segment_size, - int *elfclass); - -// 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); - -} // namespace google_breakpad - -#endif // COMMON_LINUX_ELFUTILS_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.cc deleted file mode 100644 index 311e03020..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.cc +++ /dev/null @@ -1,202 +0,0 @@ -// 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 { - -// 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. - -template<typename ElfClass> -static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length, - wasteful_vector<uint8_t>& identifier) { - typedef typename ElfClass::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) { - void* note_section; - size_t note_size; - int elfclass; - if ((!FindElfSegment(elf_mapped_base, PT_NOTE, - (const void**)¬e_section, ¬e_size, &elfclass) || - note_size == 0) && - (!FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE, - (const void**)¬e_section, ¬e_size, &elfclass) || - note_size == 0)) { - return false; - } - - if (elfclass == ELFCLASS32) { - return ElfClassBuildIDNoteIdentifier<ElfClass32>(note_section, note_size, - identifier); - } else if (elfclass == ELFCLASS64) { - return ElfClassBuildIDNoteIdentifier<ElfClass64>(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, NULL) || - 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()); -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.h b/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.h deleted file mode 100644 index a1d2fd6ed..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/file_id.h +++ /dev/null @@ -1,87 +0,0 @@ -// 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.h" - -namespace google_breakpad { - -// 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 std::string ConvertIdentifierToUUIDString( - const wasteful_vector<uint8_t>& identifier); - - // Convert the entire |identifier| data to a hex string. - static std::string ConvertIdentifierToString( - const wasteful_vector<uint8_t>& identifier); - - private: - // Storage for the path specified - std::string path_; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_FILE_ID_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/file_id_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/file_id_unittest.cc deleted file mode 100644 index 3a8193034..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/file_id_unittest.cc +++ /dev/null @@ -1,338 +0,0 @@ -// 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. - -// Unit tests for FileID - -#include <elf.h> -#include <stdlib.h> - -#include <string> -#include <vector> - -#include "common/linux/elf_gnu_compat.h" -#include "common/linux/elfutils.h" -#include "common/linux/file_id.h" -#include "common/linux/safe_readlink.h" -#include "common/linux/synth_elf.h" -#include "common/test_assembler.h" -#include "common/tests/auto_tempdir.h" -#include "common/using_std_string.h" -#include "breakpad_googletest_includes.h" - -using namespace google_breakpad; -using google_breakpad::synth_elf::ELF; -using google_breakpad::synth_elf::Notes; -using google_breakpad::test_assembler::kLittleEndian; -using google_breakpad::test_assembler::Section; -using std::vector; -using ::testing::Types; - -namespace { - -// Simply calling Section::Append(size, byte) produces a uninteresting pattern -// that tends to get hashed to 0000...0000. This populates the section with -// data to produce better hashes. -void PopulateSection(Section* section, int size, int prime_number) { - for (int i = 0; i < size; i++) - section->Append(1, (i % prime_number) % 256); -} - -typedef wasteful_vector<uint8_t> id_vector; - -} // namespace - -#ifndef __ANDROID__ -// This test is disabled on Android: It will always fail, since there is no -// 'strip' binary installed on test devices. -TEST(FileIDStripTest, StripSelf) { - // Calculate the File ID of this binary using - // FileID::ElfFileIdentifier, then make a copy of this binary, - // strip it, and ensure that the result is the same. - char exe_name[PATH_MAX]; - ASSERT_TRUE(SafeReadLink("/proc/self/exe", exe_name)); - - // copy our binary to a temp file, and strip it - AutoTempDir temp_dir; - string templ = temp_dir.path() + "/file-id-unittest"; - char cmdline[4096]; - sprintf(cmdline, "cp \"%s\" \"%s\"", exe_name, templ.c_str()); - ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline; - sprintf(cmdline, "chmod u+w \"%s\"", templ.c_str()); - ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline; - sprintf(cmdline, "strip \"%s\"", templ.c_str()); - ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline; - - PageAllocator allocator; - id_vector identifier1(&allocator, kDefaultBuildIdSize); - id_vector identifier2(&allocator, kDefaultBuildIdSize); - - FileID fileid1(exe_name); - EXPECT_TRUE(fileid1.ElfFileIdentifier(identifier1)); - FileID fileid2(templ.c_str()); - EXPECT_TRUE(fileid2.ElfFileIdentifier(identifier2)); - - string identifier_string1 = - FileID::ConvertIdentifierToUUIDString(identifier1); - string identifier_string2 = - FileID::ConvertIdentifierToUUIDString(identifier2); - EXPECT_EQ(identifier_string1, identifier_string2); -} -#endif // !__ANDROID__ - -template<typename ElfClass> -class FileIDTest : public testing::Test { -public: - void GetElfContents(ELF& elf) { - string contents; - ASSERT_TRUE(elf.GetContents(&contents)); - ASSERT_LT(0U, contents.size()); - - elfdata_v.clear(); - elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end()); - elfdata = &elfdata_v[0]; - } - - id_vector make_vector() { - return id_vector(&allocator, kDefaultBuildIdSize); - } - - template<size_t N> - string get_file_id(const uint8_t (&data)[N]) { - id_vector expected_identifier(make_vector()); - expected_identifier.insert(expected_identifier.end(), - &data[0], - data + N); - return FileID::ConvertIdentifierToUUIDString(expected_identifier); - } - - vector<uint8_t> elfdata_v; - uint8_t* elfdata; - PageAllocator allocator; -}; - -typedef Types<ElfClass32, ElfClass64> ElfClasses; - -TYPED_TEST_CASE(FileIDTest, ElfClasses); - -TYPED_TEST(FileIDTest, ElfClass) { - const char expected_identifier_string[] = - "80808080808000000000008080808080"; - const size_t kTextSectionSize = 128; - - ELF elf(EM_386, TypeParam::kClass, kLittleEndian); - Section text(kLittleEndian); - for (size_t i = 0; i < kTextSectionSize; ++i) { - text.D8(i * 3); - } - elf.AddSection(".text", text, SHT_PROGBITS); - elf.Finish(); - this->GetElfContents(elf); - - id_vector identifier(this->make_vector()); - EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, - identifier)); - - string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); - EXPECT_EQ(expected_identifier_string, identifier_string); -} - -TYPED_TEST(FileIDTest, BuildID) { - const uint8_t kExpectedIdentifierBytes[] = - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13}; - const string expected_identifier_string = - this->get_file_id(kExpectedIdentifierBytes); - - ELF elf(EM_386, TypeParam::kClass, kLittleEndian); - Section text(kLittleEndian); - text.Append(4096, 0); - elf.AddSection(".text", text, SHT_PROGBITS); - Notes notes(kLittleEndian); - notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, - sizeof(kExpectedIdentifierBytes)); - elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE); - elf.Finish(); - this->GetElfContents(elf); - - id_vector identifier(this->make_vector()); - EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, - identifier)); - EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size()); - - string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); - EXPECT_EQ(expected_identifier_string, identifier_string); -} - -// Test that a build id note with fewer bytes than usual is handled. -TYPED_TEST(FileIDTest, BuildIDShort) { - const uint8_t kExpectedIdentifierBytes[] = - {0x00, 0x01, 0x02, 0x03}; - const string expected_identifier_string = - this->get_file_id(kExpectedIdentifierBytes); - - ELF elf(EM_386, TypeParam::kClass, kLittleEndian); - Section text(kLittleEndian); - text.Append(4096, 0); - elf.AddSection(".text", text, SHT_PROGBITS); - Notes notes(kLittleEndian); - notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, - sizeof(kExpectedIdentifierBytes)); - elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE); - elf.Finish(); - this->GetElfContents(elf); - - id_vector identifier(this->make_vector()); - EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, - identifier)); - EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size()); - - string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); - EXPECT_EQ(expected_identifier_string, identifier_string); -} - -// Test that a build id note with more bytes than usual is handled. -TYPED_TEST(FileIDTest, BuildIDLong) { - const uint8_t kExpectedIdentifierBytes[] = - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}; - const string expected_identifier_string = - this->get_file_id(kExpectedIdentifierBytes); - - ELF elf(EM_386, TypeParam::kClass, kLittleEndian); - Section text(kLittleEndian); - text.Append(4096, 0); - elf.AddSection(".text", text, SHT_PROGBITS); - Notes notes(kLittleEndian); - notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, - sizeof(kExpectedIdentifierBytes)); - elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE); - elf.Finish(); - this->GetElfContents(elf); - - id_vector identifier(this->make_vector()); - EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, - identifier)); - EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size()); - - string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); - EXPECT_EQ(expected_identifier_string, identifier_string); -} - -TYPED_TEST(FileIDTest, BuildIDPH) { - const uint8_t kExpectedIdentifierBytes[] = - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13}; - const string expected_identifier_string = - this->get_file_id(kExpectedIdentifierBytes); - - ELF elf(EM_386, TypeParam::kClass, kLittleEndian); - Section text(kLittleEndian); - text.Append(4096, 0); - elf.AddSection(".text", text, SHT_PROGBITS); - Notes notes(kLittleEndian); - notes.AddNote(0, "Linux", - reinterpret_cast<const uint8_t *>("\0x42\0x02\0\0"), 4); - notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes, - sizeof(kExpectedIdentifierBytes)); - int note_idx = elf.AddSection(".note", notes, SHT_NOTE); - elf.AddSegment(note_idx, note_idx, PT_NOTE); - elf.Finish(); - this->GetElfContents(elf); - - id_vector identifier(this->make_vector()); - EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, - identifier)); - EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size()); - - string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier); - EXPECT_EQ(expected_identifier_string, identifier_string); -} - -// Test to make sure two files with different text sections produce -// different hashes when not using a build id. -TYPED_TEST(FileIDTest, UniqueHashes) { - { - ELF elf1(EM_386, TypeParam::kClass, kLittleEndian); - Section foo_1(kLittleEndian); - PopulateSection(&foo_1, 32, 5); - elf1.AddSection(".foo", foo_1, SHT_PROGBITS); - Section text_1(kLittleEndian); - PopulateSection(&text_1, 4096, 17); - elf1.AddSection(".text", text_1, SHT_PROGBITS); - elf1.Finish(); - this->GetElfContents(elf1); - } - - id_vector identifier_1(this->make_vector()); - EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, - identifier_1)); - string identifier_string_1 = - FileID::ConvertIdentifierToUUIDString(identifier_1); - - { - ELF elf2(EM_386, TypeParam::kClass, kLittleEndian); - Section text_2(kLittleEndian); - Section foo_2(kLittleEndian); - PopulateSection(&foo_2, 32, 5); - elf2.AddSection(".foo", foo_2, SHT_PROGBITS); - PopulateSection(&text_2, 4096, 31); - elf2.AddSection(".text", text_2, SHT_PROGBITS); - elf2.Finish(); - this->GetElfContents(elf2); - } - - id_vector identifier_2(this->make_vector()); - EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata, - identifier_2)); - string identifier_string_2 = - FileID::ConvertIdentifierToUUIDString(identifier_2); - - EXPECT_NE(identifier_string_1, identifier_string_2); -} - -TYPED_TEST(FileIDTest, ConvertIdentifierToString) { - const uint8_t kIdentifierBytes[] = - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}; - const char* kExpected = - "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"; - - id_vector identifier(this->make_vector()); - identifier.insert(identifier.end(), - kIdentifierBytes, - kIdentifierBytes + sizeof(kIdentifierBytes)); - ASSERT_EQ(kExpected, - FileID::ConvertIdentifierToString(identifier)); -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.cc deleted file mode 100644 index 6d86fb369..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.cc +++ /dev/null @@ -1,202 +0,0 @@ -// 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 "common/linux/google_crashdump_uploader.h" - -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> - -#include <iostream> - -#include "common/using_std_string.h" - -namespace google_breakpad { - -GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product, - const string& version, - const string& guid, - const string& ptime, - const string& ctime, - const string& email, - const string& comments, - const string& minidump_pathname, - const string& crash_server, - const string& proxy_host, - const string& proxy_userpassword) { - LibcurlWrapper* http_layer = new LibcurlWrapper(); - Init(product, - version, - guid, - ptime, - ctime, - email, - comments, - minidump_pathname, - crash_server, - proxy_host, - proxy_userpassword, - http_layer); -} - -GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product, - const string& version, - const string& guid, - const string& ptime, - const string& ctime, - const string& email, - const string& comments, - const string& minidump_pathname, - const string& crash_server, - const string& proxy_host, - const string& proxy_userpassword, - LibcurlWrapper* http_layer) { - Init(product, - version, - guid, - ptime, - ctime, - email, - comments, - minidump_pathname, - crash_server, - proxy_host, - proxy_userpassword, - http_layer); -} - -void GoogleCrashdumpUploader::Init(const string& product, - const string& version, - const string& guid, - const string& ptime, - const string& ctime, - const string& email, - const string& comments, - const string& minidump_pathname, - const string& crash_server, - const string& proxy_host, - const string& proxy_userpassword, - LibcurlWrapper* http_layer) { - product_ = product; - version_ = version; - guid_ = guid; - ptime_ = ptime; - ctime_ = ctime; - email_ = email; - comments_ = comments; - http_layer_.reset(http_layer); - - crash_server_ = crash_server; - proxy_host_ = proxy_host; - proxy_userpassword_ = proxy_userpassword; - minidump_pathname_ = minidump_pathname; - std::cout << "Uploader initializing"; - std::cout << "\tProduct: " << product_; - std::cout << "\tVersion: " << version_; - std::cout << "\tGUID: " << guid_; - if (!ptime_.empty()) { - std::cout << "\tProcess uptime: " << ptime_; - } - if (!ctime_.empty()) { - std::cout << "\tCumulative Process uptime: " << ctime_; - } - if (!email_.empty()) { - std::cout << "\tEmail: " << email_; - } - if (!comments_.empty()) { - std::cout << "\tComments: " << comments_; - } -} - -bool GoogleCrashdumpUploader::CheckRequiredParametersArePresent() { - string error_text; - if (product_.empty()) { - error_text.append("\nProduct name must be specified."); - } - - if (version_.empty()) { - error_text.append("\nProduct version must be specified."); - } - - if (guid_.empty()) { - error_text.append("\nClient ID must be specified."); - } - - if (minidump_pathname_.empty()) { - error_text.append("\nMinidump pathname must be specified."); - } - - if (!error_text.empty()) { - std::cout << error_text; - return false; - } - return true; - -} - -bool GoogleCrashdumpUploader::Upload(int* http_status_code, - string* http_response_header, - string* http_response_body) { - bool ok = http_layer_->Init(); - if (!ok) { - std::cout << "http layer init failed"; - return ok; - } - - if (!CheckRequiredParametersArePresent()) { - return false; - } - - struct stat st; - int err = stat(minidump_pathname_.c_str(), &st); - if (err) { - std::cout << minidump_pathname_ << " could not be found"; - return false; - } - - parameters_["prod"] = product_; - parameters_["ver"] = version_; - parameters_["guid"] = guid_; - parameters_["ptime"] = ptime_; - parameters_["ctime"] = ctime_; - parameters_["email"] = email_; - parameters_["comments_"] = comments_; - if (!http_layer_->AddFile(minidump_pathname_, - "upload_file_minidump")) { - return false; - } - std::cout << "Sending request to " << crash_server_; - return http_layer_->SendRequest(crash_server_, - parameters_, - http_status_code, - http_response_header, - http_response_body); -} -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.h b/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.h deleted file mode 100644 index a2d0575b5..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader.h +++ /dev/null @@ -1,107 +0,0 @@ -// 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. - - -#ifndef COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_ -#define COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_ - -#include <string> -#include <map> - -#include "common/linux/libcurl_wrapper.h" -#include "common/scoped_ptr.h" -#include "common/using_std_string.h" - -namespace google_breakpad { - -class GoogleCrashdumpUploader { - public: - GoogleCrashdumpUploader(const string& product, - const string& version, - const string& guid, - const string& ptime, - const string& ctime, - const string& email, - const string& comments, - const string& minidump_pathname, - const string& crash_server, - const string& proxy_host, - const string& proxy_userpassword); - - GoogleCrashdumpUploader(const string& product, - const string& version, - const string& guid, - const string& ptime, - const string& ctime, - const string& email, - const string& comments, - const string& minidump_pathname, - const string& crash_server, - const string& proxy_host, - const string& proxy_userpassword, - LibcurlWrapper* http_layer); - - void Init(const string& product, - const string& version, - const string& guid, - const string& ptime, - const string& ctime, - const string& email, - const string& comments, - const string& minidump_pathname, - const string& crash_server, - const string& proxy_host, - const string& proxy_userpassword, - LibcurlWrapper* http_layer); - bool Upload(int* http_status_code, - string* http_response_header, - string* http_response_body); - - private: - bool CheckRequiredParametersArePresent(); - - scoped_ptr<LibcurlWrapper> http_layer_; - string product_; - string version_; - string guid_; - string ptime_; - string ctime_; - string email_; - string comments_; - string minidump_pathname_; - - string crash_server_; - string proxy_host_; - string proxy_userpassword_; - - std::map<string, string> parameters_; -}; -} - -#endif // COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader_test.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader_test.cc deleted file mode 100644 index e94c5d62a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/google_crashdump_uploader_test.cc +++ /dev/null @@ -1,170 +0,0 @@ -// 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. - -// Unit test for crash dump uploader. - -#include <string> - -#include "common/linux/google_crashdump_uploader.h" -#include "breakpad_googletest_includes.h" -#include "common/using_std_string.h" - -namespace google_breakpad { - -using ::testing::Return; -using ::testing::_; - -class MockLibcurlWrapper : public LibcurlWrapper { - public: - MOCK_METHOD0(Init, bool()); - MOCK_METHOD2(SetProxy, bool(const string& proxy_host, - const string& proxy_userpwd)); - MOCK_METHOD2(AddFile, bool(const string& upload_file_path, - const string& basename)); - MOCK_METHOD5(SendRequest, - bool(const string& url, - const std::map<string, string>& parameters, - int* http_status_code, - string* http_header_data, - string* http_response_data)); -}; - -class GoogleCrashdumpUploaderTest : public ::testing::Test { -}; - -TEST_F(GoogleCrashdumpUploaderTest, InitFailsCausesUploadFailure) { - MockLibcurlWrapper m; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(false)); - GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", - "1.0", - "AAA-BBB", - "", - "", - "test@test.com", - "none", - "/tmp/foo.dmp", - "http://foo.com", - "", - "", - &m); - ASSERT_FALSE(uploader->Upload(NULL, NULL, NULL)); -} - -TEST_F(GoogleCrashdumpUploaderTest, TestSendRequestHappensWithValidParameters) { - // Create a temp file - char tempfn[80] = "/tmp/googletest-upload-XXXXXX"; - int fd = mkstemp(tempfn); - ASSERT_NE(fd, -1); - close(fd); - - MockLibcurlWrapper m; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); - EXPECT_CALL(m, AddFile(tempfn, _)).WillOnce(Return(true)); - EXPECT_CALL(m, - SendRequest("http://foo.com",_,_,_,_)).Times(1).WillOnce(Return(true)); - GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", - "1.0", - "AAA-BBB", - "", - "", - "test@test.com", - "none", - tempfn, - "http://foo.com", - "", - "", - &m); - ASSERT_TRUE(uploader->Upload(NULL, NULL, NULL)); -} - - -TEST_F(GoogleCrashdumpUploaderTest, InvalidPathname) { - MockLibcurlWrapper m; - EXPECT_CALL(m, Init()).Times(1).WillOnce(Return(true)); - EXPECT_CALL(m, SendRequest(_,_,_,_,_)).Times(0); - GoogleCrashdumpUploader *uploader = new GoogleCrashdumpUploader("foobar", - "1.0", - "AAA-BBB", - "", - "", - "test@test.com", - "none", - "/tmp/foo.dmp", - "http://foo.com", - "", - "", - &m); - ASSERT_FALSE(uploader->Upload(NULL, NULL, NULL)); -} - -TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) { - // Test with empty product name. - GoogleCrashdumpUploader uploader("", - "1.0", - "AAA-BBB", - "", - "", - "test@test.com", - "none", - "/tmp/foo.dmp", - "http://foo.com", - "", - ""); - ASSERT_FALSE(uploader.Upload(NULL, NULL, NULL)); - - // Test with empty product version. - GoogleCrashdumpUploader uploader1("product", - "", - "AAA-BBB", - "", - "", - "", - "", - "/tmp/foo.dmp", - "", - "", - ""); - - ASSERT_FALSE(uploader1.Upload(NULL, NULL, NULL)); - - // Test with empty client GUID. - GoogleCrashdumpUploader uploader2("product", - "1.0", - "", - "", - "", - "", - "", - "/tmp/foo.dmp", - "", - "", - ""); - ASSERT_FALSE(uploader2.Upload(NULL, NULL, NULL)); -} -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.cc deleted file mode 100644 index bfb308ee2..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.cc +++ /dev/null @@ -1,104 +0,0 @@ -// 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/guid_creator.h" - -#include <assert.h> -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> -#include <time.h> -#include <unistd.h> - -// -// 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) { - InitOnce(); - guid->data1 = random(); - guid->data2 = (uint16_t)(random()); - guid->data3 = (uint16_t)(random()); - UInt32ToBytes(&guid->data4[0], random()); - UInt32ToBytes(&guid->data4[4], random()); - return true; - } - - private: - static void InitOnce() { - pthread_once(&once_control, &InitOnceImpl); - } - - static void InitOnceImpl() { - srandom(time(NULL)); - } - - static pthread_once_t once_control; -}; - -pthread_once_t GUIDGenerator::once_control = PTHREAD_ONCE_INIT; - -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/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.h b/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.h deleted file mode 100644 index c86d856c4..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/guid_creator.h +++ /dev/null @@ -1,48 +0,0 @@ -// 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/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.cc deleted file mode 100644 index 702526af7..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.cc +++ /dev/null @@ -1,230 +0,0 @@ -// 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> ¶meters, - 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> ¶meters) { - 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/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.h b/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.h deleted file mode 100644 index bc1d5d570..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/http_upload.h +++ /dev/null @@ -1,90 +0,0 @@ -// 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> ¶meters, - 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> ¶meters); - - // 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/toolkit/crashreporter/google-breakpad/src/common/linux/ignore_ret.h b/toolkit/crashreporter/google-breakpad/src/common/linux/ignore_ret.h deleted file mode 100644 index efd274c20..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/ignore_ret.h +++ /dev/null @@ -1,40 +0,0 @@ -// 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/toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.cc deleted file mode 100644 index fd4e34cd8..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.cc +++ /dev/null @@ -1,241 +0,0 @@ -// 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), - formpost_(NULL), - lastptr_(NULL), - headerlist_(NULL) { - 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; - } - std::cout << "LibcurlWrapper init succeeded"; - init_ok_ = true; - return; -} - -LibcurlWrapper::~LibcurlWrapper() {} - -bool LibcurlWrapper::SetProxy(const string& proxy_host, - const string& proxy_userpwd) { - if (!init_ok_) { - 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 (!init_ok_) { - 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, - int* http_status_code, - string* http_header_data, - string* http_response_data) { - (*easy_setopt_)(curl_, CURLOPT_URL, url.c_str()); - 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_); - if (http_response_data != NULL) { - 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 != NULL) { - 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 != NULL) { - (*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 - if (headerlist_ != NULL) { - (*slist_free_all_)(headerlist_); - } - - (*easy_cleanup_)(curl_); - if (formpost_ != NULL) { - (*formfree_)(formpost_); - } - - return err_code == CURLE_OK; -} - -bool LibcurlWrapper::Init() { - if (!init_ok_) { - std::cout << "Init_OK was not true in LibcurlWrapper::Init(), check earlier log messages"; - return false; - } - - if (!SetFunctionPointers()) { - std::cout << "Could not find function pointers"; - init_ok_ = false; - return false; - } - - curl_ = (*easy_init_)(); - - last_curl_error_ = "No Error"; - - if (!curl_) { - dlclose(curl_lib_); - std::cout << "Curl initialization failed"; - return false; - } - - // Disable 100-continue header. - char buf[] = "Expect:"; - - headerlist_ = (*slist_append_)(headerlist_, buf); - (*easy_setopt_)(curl_, CURLOPT_HTTPHEADER, headerlist_); - 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(slist_free_all_, - "curl_slist_free_all", - void(*)(curl_slist*)); - - SET_AND_CHECK_FUNCTION_POINTER(formfree_, - "curl_formfree", - void(*)(curl_httppost*)); - return true; -} - -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.h b/toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.h deleted file mode 100644 index 25905ad8f..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/libcurl_wrapper.h +++ /dev/null @@ -1,93 +0,0 @@ -// 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, - int* 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 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 (*formfree_)(struct curl_httppost *); - -}; -} - -#endif // COMMON_LINUX_LIBCURL_WRAPPER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.cc deleted file mode 100644 index 08b0325e6..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.cc +++ /dev/null @@ -1,237 +0,0 @@ -// 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/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.h b/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.h deleted file mode 100644 index ec5a8d6b6..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support.h +++ /dev/null @@ -1,96 +0,0 @@ -// 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/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support_unittest.cc deleted file mode 100644 index adadfed44..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/linux_libc_support_unittest.cc +++ /dev/null @@ -1,213 +0,0 @@ -// 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 "breakpad_googletest_includes.h" -#include "common/linux/linux_libc_support.h" - -namespace { -typedef testing::Test LinuxLibcSupportTest; -} - -TEST(LinuxLibcSupportTest, strlen) { - static const char* test_data[] = { "", "a", "aa", "aaa", "aabc", NULL }; - for (unsigned i = 0; ; ++i) { - if (!test_data[i]) - break; - ASSERT_EQ(strlen(test_data[i]), my_strlen(test_data[i])); - } -} - -TEST(LinuxLibcSupportTest, strcmp) { - static const char* test_data[] = { - "", "", - "a", "", - "", "a", - "a", "b", - "a", "a", - "ab", "aa", - "abc", "ab", - "abc", "abc", - NULL, - }; - - for (unsigned i = 0; ; ++i) { - if (!test_data[i*2]) - break; - int libc_result = strcmp(test_data[i*2], test_data[i*2 + 1]); - if (libc_result > 1) - libc_result = 1; - else if (libc_result < -1) - libc_result = -1; - ASSERT_EQ(my_strcmp(test_data[i*2], test_data[i*2 + 1]), libc_result); - } -} - -TEST(LinuxLibcSupportTest, strtoui) { - int result; - - ASSERT_FALSE(my_strtoui(&result, "")); - ASSERT_FALSE(my_strtoui(&result, "-1")); - ASSERT_FALSE(my_strtoui(&result, "-")); - ASSERT_FALSE(my_strtoui(&result, "a")); - ASSERT_FALSE(my_strtoui(&result, "23472893472938472987987398472398")); - - ASSERT_TRUE(my_strtoui(&result, "0")); - ASSERT_EQ(result, 0); - ASSERT_TRUE(my_strtoui(&result, "1")); - ASSERT_EQ(result, 1); - ASSERT_TRUE(my_strtoui(&result, "12")); - ASSERT_EQ(result, 12); - ASSERT_TRUE(my_strtoui(&result, "123")); - ASSERT_EQ(result, 123); - ASSERT_TRUE(my_strtoui(&result, "0123")); - ASSERT_EQ(result, 123); -} - -TEST(LinuxLibcSupportTest, uint_len) { - ASSERT_EQ(my_uint_len(0), 1U); - ASSERT_EQ(my_uint_len(2), 1U); - ASSERT_EQ(my_uint_len(5), 1U); - ASSERT_EQ(my_uint_len(9), 1U); - ASSERT_EQ(my_uint_len(10), 2U); - ASSERT_EQ(my_uint_len(99), 2U); - ASSERT_EQ(my_uint_len(100), 3U); - ASSERT_EQ(my_uint_len(101), 3U); - ASSERT_EQ(my_uint_len(1000), 4U); - // 0xFFFFFFFFFFFFFFFF - ASSERT_EQ(my_uint_len(18446744073709551615LLU), 20U); -} - -TEST(LinuxLibcSupportTest, uitos) { - char buf[32]; - - my_uitos(buf, 0, 1); - ASSERT_EQ(0, memcmp(buf, "0", 1)); - - my_uitos(buf, 1, 1); - ASSERT_EQ(0, memcmp(buf, "1", 1)); - - my_uitos(buf, 10, 2); - ASSERT_EQ(0, memcmp(buf, "10", 2)); - - my_uitos(buf, 63, 2); - ASSERT_EQ(0, memcmp(buf, "63", 2)); - - my_uitos(buf, 101, 3); - ASSERT_EQ(0, memcmp(buf, "101", 2)); - - // 0xFFFFFFFFFFFFFFFF - my_uitos(buf, 18446744073709551615LLU, 20); - ASSERT_EQ(0, memcmp(buf, "18446744073709551615", 20)); -} - -TEST(LinuxLibcSupportTest, strchr) { - ASSERT_EQ(NULL, my_strchr("abc", 'd')); - ASSERT_EQ(NULL, my_strchr("", 'd')); - ASSERT_EQ(NULL, my_strchr("efghi", 'd')); - - ASSERT_TRUE(my_strchr("a", 'a')); - ASSERT_TRUE(my_strchr("abc", 'a')); - ASSERT_TRUE(my_strchr("bcda", 'a')); - ASSERT_TRUE(my_strchr("sdfasdf", 'a')); - - static const char abc3[] = "abcabcabc"; - ASSERT_EQ(abc3, my_strchr(abc3, 'a')); -} - -TEST(LinuxLibcSupportTest, strrchr) { - ASSERT_EQ(NULL, my_strrchr("abc", 'd')); - ASSERT_EQ(NULL, my_strrchr("", 'd')); - ASSERT_EQ(NULL, my_strrchr("efghi", 'd')); - - ASSERT_TRUE(my_strrchr("a", 'a')); - ASSERT_TRUE(my_strrchr("abc", 'a')); - ASSERT_TRUE(my_strrchr("bcda", 'a')); - ASSERT_TRUE(my_strrchr("sdfasdf", 'a')); - - static const char abc3[] = "abcabcabc"; - ASSERT_EQ(abc3 + 6, my_strrchr(abc3, 'a')); -} - -TEST(LinuxLibcSupportTest, memchr) { - ASSERT_EQ(NULL, my_memchr("abc", 'd', 3)); - ASSERT_EQ(NULL, my_memchr("abcd", 'd', 3)); - ASSERT_EQ(NULL, my_memchr("a", 'a', 0)); - - static const char abc3[] = "abcabcabc"; - ASSERT_EQ(abc3, my_memchr(abc3, 'a', 3)); - ASSERT_EQ(abc3, my_memchr(abc3, 'a', 9)); - ASSERT_EQ(abc3+1, my_memchr(abc3, 'b', 9)); - ASSERT_EQ(abc3+2, my_memchr(abc3, 'c', 9)); -} - -TEST(LinuxLibcSupportTest, read_hex_ptr) { - uintptr_t result; - const char* last; - - last = my_read_hex_ptr(&result, ""); - ASSERT_EQ(result, 0U); - ASSERT_EQ(*last, 0); - - last = my_read_hex_ptr(&result, "0"); - ASSERT_EQ(result, 0U); - ASSERT_EQ(*last, 0); - - last = my_read_hex_ptr(&result, "0123"); - ASSERT_EQ(result, 0x123U); - ASSERT_EQ(*last, 0); - - last = my_read_hex_ptr(&result, "0123a"); - ASSERT_EQ(result, 0x123aU); - ASSERT_EQ(*last, 0); - - last = my_read_hex_ptr(&result, "0123a-"); - ASSERT_EQ(result, 0x123aU); - ASSERT_EQ(*last, '-'); -} - -TEST(LinuxLibcSupportTest, read_decimal_ptr) { - uintptr_t result; - const char* last; - - last = my_read_decimal_ptr(&result, "0"); - ASSERT_EQ(result, 0U); - ASSERT_EQ(*last, 0); - - last = my_read_decimal_ptr(&result, "0123"); - ASSERT_EQ(result, 123U); - ASSERT_EQ(*last, 0); - - last = my_read_decimal_ptr(&result, "1234"); - ASSERT_EQ(result, 1234U); - ASSERT_EQ(*last, 0); - - last = my_read_decimal_ptr(&result, "01234-"); - ASSERT_EQ(result, 1234U); - ASSERT_EQ(*last, '-'); -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.cc deleted file mode 100644 index 4e938269f..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.cc +++ /dev/null @@ -1,107 +0,0 @@ -// 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; - } - - void* data = sys_mmap(NULL, file_len, PROT_READ, MAP_PRIVATE, fd, offset); - sys_close(fd); - if (data == MAP_FAILED) { - return false; - } - - content_.Set(data, file_len - offset); - 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/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.h b/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.h deleted file mode 100644 index fa660cc91..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file.h +++ /dev/null @@ -1,87 +0,0 @@ -// 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/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file_unittest.cc deleted file mode 100644 index fad59f40c..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/memory_mapped_file_unittest.cc +++ /dev/null @@ -1,208 +0,0 @@ -// 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_unittest.cc: -// Unit tests for google_breakpad::MemoryMappedFile. - -#include <fcntl.h> -#include <string.h> -#include <unistd.h> - -#include <string> - -#include "breakpad_googletest_includes.h" -#include "common/linux/memory_mapped_file.h" -#include "common/tests/auto_tempdir.h" -#include "common/tests/file_utils.h" -#include "common/using_std_string.h" - -using google_breakpad::AutoTempDir; -using google_breakpad::MemoryMappedFile; -using google_breakpad::WriteFile; - -namespace { - -class MemoryMappedFileTest : public testing::Test { - protected: - void ExpectNoMappedData(const MemoryMappedFile& mapped_file) { - EXPECT_TRUE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() == NULL); - EXPECT_EQ(0U, mapped_file.size()); - } -}; - -} // namespace - -TEST_F(MemoryMappedFileTest, DefaultConstructor) { - MemoryMappedFile mapped_file; - ExpectNoMappedData(mapped_file); -} - -TEST_F(MemoryMappedFileTest, UnmapWithoutMap) { - MemoryMappedFile mapped_file; - mapped_file.Unmap(); -} - -TEST_F(MemoryMappedFileTest, MapNonexistentFile) { - { - MemoryMappedFile mapped_file("nonexistent-file", 0); - ExpectNoMappedData(mapped_file); - } - { - MemoryMappedFile mapped_file; - EXPECT_FALSE(mapped_file.Map("nonexistent-file", 0)); - ExpectNoMappedData(mapped_file); - } -} - -TEST_F(MemoryMappedFileTest, MapEmptyFile) { - AutoTempDir temp_dir; - string test_file = temp_dir.path() + "/empty_file"; - ASSERT_TRUE(WriteFile(test_file.c_str(), NULL, 0)); - - { - MemoryMappedFile mapped_file(test_file.c_str(), 0); - ExpectNoMappedData(mapped_file); - } - { - MemoryMappedFile mapped_file; - EXPECT_TRUE(mapped_file.Map(test_file.c_str(), 0)); - ExpectNoMappedData(mapped_file); - } -} - -TEST_F(MemoryMappedFileTest, MapNonEmptyFile) { - char data[256]; - size_t data_size = sizeof(data); - for (size_t i = 0; i < data_size; ++i) { - data[i] = i; - } - - AutoTempDir temp_dir; - string test_file = temp_dir.path() + "/test_file"; - ASSERT_TRUE(WriteFile(test_file.c_str(), data, data_size)); - - { - MemoryMappedFile mapped_file(test_file.c_str(), 0); - EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); - EXPECT_EQ(data_size, mapped_file.size()); - EXPECT_EQ(0, memcmp(data, mapped_file.data(), data_size)); - } - { - MemoryMappedFile mapped_file; - EXPECT_TRUE(mapped_file.Map(test_file.c_str(), 0)); - EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); - EXPECT_EQ(data_size, mapped_file.size()); - EXPECT_EQ(0, memcmp(data, mapped_file.data(), data_size)); - } -} - -TEST_F(MemoryMappedFileTest, RemapAfterMap) { - char data1[256]; - size_t data1_size = sizeof(data1); - for (size_t i = 0; i < data1_size; ++i) { - data1[i] = i; - } - - char data2[50]; - size_t data2_size = sizeof(data2); - for (size_t i = 0; i < data2_size; ++i) { - data2[i] = 255 - i; - } - - AutoTempDir temp_dir; - string test_file1 = temp_dir.path() + "/test_file1"; - string test_file2 = temp_dir.path() + "/test_file2"; - ASSERT_TRUE(WriteFile(test_file1.c_str(), data1, data1_size)); - ASSERT_TRUE(WriteFile(test_file2.c_str(), data2, data2_size)); - - { - MemoryMappedFile mapped_file(test_file1.c_str(), 0); - EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); - EXPECT_EQ(data1_size, mapped_file.size()); - EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size)); - - mapped_file.Map(test_file2.c_str(), 0); - EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); - EXPECT_EQ(data2_size, mapped_file.size()); - EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size)); - } - { - MemoryMappedFile mapped_file; - EXPECT_TRUE(mapped_file.Map(test_file1.c_str(), 0)); - EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); - EXPECT_EQ(data1_size, mapped_file.size()); - EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size)); - - mapped_file.Map(test_file2.c_str(), 0); - EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); - EXPECT_EQ(data2_size, mapped_file.size()); - EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size)); - } -} - -TEST_F(MemoryMappedFileTest, MapWithOffset) { - // Put more data in the test file this time. Offsets can only be - // done on page boundaries, so we need a two page file to test this. - const int page_size = 4096; - char data1[2 * page_size]; - size_t data1_size = sizeof(data1); - for (size_t i = 0; i < data1_size; ++i) { - data1[i] = i & 0x7f; - } - - AutoTempDir temp_dir; - string test_file1 = temp_dir.path() + "/test_file1"; - ASSERT_TRUE(WriteFile(test_file1.c_str(), data1, data1_size)); - { - MemoryMappedFile mapped_file(test_file1.c_str(), page_size); - EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); - EXPECT_EQ(data1_size - page_size, mapped_file.size()); - EXPECT_EQ( - 0, - memcmp(data1 + page_size, mapped_file.data(), data1_size - page_size)); - } - { - MemoryMappedFile mapped_file; - mapped_file.Map(test_file1.c_str(), page_size); - EXPECT_FALSE(mapped_file.content().IsEmpty()); - EXPECT_TRUE(mapped_file.data() != NULL); - EXPECT_EQ(data1_size - page_size, mapped_file.size()); - EXPECT_EQ( - 0, - memcmp(data1 + page_size, mapped_file.data(), data1_size - page_size)); - } -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/moz.build b/toolkit/crashreporter/google-breakpad/src/common/linux/moz.build deleted file mode 100644 index 7450f6ba3..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/moz.build +++ /dev/null @@ -1,56 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -UNIFIED_SOURCES += [ - 'elfutils.cc', - 'guid_creator.cc', - 'linux_libc_support.cc', - 'memory_mapped_file.cc', - 'safe_readlink.cc', -] - -# file_id.cc cannot be built in unified mode because it uses a custom DISABLE_STL_WRAPPING -SOURCES += [ - 'file_id.cc', -] - -if CONFIG['OS_TARGET'] != 'Android': - UNIFIED_SOURCES += [ - 'http_upload.cc', - ] - -HostLibrary('host_breakpad_linux_common_s') -HOST_SOURCES += [ - 'crc32.cc', - 'dump_symbols.cc', - 'elf_symbols_to_module.cc', - 'elfutils.cc', - 'file_id.cc', - 'guid_creator.cc', - 'linux_libc_support.cc', - 'memory_mapped_file.cc', -] - -HOST_CXXFLAGS += [ - '-O2', - '-g', -] - -if CONFIG['OS_TARGET'] == 'Android': - LOCAL_INCLUDES += [ - '/toolkit/crashreporter/google-breakpad/src/common/android/include', - ] - -Library('breakpad_linux_common_s') - -FINAL_LIBRARY = 'xul' - -HOST_DEFINES['NO_STABS_SUPPORT'] = True - -include('/toolkit/crashreporter/crashreporter.mozbuild') - -if CONFIG['GNU_CXX']: - CXXFLAGS += ['-Wno-shadow'] diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.cc deleted file mode 100644 index 870c28af3..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.cc +++ /dev/null @@ -1,53 +0,0 @@ -// 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/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.h b/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.h deleted file mode 100644 index 4ae131b58..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink.h +++ /dev/null @@ -1,65 +0,0 @@ -// 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/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink_unittest.cc deleted file mode 100644 index d346b2a80..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/safe_readlink_unittest.cc +++ /dev/null @@ -1,89 +0,0 @@ -// 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_unittest.cc: Unit tests for google_breakpad::SafeReadLink. - -#include "breakpad_googletest_includes.h" -#include "common/linux/safe_readlink.h" - -using google_breakpad::SafeReadLink; - -TEST(SafeReadLinkTest, ZeroBufferSize) { - char buffer[1]; - EXPECT_FALSE(SafeReadLink("/proc/self/exe", buffer, 0)); -} - -TEST(SafeReadLinkTest, BufferSizeTooSmall) { - char buffer[1]; - EXPECT_FALSE(SafeReadLink("/proc/self/exe", buffer, 1)); -} - -TEST(SafeReadLinkTest, BoundaryBufferSize) { - char buffer[PATH_MAX]; - EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer, sizeof(buffer))); - size_t path_length = strlen(buffer); - EXPECT_LT(0U, path_length); - EXPECT_GT(sizeof(buffer), path_length); - - // Buffer size equals to the expected path length plus 1 for the NULL byte. - char buffer2[PATH_MAX]; - EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer2, path_length + 1)); - EXPECT_EQ(path_length, strlen(buffer2)); - EXPECT_EQ(0, strncmp(buffer, buffer2, PATH_MAX)); - - // Buffer size equals to the expected path length. - EXPECT_FALSE(SafeReadLink("/proc/self/exe", buffer, path_length)); -} - -TEST(SafeReadLinkTest, NonexistentPath) { - char buffer[PATH_MAX]; - EXPECT_FALSE(SafeReadLink("nonexistent_path", buffer, sizeof(buffer))); -} - -TEST(SafeReadLinkTest, NonSymbolicLinkPath) { - char actual_path[PATH_MAX]; - EXPECT_TRUE(SafeReadLink("/proc/self/exe", actual_path, sizeof(actual_path))); - - char buffer[PATH_MAX]; - EXPECT_FALSE(SafeReadLink(actual_path, buffer, sizeof(buffer))); -} - -TEST(SafeReadLinkTest, DeduceBufferSizeFromCharArray) { - char buffer[PATH_MAX]; - char* buffer_pointer = buffer; - EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer_pointer, sizeof(buffer))); - size_t path_length = strlen(buffer); - - // Use the template version of SafeReadLink to deduce the buffer size - // from the char array. - char buffer2[PATH_MAX]; - EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer2)); - EXPECT_EQ(path_length, strlen(buffer2)); - EXPECT_EQ(0, strncmp(buffer, buffer2, PATH_MAX)); -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.cc deleted file mode 100644 index bbd3181e1..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.cc +++ /dev/null @@ -1,155 +0,0 @@ -// 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/http_upload.h" -#include "common/linux/symbol_upload.h" - -#include <assert.h> -#include <stdio.h> - -#include <functional> -#include <vector> - -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; -} - -//============================================================================= -void Start(Options *options) { - std::map<string, string> parameters; - options->success = false; - std::vector<string> module_parts; - if (!ModuleDataForSymbolFile(options->symbolsPath, &module_parts)) { - fprintf(stderr, "Failed to parse symbol file!\n"); - return; - } - - string compacted_id = CompactIdentifier(module_parts[3]); - - // 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, - "", - &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"); - } - options->success = success; -} - -} // namespace sym_upload -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.h b/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.h deleted file mode 100644 index 0a469692a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/symbol_upload.h +++ /dev/null @@ -1,59 +0,0 @@ -// -*- 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 { - -typedef struct { - string symbolsPath; - string uploadURLStr; - string proxy; - string proxy_user_pwd; - string version; - bool success; -} Options; - -// 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/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.cc deleted file mode 100644 index 98e81dab7..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.cc +++ /dev/null @@ -1,263 +0,0 @@ -#include "common/linux/synth_elf.h" - -#include <assert.h> -#include <elf.h> -#include <stdio.h> -#include <string.h> - -#include "common/linux/elf_gnu_compat.h" -#include "common/using_std_string.h" - -namespace google_breakpad { -namespace synth_elf { - -ELF::ELF(uint16_t machine, - uint8_t file_class, - Endianness endianness) - : Section(endianness), - addr_size_(file_class == ELFCLASS64 ? 8 : 4), - program_count_(0), - program_header_table_(endianness), - section_count_(0), - section_header_table_(endianness), - section_header_strings_(endianness) { - // Could add support for more machine types here if needed. - assert(machine == EM_386 || - machine == EM_X86_64 || - machine == EM_ARM); - assert(file_class == ELFCLASS32 || file_class == ELFCLASS64); - - start() = 0; - // Add ELF header - // e_ident - // EI_MAG0...EI_MAG3 - D8(ELFMAG0); - D8(ELFMAG1); - D8(ELFMAG2); - D8(ELFMAG3); - // EI_CLASS - D8(file_class); - // EI_DATA - D8(endianness == kLittleEndian ? ELFDATA2LSB : ELFDATA2MSB); - // EI_VERSION - D8(EV_CURRENT); - // EI_OSABI - D8(ELFOSABI_SYSV); - // EI_ABIVERSION - D8(0); - // EI_PAD - Append(7, 0); - assert(Size() == EI_NIDENT); - - // e_type - D16(ET_EXEC); //TODO: allow passing ET_DYN? - // e_machine - D16(machine); - // e_version - D32(EV_CURRENT); - // e_entry - Append(endianness, addr_size_, 0); - // e_phoff - Append(endianness, addr_size_, program_header_label_); - // e_shoff - Append(endianness, addr_size_, section_header_label_); - // e_flags - D32(0); - // e_ehsize - D16(addr_size_ == 8 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr)); - // e_phentsize - D16(addr_size_ == 8 ? sizeof(Elf64_Phdr) : sizeof(Elf32_Phdr)); - // e_phnum - D16(program_count_label_); - // e_shentsize - D16(addr_size_ == 8 ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr)); - // e_shnum - D16(section_count_label_); - // e_shstrndx - D16(section_header_string_index_); - - // Add an empty section for SHN_UNDEF. - Section shn_undef; - AddSection("", shn_undef, SHT_NULL); -} - -int ELF::AddSection(const string& name, const Section& section, - uint32_t type, uint32_t flags, uint64_t addr, - uint32_t link, uint64_t entsize, uint64_t offset) { - Label offset_label; - Label string_label(section_header_strings_.Add(name)); - size_t size = section.Size(); - - int index = section_count_; - ++section_count_; - - section_header_table_ - // sh_name - .D32(string_label) - // sh_type - .D32(type) - // sh_flags - .Append(endianness(), addr_size_, flags) - // sh_addr - .Append(endianness(), addr_size_, addr) - // sh_offset - .Append(endianness(), addr_size_, offset_label) - // sh_size - .Append(endianness(), addr_size_, size) - // sh_link - .D32(link) - // sh_info - .D32(0) - // sh_addralign - .Append(endianness(), addr_size_, 0) - // sh_entsize - .Append(endianness(), addr_size_, entsize); - - sections_.push_back(ElfSection(section, type, addr, offset, offset_label, - size)); - return index; -} - -void ELF::AppendSection(ElfSection §ion) { - // NULL and NOBITS sections have no content, so they - // don't need to be written to the file. - if (section.type_ == SHT_NULL) { - section.offset_label_ = 0; - } else if (section.type_ == SHT_NOBITS) { - section.offset_label_ = section.offset_; - } else { - Mark(§ion.offset_label_); - Append(section); - Align(4); - } -} - -void ELF::AddSegment(int start, int end, uint32_t type, uint32_t flags) { - assert(start > 0); - assert(size_t(start) < sections_.size()); - assert(end > 0); - assert(size_t(end) < sections_.size()); - ++program_count_; - - // p_type - program_header_table_.D32(type); - - if (addr_size_ == 8) { - // p_flags - program_header_table_.D32(flags); - } - - size_t filesz = 0; - size_t memsz = 0; - bool prev_was_nobits = false; - for (int i = start; i <= end; ++i) { - size_t size = sections_[i].size_; - if (sections_[i].type_ != SHT_NOBITS) { - assert(!prev_was_nobits); - // non SHT_NOBITS sections are 4-byte aligned (see AddSection) - size = (size + 3) & ~3; - filesz += size; - } else { - prev_was_nobits = true; - } - memsz += size; - } - - program_header_table_ - // p_offset - .Append(endianness(), addr_size_, sections_[start].offset_label_) - // p_vaddr - .Append(endianness(), addr_size_, sections_[start].addr_) - // p_paddr - .Append(endianness(), addr_size_, sections_[start].addr_) - // p_filesz - .Append(endianness(), addr_size_, filesz) - // p_memsz - .Append(endianness(), addr_size_, memsz); - - if (addr_size_ == 4) { - // p_flags - program_header_table_.D32(flags); - } - - // p_align - program_header_table_.Append(endianness(), addr_size_, 0); -} - -void ELF::Finish() { - // Add the section header string table at the end. - section_header_string_index_ = section_count_; - //printf(".shstrtab size: %ld\n", section_header_strings_.Size()); - AddSection(".shstrtab", section_header_strings_, SHT_STRTAB); - //printf("section_count_: %ld, sections_.size(): %ld\n", - // section_count_, sections_.size()); - if (program_count_) { - Mark(&program_header_label_); - Append(program_header_table_); - } else { - program_header_label_ = 0; - } - - for (vector<ElfSection>::iterator it = sections_.begin(); - it < sections_.end(); ++it) { - AppendSection(*it); - } - section_count_label_ = section_count_; - program_count_label_ = program_count_; - - // Section header table starts here. - Mark(§ion_header_label_); - Append(section_header_table_); -} - -SymbolTable::SymbolTable(Endianness endianness, - size_t addr_size, - StringTable& table) : Section(endianness), - table_(table) { -#ifndef NDEBUG - addr_size_ = addr_size; -#endif - assert(addr_size_ == 4 || addr_size_ == 8); -} - -void SymbolTable::AddSymbol(const string& name, uint32_t value, - uint32_t size, unsigned info, uint16_t shndx) { - assert(addr_size_ == 4); - D32(table_.Add(name)); - D32(value); - D32(size); - D8(info); - D8(0); // other - D16(shndx); -} - -void SymbolTable::AddSymbol(const string& name, uint64_t value, - uint64_t size, unsigned info, uint16_t shndx) { - assert(addr_size_ == 8); - D32(table_.Add(name)); - D8(info); - D8(0); // other - D16(shndx); - D64(value); - D64(size); -} - -void Notes::AddNote(int type, const string &name, const uint8_t* desc_bytes, - size_t desc_size) { - // Elf32_Nhdr and Elf64_Nhdr are exactly the same. - Elf32_Nhdr note_header; - memset(¬e_header, 0, sizeof(note_header)); - note_header.n_namesz = name.length() + 1; - note_header.n_descsz = desc_size; - note_header.n_type = type; - - Append(reinterpret_cast<const uint8_t*>(¬e_header), - sizeof(note_header)); - AppendCString(name); - Align(4); - Append(desc_bytes, desc_size); - Align(4); -} - -} // namespace synth_elf -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.h b/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.h deleted file mode 100644 index 1d2a20ca2..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf.h +++ /dev/null @@ -1,197 +0,0 @@ -// -*- 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> - -// synth_elf.h: Interface to synth_elf::ELF: fake ELF generator. - -#ifndef COMMON_LINUX_SYNTH_ELF_H_ -#define COMMON_LINUX_SYNTH_ELF_H_ - -#include "common/test_assembler.h" - -#include <list> -#include <vector> -#include <map> -#include <string> -#include <utility> - -#include "common/using_std_string.h" - -namespace google_breakpad { -namespace synth_elf { - -using std::list; -using std::vector; -using std::map; -using std::pair; -using test_assembler::Endianness; -using test_assembler::kLittleEndian; -using test_assembler::kUnsetEndian; -using test_assembler::Label; -using test_assembler::Section; - -// String tables are common in ELF headers, so subclass Section -// to make them easy to generate. -class StringTable : public Section { -public: - StringTable(Endianness endianness = kUnsetEndian) - : Section(endianness) { - start() = 0; - empty_string = Add(""); - } - - // Add the string s to the string table, and return - // a label containing the offset into the string table - // at which it was added. - Label Add(const string& s) { - if (strings_.find(s) != strings_.end()) - return strings_[s]; - - Label string_label(Here()); - AppendCString(s); - strings_[s] = string_label; - return string_label; - } - - // All StringTables contain an empty string as their first - // entry. - Label empty_string; - - // Avoid inserting duplicate strings. - map<string,Label> strings_; -}; - -// A Section representing an entire ELF file. -class ELF : public Section { - public: - ELF(uint16_t machine, // EM_386, etc - uint8_t file_class, // ELFCLASS{32,64} - Endianness endianness = kLittleEndian); - - // Add the Section section to the section header table and append it - // to the file. Returns the index of the section in the section - // header table. - int AddSection(const string& name, const Section& section, - uint32_t type, uint32_t flags = 0, uint64_t addr = 0, - uint32_t link = 0, uint64_t entsize = 0, uint64_t offset = 0); - - // Add a segment containing from section index start to section index end. - // The indexes must have been gotten from AddSection. - void AddSegment(int start, int end, uint32_t type, uint32_t flags = 0); - - // Write out all data. GetContents may be used after this. - void Finish(); - - private: - // Size of an address, in bytes. - const size_t addr_size_; - - // Offset to the program header table. - Label program_header_label_; - // Number of entries in the program header table. - int program_count_; - Label program_count_label_; - // The program header table itself. - Section program_header_table_; - - // Offset to the section header table. - Label section_header_label_; - // Number of entries in the section header table. - int section_count_; - Label section_count_label_; - // The section header table itself. - Section section_header_table_; - - // Index of the section header string table in the section - // header table. - Label section_header_string_index_; - // Section containing the names of section header table entries. - StringTable section_header_strings_; - - // Record of an added section - struct ElfSection : public Section { - ElfSection(const Section& section, uint32_t type, uint32_t addr, - uint32_t offset, Label offset_label, uint32_t size) - : Section(section), type_(type), addr_(addr), offset_(offset) - , offset_label_(offset_label), size_(size) { - } - - uint32_t type_; - uint32_t addr_; - uint32_t offset_; - Label offset_label_; - uint32_t size_; - }; - - vector<ElfSection> sections_; - - void AppendSection(ElfSection §ion); -}; - -// A class to build .symtab or .dynsym sections. -class SymbolTable : public Section { - public: - // table is the StringTable that contains symbol names. The caller - // must ensure that it remains alive for the life of the - // SymbolTable. - SymbolTable(Endianness endianness, size_t addr_size, StringTable& table); - - // Add an Elf32_Sym. - void AddSymbol(const string& name, uint32_t value, - uint32_t size, unsigned info, uint16_t shndx); - // Add an Elf64_Sym. - void AddSymbol(const string& name, uint64_t value, - uint64_t size, unsigned info, uint16_t shndx); - - private: -#ifndef NDEBUG - size_t addr_size_; -#endif - StringTable& table_; -}; - -// A class for note sections -class Notes : public Section { -public: - Notes(Endianness endianness) - : Section(endianness) { - } - - // Add a note. - void AddNote(int type, const string &name, const uint8_t* desc_bytes, - size_t desc_size); -}; - -} // namespace synth_elf -} // namespace google_breakpad - -#endif // COMMON_LINUX_SYNTH_ELF_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf_unittest.cc deleted file mode 100644 index 3715b6e60..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/synth_elf_unittest.cc +++ /dev/null @@ -1,413 +0,0 @@ -// 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> - -// synth_elf_unittest.cc: -// Unittests for google_breakpad::synth_elf::ELF - -#include <elf.h> - -#include "breakpad_googletest_includes.h" -#include "common/linux/elfutils.h" -#include "common/linux/synth_elf.h" -#include "common/using_std_string.h" - -using google_breakpad::ElfClass32; -using google_breakpad::ElfClass64; -using google_breakpad::synth_elf::ELF; -using google_breakpad::synth_elf::Notes; -using google_breakpad::synth_elf::Section; -using google_breakpad::synth_elf::StringTable; -using google_breakpad::synth_elf::SymbolTable; -using google_breakpad::test_assembler::Endianness; -using google_breakpad::test_assembler::kBigEndian; -using google_breakpad::test_assembler::kLittleEndian; -using google_breakpad::test_assembler::Label; -using ::testing::Test; -using ::testing::Types; - -class StringTableTest : public Test { -public: - StringTableTest() : table(kLittleEndian) {} - - StringTable table; -}; - -TEST_F(StringTableTest, Empty) { - EXPECT_EQ(1U, table.Size()); - string contents; - ASSERT_TRUE(table.GetContents(&contents)); - const char* kExpectedContents = "\0"; - EXPECT_EQ(0, memcmp(kExpectedContents, - contents.c_str(), - contents.size())); - ASSERT_TRUE(table.empty_string.IsKnownConstant()); - EXPECT_EQ(0U, table.empty_string.Value()); -} - -TEST_F(StringTableTest, Basic) { - const string s1("table fills with strings"); - const string s2("offsets preserved as labels"); - const string s3("verified with tests"); - const char* kExpectedContents = - "\0table fills with strings\0" - "offsets preserved as labels\0" - "verified with tests\0"; - Label l1(table.Add(s1)); - Label l2(table.Add(s2)); - Label l3(table.Add(s3)); - string contents; - ASSERT_TRUE(table.GetContents(&contents)); - EXPECT_EQ(0, memcmp(kExpectedContents, - contents.c_str(), - contents.size())); - // empty_string is at zero, other strings start at 1. - ASSERT_TRUE(l1.IsKnownConstant()); - EXPECT_EQ(1U, l1.Value()); - // Each string has an extra byte for a trailing null. - EXPECT_EQ(1 + s1.length() + 1, l2.Value()); - EXPECT_EQ(1 + s1.length() + 1 + s2.length() + 1, l3.Value()); -} - -TEST_F(StringTableTest, Duplicates) { - const string s1("string 1"); - const string s2("string 2"); - const string s3(""); - const char* kExpectedContents = "\0string 1\0string 2\0"; - Label l1(table.Add(s1)); - Label l2(table.Add(s2)); - // Adding strings twice should return the same Label. - Label l3(table.Add(s3)); - Label l4(table.Add(s2)); - string contents; - ASSERT_TRUE(table.GetContents(&contents)); - EXPECT_EQ(0, memcmp(kExpectedContents, - contents.c_str(), - contents.size())); - EXPECT_EQ(0U, table.empty_string.Value()); - EXPECT_EQ(table.empty_string.Value(), l3.Value()); - EXPECT_EQ(l2.Value(), l4.Value()); -} - -class SymbolTableTest : public Test {}; - -TEST_F(SymbolTableTest, Simple32) { - StringTable table(kLittleEndian); - SymbolTable syms(kLittleEndian, 4, table); - - const string kFuncName1 = "superfunc"; - const uint32_t kFuncAddr1 = 0x10001000; - const uint32_t kFuncSize1 = 0x10; - const string kFuncName2 = "awesomefunc"; - const uint32_t kFuncAddr2 = 0x20002000; - const uint32_t kFuncSize2 = 0x2f; - const string kFuncName3 = "megafunc"; - const uint32_t kFuncAddr3 = 0x30003000; - const uint32_t kFuncSize3 = 0x3c; - - syms.AddSymbol(kFuncName1, kFuncAddr1, kFuncSize1, - ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), - SHN_UNDEF + 1); - syms.AddSymbol(kFuncName2, kFuncAddr2, kFuncSize2, - ELF32_ST_INFO(STB_LOCAL, STT_FUNC), - SHN_UNDEF + 2); - syms.AddSymbol(kFuncName3, kFuncAddr3, kFuncSize3, - ELF32_ST_INFO(STB_LOCAL, STT_FUNC), - SHN_UNDEF + 3); - - const char kExpectedStringTable[] = "\0superfunc\0awesomefunc\0megafunc"; - const size_t kExpectedStringTableSize = sizeof(kExpectedStringTable); - EXPECT_EQ(kExpectedStringTableSize, table.Size()); - string table_contents; - table.GetContents(&table_contents); - EXPECT_EQ(0, memcmp(kExpectedStringTable, - table_contents.c_str(), - table_contents.size())); - - const uint8_t kExpectedSymbolContents[] = { - // Symbol 1 - 0x01, 0x00, 0x00, 0x00, // name - 0x00, 0x10, 0x00, 0x10, // value - 0x10, 0x00, 0x00, 0x00, // size - ELF32_ST_INFO(STB_GLOBAL, STT_FUNC), // info - 0x00, // other - 0x01, 0x00, // shndx - // Symbol 2 - 0x0B, 0x00, 0x00, 0x00, // name - 0x00, 0x20, 0x00, 0x20, // value - 0x2f, 0x00, 0x00, 0x00, // size - ELF32_ST_INFO(STB_LOCAL, STT_FUNC), // info - 0x00, // other - 0x02, 0x00, // shndx - // Symbol 3 - 0x17, 0x00, 0x00, 0x00, // name - 0x00, 0x30, 0x00, 0x30, // value - 0x3c, 0x00, 0x00, 0x00, // size - ELF32_ST_INFO(STB_LOCAL, STT_FUNC), // info - 0x00, // other - 0x03, 0x00, // shndx - }; - const size_t kExpectedSymbolSize = sizeof(kExpectedSymbolContents); - EXPECT_EQ(kExpectedSymbolSize, syms.Size()); - - string symbol_contents; - syms.GetContents(&symbol_contents); - EXPECT_EQ(0, memcmp(kExpectedSymbolContents, - symbol_contents.c_str(), - symbol_contents.size())); -} - -template<typename ElfClass> -class BasicElf : public Test {}; - -// Doesn't seem worthwhile writing the tests to be endian-independent -// when they're unlikely to ever be run on big-endian systems. -#if defined(__i386__) || defined(__x86_64__) - -typedef Types<ElfClass32, ElfClass64> ElfClasses; - -TYPED_TEST_CASE(BasicElf, ElfClasses); - -TYPED_TEST(BasicElf, EmptyLE) { - typedef typename TypeParam::Ehdr Ehdr; - typedef typename TypeParam::Phdr Phdr; - typedef typename TypeParam::Shdr Shdr; - const size_t kStringTableSize = sizeof("\0.shstrtab"); - const size_t kStringTableAlign = 4 - kStringTableSize % 4; - const size_t kExpectedSize = sizeof(Ehdr) + - // Two sections, SHT_NULL + the section header string table. - 2 * sizeof(Shdr) + - kStringTableSize + kStringTableAlign; - - // It doesn't really matter that the machine type is right for the class. - ELF elf(EM_386, TypeParam::kClass, kLittleEndian); - elf.Finish(); - EXPECT_EQ(kExpectedSize, elf.Size()); - - string contents; - ASSERT_TRUE(elf.GetContents(&contents)); - ASSERT_EQ(kExpectedSize, contents.size()); - const Ehdr* header = - reinterpret_cast<const Ehdr*>(contents.data()); - const uint8_t kIdent[] = { - ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, - TypeParam::kClass, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV, - 0, 0, 0, 0, 0, 0, 0, 0 - }; - EXPECT_EQ(0, memcmp(kIdent, header->e_ident, sizeof(kIdent))); - EXPECT_EQ(ET_EXEC, header->e_type); - EXPECT_EQ(EM_386, header->e_machine); - EXPECT_EQ(static_cast<unsigned int>(EV_CURRENT), header->e_version); - EXPECT_EQ(0U, header->e_entry); - EXPECT_EQ(0U, header->e_phoff); - EXPECT_EQ(sizeof(Ehdr) + kStringTableSize + kStringTableAlign, - header->e_shoff); - EXPECT_EQ(0U, header->e_flags); - EXPECT_EQ(sizeof(Ehdr), header->e_ehsize); - EXPECT_EQ(sizeof(Phdr), header->e_phentsize); - EXPECT_EQ(0, header->e_phnum); - EXPECT_EQ(sizeof(Shdr), header->e_shentsize); - EXPECT_EQ(2, header->e_shnum); - EXPECT_EQ(1, header->e_shstrndx); - - const Shdr* shdr = - reinterpret_cast<const Shdr*>(contents.data() + header->e_shoff); - EXPECT_EQ(0U, shdr[0].sh_name); - EXPECT_EQ(static_cast<unsigned int>(SHT_NULL), shdr[0].sh_type); - EXPECT_EQ(0U, shdr[0].sh_flags); - EXPECT_EQ(0U, shdr[0].sh_addr); - EXPECT_EQ(0U, shdr[0].sh_offset); - EXPECT_EQ(0U, shdr[0].sh_size); - EXPECT_EQ(0U, shdr[0].sh_link); - EXPECT_EQ(0U, shdr[0].sh_info); - EXPECT_EQ(0U, shdr[0].sh_addralign); - EXPECT_EQ(0U, shdr[0].sh_entsize); - - EXPECT_EQ(1U, shdr[1].sh_name); - EXPECT_EQ(static_cast<unsigned int>(SHT_STRTAB), shdr[1].sh_type); - EXPECT_EQ(0U, shdr[1].sh_flags); - EXPECT_EQ(0U, shdr[1].sh_addr); - EXPECT_EQ(sizeof(Ehdr), shdr[1].sh_offset); - EXPECT_EQ(kStringTableSize, shdr[1].sh_size); - EXPECT_EQ(0U, shdr[1].sh_link); - EXPECT_EQ(0U, shdr[1].sh_info); - EXPECT_EQ(0U, shdr[1].sh_addralign); - EXPECT_EQ(0U, shdr[1].sh_entsize); -} - -TYPED_TEST(BasicElf, BasicLE) { - typedef typename TypeParam::Ehdr Ehdr; - typedef typename TypeParam::Phdr Phdr; - typedef typename TypeParam::Shdr Shdr; - const size_t kStringTableSize = sizeof("\0.text\0.bss\0.shstrtab"); - const size_t kStringTableAlign = 4 - kStringTableSize % 4; - const size_t kExpectedSize = sizeof(Ehdr) + - // Four sections, SHT_NULL + the section header string table + - // 4096 bytes of the size-aligned .text section + one program header. - sizeof(Phdr) + 4 * sizeof(Shdr) + 4096 + - kStringTableSize + kStringTableAlign; - - // It doesn't really matter that the machine type is right for the class. - ELF elf(EM_386, TypeParam::kClass, kLittleEndian); - Section text(kLittleEndian); - text.Append(4094, 0); - int text_idx = elf.AddSection(".text", text, SHT_PROGBITS); - Section bss(kLittleEndian); - bss.Append(16, 0); - int bss_idx = elf.AddSection(".bss", bss, SHT_NOBITS); - elf.AddSegment(text_idx, bss_idx, PT_LOAD); - elf.Finish(); - EXPECT_EQ(kExpectedSize, elf.Size()); - - string contents; - ASSERT_TRUE(elf.GetContents(&contents)); - ASSERT_EQ(kExpectedSize, contents.size()); - const Ehdr* header = - reinterpret_cast<const Ehdr*>(contents.data()); - const uint8_t kIdent[] = { - ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3, - TypeParam::kClass, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV, - 0, 0, 0, 0, 0, 0, 0, 0 - }; - EXPECT_EQ(0, memcmp(kIdent, header->e_ident, sizeof(kIdent))); - EXPECT_EQ(ET_EXEC, header->e_type); - EXPECT_EQ(EM_386, header->e_machine); - EXPECT_EQ(static_cast<unsigned int>(EV_CURRENT), header->e_version); - EXPECT_EQ(0U, header->e_entry); - EXPECT_EQ(sizeof(Ehdr), header->e_phoff); - EXPECT_EQ(sizeof(Ehdr) + sizeof(Phdr) + 4096 + kStringTableSize + - kStringTableAlign, header->e_shoff); - EXPECT_EQ(0U, header->e_flags); - EXPECT_EQ(sizeof(Ehdr), header->e_ehsize); - EXPECT_EQ(sizeof(Phdr), header->e_phentsize); - EXPECT_EQ(1, header->e_phnum); - EXPECT_EQ(sizeof(Shdr), header->e_shentsize); - EXPECT_EQ(4, header->e_shnum); - EXPECT_EQ(3, header->e_shstrndx); - - const Shdr* shdr = - reinterpret_cast<const Shdr*>(contents.data() + header->e_shoff); - EXPECT_EQ(0U, shdr[0].sh_name); - EXPECT_EQ(static_cast<unsigned int>(SHT_NULL), shdr[0].sh_type); - EXPECT_EQ(0U, shdr[0].sh_flags); - EXPECT_EQ(0U, shdr[0].sh_addr); - EXPECT_EQ(0U, shdr[0].sh_offset); - EXPECT_EQ(0U, shdr[0].sh_size); - EXPECT_EQ(0U, shdr[0].sh_link); - EXPECT_EQ(0U, shdr[0].sh_info); - EXPECT_EQ(0U, shdr[0].sh_addralign); - EXPECT_EQ(0U, shdr[0].sh_entsize); - - EXPECT_EQ(1U, shdr[1].sh_name); - EXPECT_EQ(static_cast<unsigned int>(SHT_PROGBITS), shdr[1].sh_type); - EXPECT_EQ(0U, shdr[1].sh_flags); - EXPECT_EQ(0U, shdr[1].sh_addr); - EXPECT_EQ(sizeof(Ehdr) + sizeof(Phdr), shdr[1].sh_offset); - EXPECT_EQ(4094U, shdr[1].sh_size); - EXPECT_EQ(0U, shdr[1].sh_link); - EXPECT_EQ(0U, shdr[1].sh_info); - EXPECT_EQ(0U, shdr[1].sh_addralign); - EXPECT_EQ(0U, shdr[1].sh_entsize); - - EXPECT_EQ(sizeof("\0.text"), shdr[2].sh_name); - EXPECT_EQ(static_cast<unsigned int>(SHT_NOBITS), shdr[2].sh_type); - EXPECT_EQ(0U, shdr[2].sh_flags); - EXPECT_EQ(0U, shdr[2].sh_addr); - EXPECT_EQ(0U, shdr[2].sh_offset); - EXPECT_EQ(16U, shdr[2].sh_size); - EXPECT_EQ(0U, shdr[2].sh_link); - EXPECT_EQ(0U, shdr[2].sh_info); - EXPECT_EQ(0U, shdr[2].sh_addralign); - EXPECT_EQ(0U, shdr[2].sh_entsize); - - EXPECT_EQ(sizeof("\0.text\0.bss"), shdr[3].sh_name); - EXPECT_EQ(static_cast<unsigned int>(SHT_STRTAB), shdr[3].sh_type); - EXPECT_EQ(0U, shdr[3].sh_flags); - EXPECT_EQ(0U, shdr[3].sh_addr); - EXPECT_EQ(sizeof(Ehdr) + sizeof(Phdr) + 4096, shdr[3].sh_offset); - EXPECT_EQ(kStringTableSize, shdr[3].sh_size); - EXPECT_EQ(0U, shdr[3].sh_link); - EXPECT_EQ(0U, shdr[3].sh_info); - EXPECT_EQ(0U, shdr[3].sh_addralign); - EXPECT_EQ(0U, shdr[3].sh_entsize); - - const Phdr* phdr = - reinterpret_cast<const Phdr*>(contents.data() + header->e_phoff); - EXPECT_EQ(static_cast<unsigned int>(PT_LOAD), phdr->p_type); - EXPECT_EQ(sizeof(Ehdr) + sizeof(Phdr), phdr->p_offset); - EXPECT_EQ(0U, phdr->p_vaddr); - EXPECT_EQ(0U, phdr->p_paddr); - EXPECT_EQ(4096U, phdr->p_filesz); - EXPECT_EQ(4096U + 16U, phdr->p_memsz); - EXPECT_EQ(0U, phdr->p_flags); - EXPECT_EQ(0U, phdr->p_align); -} - -class ElfNotesTest : public Test {}; - -TEST_F(ElfNotesTest, Empty) { - Notes notes(kLittleEndian); - string contents; - ASSERT_TRUE(notes.GetContents(&contents)); - EXPECT_EQ(0U, contents.size()); -} - -TEST_F(ElfNotesTest, Notes) { - Notes notes(kLittleEndian); - notes.AddNote(1, "Linux", reinterpret_cast<const uint8_t *>("\x42\x02\0\0"), - 4); - notes.AddNote(2, "a", reinterpret_cast<const uint8_t *>("foobar"), - sizeof("foobar") - 1); - - const uint8_t kExpectedNotesContents[] = { - // Note 1 - 0x06, 0x00, 0x00, 0x00, // name size, including terminating zero - 0x04, 0x00, 0x00, 0x00, // desc size - 0x01, 0x00, 0x00, 0x00, // type - 'L', 'i', 'n', 'u', 'x', 0x00, 0x00, 0x00, // padded "Linux" - 0x42, 0x02, 0x00, 0x00, // desc - // Note 2 - 0x02, 0x00, 0x00, 0x00, // name size - 0x06, 0x00, 0x00, 0x00, // desc size - 0x02, 0x00, 0x00, 0x00, // type - 'a', 0x00, 0x00, 0x00, // padded "a" - 'f', 'o', 'o', 'b', 'a', 'r', 0x00, 0x00, // padded "foobar" - }; - const size_t kExpectedNotesSize = sizeof(kExpectedNotesContents); - EXPECT_EQ(kExpectedNotesSize, notes.Size()); - - string notes_contents; - ASSERT_TRUE(notes.GetContents(¬es_contents)); - EXPECT_EQ(0, memcmp(kExpectedNotesContents, - notes_contents.data(), - notes_contents.size())); -} - -#endif // defined(__i386__) || defined(__x86_64__) diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/tests/auto_testfile.h b/toolkit/crashreporter/google-breakpad/src/common/linux/tests/auto_testfile.h deleted file mode 100644 index 92fe017b9..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/tests/auto_testfile.h +++ /dev/null @@ -1,124 +0,0 @@ -// 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. - -// Utility class for creating a temporary file for unit tests -// that is deleted in the destructor. - -#ifndef GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE -#define GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE - -#include <unistd.h> -#include <sys/types.h> - -#include <string> - -#include "breakpad_googletest_includes.h" -#include "common/linux/eintr_wrapper.h" -#include "common/tests/auto_tempdir.h" - -namespace google_breakpad { - -class AutoTestFile { - public: - // Create a new empty test file. - // test_prefix: (input) test-specific prefix, can't be NULL. - explicit AutoTestFile(const char* test_prefix) { - Init(test_prefix); - } - - // Create a new test file, and fill it with initial data from a C string. - // The terminating zero is not written. - // test_prefix: (input) test-specific prefix, can't be NULL. - // text: (input) initial content. - AutoTestFile(const char* test_prefix, const char* text) { - Init(test_prefix); - if (fd_ >= 0) - WriteText(text, static_cast<size_t>(strlen(text))); - } - - AutoTestFile(const char* test_prefix, const char* text, size_t text_len) { - Init(test_prefix); - if (fd_ >= 0) - WriteText(text, text_len); - } - - // Destroy test file on scope exit. - ~AutoTestFile() { - if (fd_ >= 0) { - close(fd_); - fd_ = -1; - } - } - - // Returns true iff the test file could be created properly. - // Useful in tests inside EXPECT_TRUE(file.IsOk()); - bool IsOk() { - return fd_ >= 0; - } - - // Returns the Posix file descriptor for the test file, or -1 - // If IsOk() returns false. Note: on Windows, this always returns -1. - int GetFd() { - return fd_; - } - - private: - void Init(const char* test_prefix) { - fd_ = -1; - char path_templ[PATH_MAX]; - int ret = snprintf(path_templ, sizeof(path_templ), - TEMPDIR "/%s-unittest.XXXXXX", - test_prefix); - if (ret >= static_cast<int>(sizeof(path_templ))) - return; - - fd_ = mkstemp(path_templ); - if (fd_ < 0) - return; - - unlink(path_templ); - } - - void WriteText(const char* text, size_t text_len) { - ssize_t r = HANDLE_EINTR(write(fd_, text, text_len)); - if (r != static_cast<ssize_t>(text_len)) { - close(fd_); - fd_ = -1; - return; - } - - lseek(fd_, 0, SEEK_SET); - } - - int fd_; -}; - -} // namespace google_breakpad - -#endif // GOOGLE_BREAKPAD_COMMON_LINUX_TESTS_AUTO_TESTFILE diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.cc b/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.cc deleted file mode 100644 index c9491f6f2..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.cc +++ /dev/null @@ -1,322 +0,0 @@ -// 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. - -// crash_generator.cc: Implement google_breakpad::CrashGenerator. -// See crash_generator.h for details. - -#include "common/linux/tests/crash_generator.h" - -#include <pthread.h> -#include <signal.h> -#include <stdio.h> -#include <sys/mman.h> -#include <sys/resource.h> -#include <sys/syscall.h> -#include <sys/wait.h> -#include <unistd.h> - -#include <string> - -#if defined(__ANDROID__) -#include "common/android/testing/pthread_fixes.h" -#endif -#include "common/linux/eintr_wrapper.h" -#include "common/tests/auto_tempdir.h" -#include "common/tests/file_utils.h" -#include "common/using_std_string.h" - -namespace { - -struct ThreadData { - pthread_t thread; - pthread_barrier_t* barrier; - pid_t* thread_id_ptr; -}; - -const char* const kProcFilesToCopy[] = { - "auxv", "cmdline", "environ", "maps", "status" -}; -const size_t kNumProcFilesToCopy = - sizeof(kProcFilesToCopy) / sizeof(kProcFilesToCopy[0]); - -int gettid() { - // Glibc does not provide a wrapper for this. - return syscall(__NR_gettid); -} - -int tkill(pid_t tid, int sig) { - // Glibc does not provide a wrapper for this. - return syscall(__NR_tkill, tid, sig); -} - -// Core file size limit set to 1 MB, which is big enough for test purposes. -const rlim_t kCoreSizeLimit = 1024 * 1024; - -void *thread_function(void *data) { - ThreadData* thread_data = reinterpret_cast<ThreadData*>(data); - volatile pid_t thread_id = gettid(); - *(thread_data->thread_id_ptr) = thread_id; - int result = pthread_barrier_wait(thread_data->barrier); - if (result != 0 && result != PTHREAD_BARRIER_SERIAL_THREAD) { - perror("Failed to wait for sync barrier"); - exit(1); - } - while (true) { - pthread_yield(); - } -} - -} // namespace - -namespace google_breakpad { - -CrashGenerator::CrashGenerator() - : shared_memory_(NULL), - shared_memory_size_(0) { -} - -CrashGenerator::~CrashGenerator() { - UnmapSharedMemory(); -} - -bool CrashGenerator::HasDefaultCorePattern() const { - char buffer[8]; - ssize_t buffer_size = sizeof(buffer); - return ReadFile("/proc/sys/kernel/core_pattern", buffer, &buffer_size) && - buffer_size == 5 && memcmp(buffer, "core", 4) == 0; -} - -string CrashGenerator::GetCoreFilePath() const { - return temp_dir_.path() + "/core"; -} - -string CrashGenerator::GetDirectoryOfProcFilesCopy() const { - return temp_dir_.path() + "/proc"; -} - -pid_t CrashGenerator::GetThreadId(unsigned index) const { - return reinterpret_cast<pid_t*>(shared_memory_)[index]; -} - -pid_t* CrashGenerator::GetThreadIdPointer(unsigned index) { - return reinterpret_cast<pid_t*>(shared_memory_) + index; -} - -bool CrashGenerator::MapSharedMemory(size_t memory_size) { - if (!UnmapSharedMemory()) - return false; - - void* mapped_memory = mmap(0, memory_size, PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS, -1, 0); - if (mapped_memory == MAP_FAILED) { - perror("CrashGenerator: Failed to map shared memory"); - return false; - } - - memset(mapped_memory, 0, memory_size); - shared_memory_ = mapped_memory; - shared_memory_size_ = memory_size; - return true; -} - -bool CrashGenerator::UnmapSharedMemory() { - if (!shared_memory_) - return true; - - if (munmap(shared_memory_, shared_memory_size_) == 0) { - shared_memory_ = NULL; - shared_memory_size_ = 0; - return true; - } - - perror("CrashGenerator: Failed to unmap shared memory"); - return false; -} - -bool CrashGenerator::SetCoreFileSizeLimit(rlim_t limit) const { - struct rlimit limits = { limit, limit }; - if (setrlimit(RLIMIT_CORE, &limits) == -1) { - perror("CrashGenerator: Failed to set core file size limit"); - return false; - } - return true; -} - -bool CrashGenerator::CreateChildCrash( - unsigned num_threads, unsigned crash_thread, int crash_signal, - pid_t* child_pid) { - if (num_threads == 0 || crash_thread >= num_threads) { - fprintf(stderr, "CrashGenerator: Invalid thread counts; num_threads=%u" - " crash_thread=%u\n", num_threads, crash_thread); - return false; - } - - if (!MapSharedMemory(num_threads * sizeof(pid_t))) { - perror("CrashGenerator: Unable to map shared memory"); - return false; - } - - pid_t pid = fork(); - if (pid == 0) { - if (chdir(temp_dir_.path().c_str()) == -1) { - perror("CrashGenerator: Failed to change directory"); - exit(1); - } - if (SetCoreFileSizeLimit(kCoreSizeLimit)) { - CreateThreadsInChildProcess(num_threads); - string proc_dir = GetDirectoryOfProcFilesCopy(); - if (mkdir(proc_dir.c_str(), 0755) == -1) { - perror("CrashGenerator: Failed to create proc directory"); - exit(1); - } - if (!CopyProcFiles(getpid(), proc_dir.c_str())) { - fprintf(stderr, "CrashGenerator: Failed to copy proc files\n"); - exit(1); - } - // On Android the signal sometimes doesn't seem to get sent even though - // tkill returns '0'. Retry a couple of times if the signal doesn't get - // through on the first go: - // https://code.google.com/p/google-breakpad/issues/detail?id=579 -#if defined(__ANDROID__) - const int kRetries = 60; - const unsigned int kSleepTimeInSeconds = 1; -#else - const int kRetries = 1; - const unsigned int kSleepTimeInSeconds = 600; -#endif - for (int i = 0; i < kRetries; i++) { - if (tkill(*GetThreadIdPointer(crash_thread), crash_signal) == -1) { - perror("CrashGenerator: Failed to kill thread by signal"); - } else { - // At this point, we've queued the signal for delivery, but there's no - // guarantee when it'll be delivered. We don't want the main thread to - // race and exit before the thread we signaled is processed. So sleep - // long enough that we won't flake even under fairly high load. - // TODO: See if we can't be a bit more deterministic. There doesn't - // seem to be an API to check on signal delivery status, so we can't - // really poll and wait for the kernel to declare the signal has been - // delivered. If it has, and things worked, we'd be killed, so the - // sleep length doesn't really matter. - sleep(kSleepTimeInSeconds); - } - } - } else { - perror("CrashGenerator: Failed to set core limit"); - } - exit(1); - } else if (pid == -1) { - perror("CrashGenerator: Failed to create child process"); - return false; - } - - int status; - if (HANDLE_EINTR(waitpid(pid, &status, 0)) == -1) { - perror("CrashGenerator: Failed to wait for child process"); - return false; - } - if (!WIFSIGNALED(status) || WTERMSIG(status) != crash_signal) { - fprintf(stderr, "CrashGenerator: Child process not killed by the expected signal\n" - " exit status=0x%x pid=%u signaled=%s sig=%d expected=%d\n", - status, pid, WIFSIGNALED(status) ? "true" : "false", - WTERMSIG(status), crash_signal); - return false; - } - - if (child_pid) - *child_pid = pid; - return true; -} - -bool CrashGenerator::CopyProcFiles(pid_t pid, const char* path) const { - char from_path[PATH_MAX], to_path[PATH_MAX]; - for (size_t i = 0; i < kNumProcFilesToCopy; ++i) { - int num_chars = snprintf(from_path, PATH_MAX, "/proc/%d/%s", - pid, kProcFilesToCopy[i]); - if (num_chars < 0 || num_chars >= PATH_MAX) - return false; - - num_chars = snprintf(to_path, PATH_MAX, "%s/%s", - path, kProcFilesToCopy[i]); - if (num_chars < 0 || num_chars >= PATH_MAX) - return false; - - if (!CopyFile(from_path, to_path)) - return false; - } - return true; -} - -void CrashGenerator::CreateThreadsInChildProcess(unsigned num_threads) { - *GetThreadIdPointer(0) = getpid(); - - if (num_threads <= 1) - return; - - // This method does not clean up any pthread resource, as the process - // is expected to be killed anyway. - ThreadData* thread_data = new ThreadData[num_threads]; - - // Create detached threads so that we do not worry about pthread_join() - // later being called or not. - pthread_attr_t thread_attributes; - if (pthread_attr_init(&thread_attributes) != 0 || - pthread_attr_setdetachstate(&thread_attributes, - PTHREAD_CREATE_DETACHED) != 0) { - fprintf(stderr, "CrashGenerator: Failed to initialize thread attribute\n"); - exit(1); - } - - pthread_barrier_t thread_barrier; - if (pthread_barrier_init(&thread_barrier, NULL, num_threads) != 0) { - fprintf(stderr, "CrashGenerator: Failed to initialize thread barrier\n"); - exit(1); - } - - for (unsigned i = 1; i < num_threads; ++i) { - thread_data[i].barrier = &thread_barrier; - thread_data[i].thread_id_ptr = GetThreadIdPointer(i); - if (pthread_create(&thread_data[i].thread, &thread_attributes, - thread_function, &thread_data[i]) != 0) { - fprintf(stderr, "CrashGenerator: Failed to create thread %d\n", i); - exit(1); - } - } - - int result = pthread_barrier_wait(&thread_barrier); - if (result != 0 && result != PTHREAD_BARRIER_SERIAL_THREAD) { - fprintf(stderr, "CrashGenerator: Failed to wait for thread barrier\n"); - exit(1); - } - - pthread_barrier_destroy(&thread_barrier); - pthread_attr_destroy(&thread_attributes); - delete[] thread_data; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.h b/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.h deleted file mode 100644 index 7e2fcbf98..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/linux/tests/crash_generator.h +++ /dev/null @@ -1,117 +0,0 @@ -// 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. - -// crash_generator.h: Define the google_breakpad::CrashGenerator class, -// which is used to generate a crash (and a core dump file) for testing. - -#ifndef COMMON_LINUX_TESTS_CRASH_GENERATOR_H_ -#define COMMON_LINUX_TESTS_CRASH_GENERATOR_H_ - -#include <sys/resource.h> - -#include <string> - -#include "common/tests/auto_tempdir.h" -#include "common/using_std_string.h" - -namespace google_breakpad { - -// A utility class for generating a crash (and a core dump file) for -// testing. It creates a child process with the specified number of -// threads, which is then termainated by the specified signal. A core -// dump file is expected to be created upon the termination of the child -// process, which can then be used for testing code that processes core -// dump files. -class CrashGenerator { - public: - CrashGenerator(); - - ~CrashGenerator(); - - // Returns true if a core dump file named 'core' will be generated in - // the current directory for a test that produces a crash by checking - // if /proc/sys/kernel/core_pattern has the default value 'core'. - bool HasDefaultCorePattern() const; - - // Returns the expected path of the core dump file. - string GetCoreFilePath() const; - - // Returns the directory of a copy of proc files of the child process. - string GetDirectoryOfProcFilesCopy() const; - - // Creates a crash (and a core dump file) by creating a child process with - // |num_threads| threads, and the terminating the child process by sending - // a signal with number |crash_signal| to the |crash_thread|-th thread. - // Returns true on success. - bool CreateChildCrash(unsigned num_threads, unsigned crash_thread, - int crash_signal, pid_t* child_pid); - - // Returns the thread ID of the |index|-th thread in the child process. - // This method does not validate |index|. - pid_t GetThreadId(unsigned index) const; - - private: - // Copies the following proc files of the process with |pid| to the directory - // at |path|: auxv, cmdline, environ, maps, status - // The directory must have been created. Returns true on success. - bool CopyProcFiles(pid_t pid, const char* path) const; - - // Creates |num_threads| threads in the child process. - void CreateThreadsInChildProcess(unsigned num_threads); - - // Sets the maximum size of core dump file (both the soft and hard limit) - // to |limit| bytes. Returns true on success. - bool SetCoreFileSizeLimit(rlim_t limit) const; - - // Creates a shared memory of |memory_size| bytes for communicating thread - // IDs between the parent and child process. Returns true on success. - bool MapSharedMemory(size_t memory_size); - - // Releases any shared memory created by MapSharedMemory(). Returns true on - // success. - bool UnmapSharedMemory(); - - // Returns the pointer to the thread ID of the |index|-th thread in the child - // process. This method does not validate |index|. - pid_t* GetThreadIdPointer(unsigned index); - - // Temporary directory in which a core file is generated. - AutoTempDir temp_dir_; - - // Shared memory for communicating thread IDs between the parent and - // child process. - void* shared_memory_; - - // Number of bytes mapped for |shared_memory_|. - size_t shared_memory_size_; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_TESTS_CRASH_GENERATOR_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/Breakpad.xcconfig b/toolkit/crashreporter/google-breakpad/src/common/mac/Breakpad.xcconfig deleted file mode 100644 index f09136908..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/Breakpad.xcconfig +++ /dev/null @@ -1,52 +0,0 @@ -// 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. - -GCC_C_LANGUAGE_STANDARD = c99 - -GCC_WARN_CHECK_SWITCH_STATEMENTS = YES -// TODO(nealsid): Get the code so we can turn on the 64_TO_32 warning. -GCC_WARN_64_TO_32_BIT_CONVERSION = NO -GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES -GCC_WARN_ABOUT_RETURN_TYPE = YES -GCC_WARN_MISSING_PARENTHESES = YES - -// Once https://bugs.chromium.org/p/google-breakpad/issues/detail?id=697 -// is fixed this should be reenabled. -//GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES -GCC_WARN_ABOUT_MISSING_NEWLINE = YES -GCC_WARN_SIGN_COMPARE = YES -GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES -GCC_WARN_UNDECLARED_SELECTOR = YES -GCC_WARN_UNKNOWN_PRAGMAS = YES -GCC_WARN_UNUSED_VARIABLE = YES -GCC_TREAT_WARNINGS_AS_ERRORS = YES - -DEBUG_INFORMATION_FORMAT = dwarf-with-dsym - -ALWAYS_SEARCH_USER_PATHS = NO diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadDebug.xcconfig b/toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadDebug.xcconfig deleted file mode 100644 index 94cdd8cfc..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadDebug.xcconfig +++ /dev/null @@ -1,32 +0,0 @@ -// 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. - -#include "Breakpad.xcconfig" - -GCC_OPTIMIZATION_LEVEL = 0 diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadRelease.xcconfig b/toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadRelease.xcconfig deleted file mode 100644 index 920f277db..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/BreakpadRelease.xcconfig +++ /dev/null @@ -1,34 +0,0 @@ -// 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. - -#include "Breakpad.xcconfig" - -GCC_OPTIMIZATION_LEVEL = s -GCC_WARN_UNINITIALIZED_AUTOS = YES -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) NDEBUG diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/GTMDefines.h b/toolkit/crashreporter/google-breakpad/src/common/mac/GTMDefines.h deleted file mode 100644 index 14ffa7e13..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/GTMDefines.h +++ /dev/null @@ -1,456 +0,0 @@ -// -// GTMDefines.h -// -// Copyright 2008 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy -// of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. -// - -// ============================================================================ - -#include <AvailabilityMacros.h> -#include <TargetConditionals.h> - -#ifdef __OBJC__ -#include <Foundation/NSObjCRuntime.h> -#endif // __OBJC__ - -#if TARGET_OS_IPHONE -#include <Availability.h> -#endif // TARGET_OS_IPHONE - -// Not all MAC_OS_X_VERSION_10_X macros defined in past SDKs -#ifndef MAC_OS_X_VERSION_10_5 - #define MAC_OS_X_VERSION_10_5 1050 -#endif -#ifndef MAC_OS_X_VERSION_10_6 - #define MAC_OS_X_VERSION_10_6 1060 -#endif -#ifndef MAC_OS_X_VERSION_10_7 - #define MAC_OS_X_VERSION_10_7 1070 -#endif - -// Not all __IPHONE_X macros defined in past SDKs -#ifndef __IPHONE_3_0 - #define __IPHONE_3_0 30000 -#endif -#ifndef __IPHONE_3_1 - #define __IPHONE_3_1 30100 -#endif -#ifndef __IPHONE_3_2 - #define __IPHONE_3_2 30200 -#endif -#ifndef __IPHONE_4_0 - #define __IPHONE_4_0 40000 -#endif -#ifndef __IPHONE_4_3 - #define __IPHONE_4_3 40300 -#endif -#ifndef __IPHONE_5_0 - #define __IPHONE_5_0 50000 -#endif - -// ---------------------------------------------------------------------------- -// CPP symbols that can be overridden in a prefix to control how the toolbox -// is compiled. -// ---------------------------------------------------------------------------- - - -// By setting the GTM_CONTAINERS_VALIDATION_FAILED_LOG and -// GTM_CONTAINERS_VALIDATION_FAILED_ASSERT macros you can control what happens -// when a validation fails. If you implement your own validators, you may want -// to control their internals using the same macros for consistency. -#ifndef GTM_CONTAINERS_VALIDATION_FAILED_ASSERT - #define GTM_CONTAINERS_VALIDATION_FAILED_ASSERT 0 -#endif - -// Give ourselves a consistent way to do inlines. Apple's macros even use -// a few different actual definitions, so we're based off of the foundation -// one. -#if !defined(GTM_INLINE) - #if (defined (__GNUC__) && (__GNUC__ == 4)) || defined (__clang__) - #define GTM_INLINE static __inline__ __attribute__((always_inline)) - #else - #define GTM_INLINE static __inline__ - #endif -#endif - -// Give ourselves a consistent way of doing externs that links up nicely -// when mixing objc and objc++ -#if !defined (GTM_EXTERN) - #if defined __cplusplus - #define GTM_EXTERN extern "C" - #define GTM_EXTERN_C_BEGIN extern "C" { - #define GTM_EXTERN_C_END } - #else - #define GTM_EXTERN extern - #define GTM_EXTERN_C_BEGIN - #define GTM_EXTERN_C_END - #endif -#endif - -// Give ourselves a consistent way of exporting things if we have visibility -// set to hidden. -#if !defined (GTM_EXPORT) - #define GTM_EXPORT __attribute__((visibility("default"))) -#endif - -// Give ourselves a consistent way of declaring something as unused. This -// doesn't use __unused because that is only supported in gcc 4.2 and greater. -#if !defined (GTM_UNUSED) -#define GTM_UNUSED(x) ((void)(x)) -#endif - -// _GTMDevLog & _GTMDevAssert -// -// _GTMDevLog & _GTMDevAssert are meant to be a very lightweight shell for -// developer level errors. This implementation simply macros to NSLog/NSAssert. -// It is not intended to be a general logging/reporting system. -// -// Please see http://code.google.com/p/google-toolbox-for-mac/wiki/DevLogNAssert -// for a little more background on the usage of these macros. -// -// _GTMDevLog log some error/problem in debug builds -// _GTMDevAssert assert if conditon isn't met w/in a method/function -// in all builds. -// -// To replace this system, just provide different macro definitions in your -// prefix header. Remember, any implementation you provide *must* be thread -// safe since this could be called by anything in what ever situtation it has -// been placed in. -// - -// We only define the simple macros if nothing else has defined this. -#ifndef _GTMDevLog - -#ifdef DEBUG - #define _GTMDevLog(...) NSLog(__VA_ARGS__) -#else - #define _GTMDevLog(...) do { } while (0) -#endif - -#endif // _GTMDevLog - -#ifndef _GTMDevAssert -// we directly invoke the NSAssert handler so we can pass on the varargs -// (NSAssert doesn't have a macro we can use that takes varargs) -#if !defined(NS_BLOCK_ASSERTIONS) - #define _GTMDevAssert(condition, ...) \ - do { \ - if (!(condition)) { \ - [[NSAssertionHandler currentHandler] \ - handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \ - file:[NSString stringWithUTF8String:__FILE__] \ - lineNumber:__LINE__ \ - description:__VA_ARGS__]; \ - } \ - } while(0) -#else // !defined(NS_BLOCK_ASSERTIONS) - #define _GTMDevAssert(condition, ...) do { } while (0) -#endif // !defined(NS_BLOCK_ASSERTIONS) - -#endif // _GTMDevAssert - -// _GTMCompileAssert -// _GTMCompileAssert is an assert that is meant to fire at compile time if you -// want to check things at compile instead of runtime. For example if you -// want to check that a wchar is 4 bytes instead of 2 you would use -// _GTMCompileAssert(sizeof(wchar_t) == 4, wchar_t_is_4_bytes_on_OS_X) -// Note that the second "arg" is not in quotes, and must be a valid processor -// symbol in it's own right (no spaces, punctuation etc). - -// Wrapping this in an #ifndef allows external groups to define their own -// compile time assert scheme. -#ifndef _GTMCompileAssert - // We got this technique from here: - // http://unixjunkie.blogspot.com/2007/10/better-compile-time-asserts_29.html - - #define _GTMCompileAssertSymbolInner(line, msg) _GTMCOMPILEASSERT ## line ## __ ## msg - #define _GTMCompileAssertSymbol(line, msg) _GTMCompileAssertSymbolInner(line, msg) - #define _GTMCompileAssert(test, msg) \ - typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ] -#endif // _GTMCompileAssert - -// ---------------------------------------------------------------------------- -// CPP symbols defined based on the project settings so the GTM code has -// simple things to test against w/o scattering the knowledge of project -// setting through all the code. -// ---------------------------------------------------------------------------- - -// Provide a single constant CPP symbol that all of GTM uses for ifdefing -// iPhone code. -#if TARGET_OS_IPHONE // iPhone SDK - // For iPhone specific stuff - #define GTM_IPHONE_SDK 1 - #if TARGET_IPHONE_SIMULATOR - #define GTM_IPHONE_DEVICE 0 - #define GTM_IPHONE_SIMULATOR 1 - #else - #define GTM_IPHONE_DEVICE 1 - #define GTM_IPHONE_SIMULATOR 0 - #endif // TARGET_IPHONE_SIMULATOR - // By default, GTM has provided it's own unittesting support, define this - // to use the support provided by Xcode, especially for the Xcode4 support - // for unittesting. - #ifndef GTM_IPHONE_USE_SENTEST - #define GTM_IPHONE_USE_SENTEST 0 - #endif - #define GTM_MACOS_SDK 0 -#else - // For MacOS specific stuff - #define GTM_MACOS_SDK 1 - #define GTM_IPHONE_SDK 0 - #define GTM_IPHONE_SIMULATOR 0 - #define GTM_IPHONE_DEVICE 0 - #define GTM_IPHONE_USE_SENTEST 0 -#endif - -// Some of our own availability macros -#if GTM_MACOS_SDK -#define GTM_AVAILABLE_ONLY_ON_IPHONE UNAVAILABLE_ATTRIBUTE -#define GTM_AVAILABLE_ONLY_ON_MACOS -#else -#define GTM_AVAILABLE_ONLY_ON_IPHONE -#define GTM_AVAILABLE_ONLY_ON_MACOS UNAVAILABLE_ATTRIBUTE -#endif - -// GC was dropped by Apple, define the old constant incase anyone still keys -// off of it. -#ifndef GTM_SUPPORT_GC - #define GTM_SUPPORT_GC 0 -#endif - -// To simplify support for 64bit (and Leopard in general), we provide the type -// defines for non Leopard SDKs -#if !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) - // NSInteger/NSUInteger and Max/Mins - #ifndef NSINTEGER_DEFINED - #if (defined(__LP64__) && __LP64__) || NS_BUILD_32_LIKE_64 - typedef long NSInteger; - typedef unsigned long NSUInteger; - #else - typedef int NSInteger; - typedef unsigned int NSUInteger; - #endif - #define NSIntegerMax LONG_MAX - #define NSIntegerMin LONG_MIN - #define NSUIntegerMax ULONG_MAX - #define NSINTEGER_DEFINED 1 - #endif // NSINTEGER_DEFINED - // CGFloat - #ifndef CGFLOAT_DEFINED - #if defined(__LP64__) && __LP64__ - // This really is an untested path (64bit on Tiger?) - typedef double CGFloat; - #define CGFLOAT_MIN DBL_MIN - #define CGFLOAT_MAX DBL_MAX - #define CGFLOAT_IS_DOUBLE 1 - #else /* !defined(__LP64__) || !__LP64__ */ - typedef float CGFloat; - #define CGFLOAT_MIN FLT_MIN - #define CGFLOAT_MAX FLT_MAX - #define CGFLOAT_IS_DOUBLE 0 - #endif /* !defined(__LP64__) || !__LP64__ */ - #define CGFLOAT_DEFINED 1 - #endif // CGFLOAT_DEFINED -#endif // MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 - -// Some support for advanced clang static analysis functionality -// See http://clang-analyzer.llvm.org/annotations.html -#ifndef __has_feature // Optional. - #define __has_feature(x) 0 // Compatibility with non-clang compilers. -#endif - -#ifndef NS_RETURNS_RETAINED - #if __has_feature(attribute_ns_returns_retained) - #define NS_RETURNS_RETAINED __attribute__((ns_returns_retained)) - #else - #define NS_RETURNS_RETAINED - #endif -#endif - -#ifndef NS_RETURNS_NOT_RETAINED - #if __has_feature(attribute_ns_returns_not_retained) - #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained)) - #else - #define NS_RETURNS_NOT_RETAINED - #endif -#endif - -#ifndef CF_RETURNS_RETAINED - #if __has_feature(attribute_cf_returns_retained) - #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) - #else - #define CF_RETURNS_RETAINED - #endif -#endif - -#ifndef CF_RETURNS_NOT_RETAINED - #if __has_feature(attribute_cf_returns_not_retained) - #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) - #else - #define CF_RETURNS_NOT_RETAINED - #endif -#endif - -#ifndef NS_CONSUMED - #if __has_feature(attribute_ns_consumed) - #define NS_CONSUMED __attribute__((ns_consumed)) - #else - #define NS_CONSUMED - #endif -#endif - -#ifndef CF_CONSUMED - #if __has_feature(attribute_cf_consumed) - #define CF_CONSUMED __attribute__((cf_consumed)) - #else - #define CF_CONSUMED - #endif -#endif - -#ifndef NS_CONSUMES_SELF - #if __has_feature(attribute_ns_consumes_self) - #define NS_CONSUMES_SELF __attribute__((ns_consumes_self)) - #else - #define NS_CONSUMES_SELF - #endif -#endif - -// Defined on 10.6 and above. -#ifndef NS_FORMAT_ARGUMENT - #define NS_FORMAT_ARGUMENT(A) -#endif - -// Defined on 10.6 and above. -#ifndef NS_FORMAT_FUNCTION - #define NS_FORMAT_FUNCTION(F,A) -#endif - -// Defined on 10.6 and above. -#ifndef CF_FORMAT_ARGUMENT - #define CF_FORMAT_ARGUMENT(A) -#endif - -// Defined on 10.6 and above. -#ifndef CF_FORMAT_FUNCTION - #define CF_FORMAT_FUNCTION(F,A) -#endif - -#ifndef GTM_NONNULL - #if defined(__has_attribute) - #if __has_attribute(nonnull) - #define GTM_NONNULL(x) __attribute__((nonnull x)) - #else - #define GTM_NONNULL(x) - #endif - #else - #define GTM_NONNULL(x) - #endif -#endif - -// Invalidates the initializer from which it's called. -#ifndef GTMInvalidateInitializer - #if __has_feature(objc_arc) - #define GTMInvalidateInitializer() \ - do { \ - [self class]; /* Avoid warning of dead store to |self|. */ \ - _GTMDevAssert(NO, @"Invalid initializer."); \ - return nil; \ - } while (0) - #else - #define GTMInvalidateInitializer() \ - do { \ - [self release]; \ - _GTMDevAssert(NO, @"Invalid initializer."); \ - return nil; \ - } while (0) - #endif -#endif - -#ifndef GTMCFAutorelease - #if __has_feature(objc_arc) - #define GTMCFAutorelease(x) CFBridgingRelease(x) - #else - #define GTMCFAutorelease(x) ([(id)x autorelease]) - #endif -#endif - -#ifdef __OBJC__ - -// Declared here so that it can easily be used for logging tracking if -// necessary. See GTMUnitTestDevLog.h for details. -@class NSString; -GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...) NS_FORMAT_FUNCTION(1, 2); - -// Macro to allow you to create NSStrings out of other macros. -// #define FOO foo -// NSString *fooString = GTM_NSSTRINGIFY(FOO); -#if !defined (GTM_NSSTRINGIFY) - #define GTM_NSSTRINGIFY_INNER(x) @#x - #define GTM_NSSTRINGIFY(x) GTM_NSSTRINGIFY_INNER(x) -#endif - -// Macro to allow fast enumeration when building for 10.5 or later, and -// reliance on NSEnumerator for 10.4. Remember, NSDictionary w/ FastEnumeration -// does keys, so pick the right thing, nothing is done on the FastEnumeration -// side to be sure you're getting what you wanted. -#ifndef GTM_FOREACH_OBJECT - #if TARGET_OS_IPHONE || !(MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) - #define GTM_FOREACH_ENUMEREE(element, enumeration) \ - for (element in enumeration) - #define GTM_FOREACH_OBJECT(element, collection) \ - for (element in collection) - #define GTM_FOREACH_KEY(element, collection) \ - for (element in collection) - #else - #define GTM_FOREACH_ENUMEREE(element, enumeration) \ - for (NSEnumerator *_ ## element ## _enum = enumeration; \ - (element = [_ ## element ## _enum nextObject]) != nil; ) - #define GTM_FOREACH_OBJECT(element, collection) \ - GTM_FOREACH_ENUMEREE(element, [collection objectEnumerator]) - #define GTM_FOREACH_KEY(element, collection) \ - GTM_FOREACH_ENUMEREE(element, [collection keyEnumerator]) - #endif -#endif - -// ============================================================================ - -// To simplify support for both Leopard and Snow Leopard we declare -// the Snow Leopard protocols that we need here. -#if !defined(GTM_10_6_PROTOCOLS_DEFINED) && !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) -#define GTM_10_6_PROTOCOLS_DEFINED 1 -@protocol NSConnectionDelegate -@end -@protocol NSAnimationDelegate -@end -@protocol NSImageDelegate -@end -@protocol NSTabViewDelegate -@end -#endif // !defined(GTM_10_6_PROTOCOLS_DEFINED) && !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) - -// GTM_SEL_STRING is for specifying selector (usually property) names to KVC -// or KVO methods. -// In debug it will generate warnings for undeclared selectors if -// -Wunknown-selector is turned on. -// In release it will have no runtime overhead. -#ifndef GTM_SEL_STRING - #ifdef DEBUG - #define GTM_SEL_STRING(selName) NSStringFromSelector(@selector(selName)) - #else - #define GTM_SEL_STRING(selName) @#selName - #endif // DEBUG -#endif // GTM_SEL_STRING - -#endif // __OBJC__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.h b/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.h deleted file mode 100644 index c4fd14029..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.h +++ /dev/null @@ -1,504 +0,0 @@ -// -// GTMLogger.h -// -// Copyright 2007-2008 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy -// of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. -// - -// Key Abstractions -// ---------------- -// -// This file declares multiple classes and protocols that are used by the -// GTMLogger logging system. The 4 main abstractions used in this file are the -// following: -// -// * logger (GTMLogger) - The main logging class that users interact with. It -// has methods for logging at different levels and uses a log writer, a log -// formatter, and a log filter to get the job done. -// -// * log writer (GTMLogWriter) - Writes a given string to some log file, where -// a "log file" can be a physical file on disk, a POST over HTTP to some URL, -// or even some in-memory structure (e.g., a ring buffer). -// -// * log formatter (GTMLogFormatter) - Given a format string and arguments as -// a va_list, returns a single formatted NSString. A "formatted string" could -// be a string with the date prepended, a string with values in a CSV format, -// or even a string of XML. -// -// * log filter (GTMLogFilter) - Given a formatted log message as an NSString -// and the level at which the message is to be logged, this class will decide -// whether the given message should be logged or not. This is a flexible way -// to filter out messages logged at a certain level, messages that contain -// certain text, or filter nothing out at all. This gives the caller the -// flexibility to dynamically enable debug logging in Release builds. -// -// This file also declares some classes to handle the common log writer, log -// formatter, and log filter cases. Callers can also create their own writers, -// formatters, and filters and they can even build them on top of the ones -// declared here. Keep in mind that your custom writer/formatter/filter may be -// called from multiple threads, so it must be thread-safe. - -#import <Foundation/Foundation.h> -#import "GTMDefines.h" - -// Predeclaration of used protocols that are declared later in this file. -@protocol GTMLogWriter, GTMLogFormatter, GTMLogFilter; - -// GTMLogger -// -// GTMLogger is the primary user-facing class for an object-oriented logging -// system. It is built on the concept of log formatters (GTMLogFormatter), log -// writers (GTMLogWriter), and log filters (GTMLogFilter). When a message is -// sent to a GTMLogger to log a message, the message is formatted using the log -// formatter, then the log filter is consulted to see if the message should be -// logged, and if so, the message is sent to the log writer to be written out. -// -// GTMLogger is intended to be a flexible and thread-safe logging solution. Its -// flexibility comes from the fact that GTMLogger instances can be customized -// with user defined formatters, filters, and writers. And these writers, -// filters, and formatters can be combined, stacked, and customized in arbitrary -// ways to suit the needs at hand. For example, multiple writers can be used at -// the same time, and a GTMLogger instance can even be used as another -// GTMLogger's writer. This allows for arbitrarily deep logging trees. -// -// A standard GTMLogger uses a writer that sends messages to standard out, a -// formatter that smacks a timestamp and a few other bits of interesting -// information on the message, and a filter that filters out debug messages from -// release builds. Using the standard log settings, a log message will look like -// the following: -// -// 2007-12-30 10:29:24.177 myapp[4588/0xa07d0f60] [lvl=1] foo=<Foo: 0x123> -// -// The output contains the date and time of the log message, the name of the -// process followed by its process ID/thread ID, the log level at which the -// message was logged (in the previous example the level was 1: -// kGTMLoggerLevelDebug), and finally, the user-specified log message itself (in -// this case, the log message was @"foo=%@", foo). -// -// Multiple instances of GTMLogger can be created, each configured their own -// way. Though GTMLogger is not a singleton (in the GoF sense), it does provide -// access to a shared (i.e., globally accessible) GTMLogger instance. This makes -// it convenient for all code in a process to use the same GTMLogger instance. -// The shared GTMLogger instance can also be configured in an arbitrary, and -// these configuration changes will affect all code that logs through the shared -// instance. - -// -// Log Levels -// ---------- -// GTMLogger has 3 different log levels: Debug, Info, and Error. GTMLogger -// doesn't take any special action based on the log level; it simply forwards -// this information on to formatters, filters, and writers, each of which may -// optionally take action based on the level. Since log level filtering is -// performed at runtime, log messages are typically not filtered out at compile -// time. The exception to this rule is that calls to the GTMLoggerDebug() macro -// *ARE* filtered out of non-DEBUG builds. This is to be backwards compatible -// with behavior that many developers are currently used to. Note that this -// means that GTMLoggerDebug(@"hi") will be compiled out of Release builds, but -// [[GTMLogger sharedLogger] logDebug:@"hi"] will NOT be compiled out. -// -// Standard loggers are created with the GTMLogLevelFilter log filter, which -// filters out certain log messages based on log level, and some other settings. -// -// In addition to the -logDebug:, -logInfo:, and -logError: methods defined on -// GTMLogger itself, there are also C macros that make usage of the shared -// GTMLogger instance very convenient. These macros are: -// -// GTMLoggerDebug(...) -// GTMLoggerInfo(...) -// GTMLoggerError(...) -// -// Again, a notable feature of these macros is that GTMLogDebug() calls *will be -// compiled out of non-DEBUG builds*. -// -// Standard Loggers -// ---------------- -// GTMLogger has the concept of "standard loggers". A standard logger is simply -// a logger that is pre-configured with some standard/common writer, formatter, -// and filter combination. Standard loggers are created using the creation -// methods beginning with "standard". The alternative to a standard logger is a -// regular logger, which will send messages to stdout, with no special -// formatting, and no filtering. -// -// How do I use GTMLogger? -// ---------------------- -// The typical way you will want to use GTMLogger is to simply use the -// GTMLogger*() macros for logging from code. That way we can easily make -// changes to the GTMLogger class and simply update the macros accordingly. Only -// your application startup code (perhaps, somewhere in main()) should use the -// GTMLogger class directly in order to configure the shared logger, which all -// of the code using the macros will be using. Again, this is just the typical -// situation. -// -// To be complete, there are cases where you may want to use GTMLogger directly, -// or even create separate GTMLogger instances for some reason. That's fine, -// too. -// -// Examples -// -------- -// The following show some common GTMLogger use cases. -// -// 1. You want to log something as simply as possible. Also, this call will only -// appear in debug builds. In non-DEBUG builds it will be completely removed. -// -// GTMLoggerDebug(@"foo = %@", foo); -// -// 2. The previous example is similar to the following. The major difference is -// that the previous call (example 1) will be compiled out of Release builds -// but this statement will not be compiled out. -// -// [[GTMLogger sharedLogger] logDebug:@"foo = %@", foo]; -// -// 3. Send all logging output from the shared logger to a file. We do this by -// creating an NSFileHandle for writing associated with a file, and setting -// that file handle as the logger's writer. -// -// NSFileHandle *f = [NSFileHandle fileHandleForWritingAtPath:@"/tmp/f.log" -// create:YES]; -// [[GTMLogger sharedLogger] setWriter:f]; -// GTMLoggerError(@"hi"); // This will be sent to /tmp/f.log -// -// 4. Create a new GTMLogger that will log to a file. This example differs from -// the previous one because here we create a new GTMLogger that is different -// from the shared logger. -// -// GTMLogger *logger = [GTMLogger standardLoggerWithPath:@"/tmp/temp.log"]; -// [logger logInfo:@"hi temp log file"]; -// -// 5. Create a logger that writes to stdout and does NOT do any formatting to -// the log message. This might be useful, for example, when writing a help -// screen for a command-line tool to standard output. -// -// GTMLogger *logger = [GTMLogger logger]; -// [logger logInfo:@"%@ version 0.1 usage", progName]; -// -// 6. Send log output to stdout AND to a log file. The trick here is that -// NSArrays function as composite log writers, which means when an array is -// set as the log writer, it forwards all logging messages to all of its -// contained GTMLogWriters. -// -// // Create array of GTMLogWriters -// NSArray *writers = [NSArray arrayWithObjects: -// [NSFileHandle fileHandleForWritingAtPath:@"/tmp/f.log" create:YES], -// [NSFileHandle fileHandleWithStandardOutput], nil]; -// -// GTMLogger *logger = [GTMLogger standardLogger]; -// [logger setWriter:writers]; -// [logger logInfo:@"hi"]; // Output goes to stdout and /tmp/f.log -// -// For futher details on log writers, formatters, and filters, see the -// documentation below. -// -// NOTE: GTMLogger is application level logging. By default it does nothing -// with _GTMDevLog/_GTMDevAssert (see GTMDefines.h). An application can choose -// to bridge _GTMDevLog/_GTMDevAssert to GTMLogger by providing macro -// definitions in its prefix header (see GTMDefines.h for how one would do -// that). -// -@interface GTMLogger : NSObject { - @private - id<GTMLogWriter> writer_; - id<GTMLogFormatter> formatter_; - id<GTMLogFilter> filter_; -} - -// -// Accessors for the shared logger instance -// - -// Returns a shared/global standard GTMLogger instance. Callers should typically -// use this method to get a GTMLogger instance, unless they explicitly want -// their own instance to configure for their own needs. This is the only method -// that returns a shared instance; all the rest return new GTMLogger instances. -+ (id)sharedLogger; - -// Sets the shared logger instance to |logger|. Future calls to +sharedLogger -// will return |logger| instead. -+ (void)setSharedLogger:(GTMLogger *)logger; - -// -// Creation methods -// - -// Returns a new autoreleased GTMLogger instance that will log to stdout, using -// the GTMLogStandardFormatter, and the GTMLogLevelFilter filter. -+ (id)standardLogger; - -// Same as +standardLogger, but logs to stderr. -+ (id)standardLoggerWithStderr; - -// Same as +standardLogger but levels >= kGTMLoggerLevelError are routed to -// stderr, everything else goes to stdout. -+ (id)standardLoggerWithStdoutAndStderr; - -// Returns a new standard GTMLogger instance with a log writer that will -// write to the file at |path|, and will use the GTMLogStandardFormatter and -// GTMLogLevelFilter classes. If |path| does not exist, it will be created. -+ (id)standardLoggerWithPath:(NSString *)path; - -// Returns an autoreleased GTMLogger instance that will use the specified -// |writer|, |formatter|, and |filter|. -+ (id)loggerWithWriter:(id<GTMLogWriter>)writer - formatter:(id<GTMLogFormatter>)formatter - filter:(id<GTMLogFilter>)filter; - -// Returns an autoreleased GTMLogger instance that logs to stdout, with the -// basic formatter, and no filter. The returned logger differs from the logger -// returned by +standardLogger because this one does not do any filtering and -// does not do any special log formatting; this is the difference between a -// "regular" logger and a "standard" logger. -+ (id)logger; - -// Designated initializer. This method returns a GTMLogger initialized with the -// specified |writer|, |formatter|, and |filter|. See the setter methods below -// for what values will be used if nil is passed for a parameter. -- (id)initWithWriter:(id<GTMLogWriter>)writer - formatter:(id<GTMLogFormatter>)formatter - filter:(id<GTMLogFilter>)filter; - -// -// Logging methods -// - -// Logs a message at the debug level (kGTMLoggerLevelDebug). -- (void)logDebug:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2); -// Logs a message at the info level (kGTMLoggerLevelInfo). -- (void)logInfo:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2); -// Logs a message at the error level (kGTMLoggerLevelError). -- (void)logError:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2); -// Logs a message at the assert level (kGTMLoggerLevelAssert). -- (void)logAssert:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2); - - -// -// Accessors -// - -// Accessor methods for the log writer. If the log writer is set to nil, -// [NSFileHandle fileHandleWithStandardOutput] is used. -- (id<GTMLogWriter>)writer; -- (void)setWriter:(id<GTMLogWriter>)writer; - -// Accessor methods for the log formatter. If the log formatter is set to nil, -// GTMLogBasicFormatter is used. This formatter will format log messages in a -// plain printf style. -- (id<GTMLogFormatter>)formatter; -- (void)setFormatter:(id<GTMLogFormatter>)formatter; - -// Accessor methods for the log filter. If the log filter is set to nil, -// GTMLogNoFilter is used, which allows all log messages through. -- (id<GTMLogFilter>)filter; -- (void)setFilter:(id<GTMLogFilter>)filter; - -@end // GTMLogger - - -// Helper functions that are used by the convenience GTMLogger*() macros that -// enable the logging of function names. -@interface GTMLogger (GTMLoggerMacroHelpers) -- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... - NS_FORMAT_FUNCTION(2, 3); -- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ... - NS_FORMAT_FUNCTION(2, 3); -- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ... - NS_FORMAT_FUNCTION(2, 3); -- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ... - NS_FORMAT_FUNCTION(2, 3); -@end // GTMLoggerMacroHelpers - - -// The convenience macros are only defined if they haven't already been defined. -#ifndef GTMLoggerInfo - -// Convenience macros that log to the shared GTMLogger instance. These macros -// are how users should typically log to GTMLogger. Notice that GTMLoggerDebug() -// calls will be compiled out of non-Debug builds. -#define GTMLoggerDebug(...) \ - [[GTMLogger sharedLogger] logFuncDebug:__func__ msg:__VA_ARGS__] -#define GTMLoggerInfo(...) \ - [[GTMLogger sharedLogger] logFuncInfo:__func__ msg:__VA_ARGS__] -#define GTMLoggerError(...) \ - [[GTMLogger sharedLogger] logFuncError:__func__ msg:__VA_ARGS__] -#define GTMLoggerAssert(...) \ - [[GTMLogger sharedLogger] logFuncAssert:__func__ msg:__VA_ARGS__] - -// If we're not in a debug build, remove the GTMLoggerDebug statements. This -// makes calls to GTMLoggerDebug "compile out" of Release builds -#ifndef DEBUG -#undef GTMLoggerDebug -#define GTMLoggerDebug(...) do {} while(0) -#endif - -#endif // !defined(GTMLoggerInfo) - -// Log levels. -typedef enum { - kGTMLoggerLevelUnknown, - kGTMLoggerLevelDebug, - kGTMLoggerLevelInfo, - kGTMLoggerLevelError, - kGTMLoggerLevelAssert, -} GTMLoggerLevel; - - -// -// Log Writers -// - -// Protocol to be implemented by a GTMLogWriter instance. -@protocol GTMLogWriter <NSObject> -// Writes the given log message to where the log writer is configured to write. -- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level; -@end // GTMLogWriter - - -// Simple category on NSFileHandle that makes NSFileHandles valid log writers. -// This is convenient because something like, say, +fileHandleWithStandardError -// now becomes a valid log writer. Log messages are written to the file handle -// with a newline appended. -@interface NSFileHandle (GTMFileHandleLogWriter) <GTMLogWriter> -// Opens the file at |path| in append mode, and creates the file with |mode| -// if it didn't previously exist. -+ (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode; -@end // NSFileHandle - - -// This category makes NSArray a GTMLogWriter that can be composed of other -// GTMLogWriters. This is the classic Composite GoF design pattern. When the -// GTMLogWriter -logMessage:level: message is sent to the array, the array -// forwards the message to all of its elements that implement the GTMLogWriter -// protocol. -// -// This is useful in situations where you would like to send log output to -// multiple log writers at the same time. Simply create an NSArray of the log -// writers you wish to use, then set the array as the "writer" for your -// GTMLogger instance. -@interface NSArray (GTMArrayCompositeLogWriter) <GTMLogWriter> -@end // GTMArrayCompositeLogWriter - - -// This category adapts the GTMLogger interface so that it can be used as a log -// writer; it's an "adapter" in the GoF Adapter pattern sense. -// -// This is useful when you want to configure a logger to log to a specific -// writer with a specific formatter and/or filter. But you want to also compose -// that with a different log writer that may have its own formatter and/or -// filter. -@interface GTMLogger (GTMLoggerLogWriter) <GTMLogWriter> -@end // GTMLoggerLogWriter - - -// -// Log Formatters -// - -// Protocol to be implemented by a GTMLogFormatter instance. -@protocol GTMLogFormatter <NSObject> -// Returns a formatted string using the format specified in |fmt| and the va -// args specified in |args|. -- (NSString *)stringForFunc:(NSString *)func - withFormat:(NSString *)fmt - valist:(va_list)args - level:(GTMLoggerLevel)level NS_FORMAT_FUNCTION(2, 0); -@end // GTMLogFormatter - - -// A basic log formatter that formats a string the same way that NSLog (or -// printf) would. It does not do anything fancy, nor does it add any data of its -// own. -@interface GTMLogBasicFormatter : NSObject <GTMLogFormatter> - -// Helper method for prettying C99 __func__ and GCC __PRETTY_FUNCTION__ -- (NSString *)prettyNameForFunc:(NSString *)func; - -@end // GTMLogBasicFormatter - - -// A log formatter that formats the log string like the basic formatter, but -// also prepends a timestamp and some basic process info to the message, as -// shown in the following sample output. -// 2007-12-30 10:29:24.177 myapp[4588/0xa07d0f60] [lvl=1] log mesage here -@interface GTMLogStandardFormatter : GTMLogBasicFormatter { - @private - NSDateFormatter *dateFormatter_; // yyyy-MM-dd HH:mm:ss.SSS - NSString *pname_; - pid_t pid_; -} -@end // GTMLogStandardFormatter - - -// -// Log Filters -// - -// Protocol to be imlemented by a GTMLogFilter instance. -@protocol GTMLogFilter <NSObject> -// Returns YES if |msg| at |level| should be filtered out; NO otherwise. -- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level; -@end // GTMLogFilter - - -// A log filter that filters messages at the kGTMLoggerLevelDebug level out of -// non-debug builds. Messages at the kGTMLoggerLevelInfo level are also filtered -// out of non-debug builds unless GTMVerboseLogging is set in the environment or -// the processes's defaults. Messages at the kGTMLoggerLevelError level are -// never filtered. -@interface GTMLogLevelFilter : NSObject <GTMLogFilter> -@end // GTMLogLevelFilter - -// A simple log filter that does NOT filter anything out; -// -filterAllowsMessage:level will always return YES. This can be a convenient -// way to enable debug-level logging in release builds (if you so desire). -@interface GTMLogNoFilter : NSObject <GTMLogFilter> -@end // GTMLogNoFilter - - -// Base class for custom level filters. Not for direct use, use the minimum -// or maximum level subclasses below. -@interface GTMLogAllowedLevelFilter : NSObject <GTMLogFilter> { - @private - NSIndexSet *allowedLevels_; -} -@end - -// A log filter that allows you to set a minimum log level. Messages below this -// level will be filtered. -@interface GTMLogMininumLevelFilter : GTMLogAllowedLevelFilter - -// Designated initializer, logs at levels < |level| will be filtered. -- (id)initWithMinimumLevel:(GTMLoggerLevel)level; - -@end - -// A log filter that allows you to set a maximum log level. Messages whose level -// exceeds this level will be filtered. This is really only useful if you have -// a composite GTMLogger that is sending the other messages elsewhere. -@interface GTMLogMaximumLevelFilter : GTMLogAllowedLevelFilter - -// Designated initializer, logs at levels > |level| will be filtered. -- (id)initWithMaximumLevel:(GTMLoggerLevel)level; - -@end - - -// For subclasses only -@interface GTMLogger (PrivateMethods) - -- (void)logInternalFunc:(const char *)func - format:(NSString *)fmt - valist:(va_list)args - level:(GTMLoggerLevel)level NS_FORMAT_FUNCTION(2, 0); - -@end - diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.m b/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.m deleted file mode 100644 index ebc5836a2..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/GTMLogger.m +++ /dev/null @@ -1,611 +0,0 @@ -// -// GTMLogger.m -// -// Copyright 2007-2008 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy -// of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. -// - -#import "GTMLogger.h" -#import <fcntl.h> -#import <unistd.h> -#import <stdlib.h> -#import <pthread.h> - - -#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42) -// Some versions of GCC (4.2 and below AFAIK) aren't great about supporting -// -Wmissing-format-attribute -// when the function is anything more complex than foo(NSString *fmt, ...). -// You see the error inside the function when you turn ... into va_args and -// attempt to call another function (like vsprintf for example). -// So we just shut off the warning for this file. We reenable it at the end. -#pragma GCC diagnostic ignored "-Wmissing-format-attribute" -#endif // !__clang__ - -// Reference to the shared GTMLogger instance. This is not a singleton, it's -// just an easy reference to one shared instance. -static GTMLogger *gSharedLogger = nil; - - -@implementation GTMLogger - -// Returns a pointer to the shared logger instance. If none exists, a standard -// logger is created and returned. -+ (id)sharedLogger { - @synchronized(self) { - if (gSharedLogger == nil) { - gSharedLogger = [[self standardLogger] retain]; - } - } - return [[gSharedLogger retain] autorelease]; -} - -+ (void)setSharedLogger:(GTMLogger *)logger { - @synchronized(self) { - [gSharedLogger autorelease]; - gSharedLogger = [logger retain]; - } -} - -+ (id)standardLogger { - // Don't trust NSFileHandle not to throw - @try { - id<GTMLogWriter> writer = [NSFileHandle fileHandleWithStandardOutput]; - id<GTMLogFormatter> fr = [[[GTMLogStandardFormatter alloc] init] - autorelease]; - id<GTMLogFilter> filter = [[[GTMLogLevelFilter alloc] init] autorelease]; - return [[[self alloc] initWithWriter:writer - formatter:fr - filter:filter] autorelease]; - } - @catch (id e) { - // Ignored - } - return nil; -} - -+ (id)standardLoggerWithStderr { - // Don't trust NSFileHandle not to throw - @try { - id me = [self standardLogger]; - [me setWriter:[NSFileHandle fileHandleWithStandardError]]; - return me; - } - @catch (id e) { - // Ignored - } - return nil; -} - -+ (id)standardLoggerWithStdoutAndStderr { - // We're going to take advantage of the GTMLogger to GTMLogWriter adaptor - // and create a composite logger that an outer "standard" logger can use - // as a writer. Our inner loggers should apply no formatting since the main - // logger does that and we want the caller to be able to change formatters - // or add writers without knowing the inner structure of our composite. - - // Don't trust NSFileHandle not to throw - @try { - GTMLogBasicFormatter *formatter = [[[GTMLogBasicFormatter alloc] init] - autorelease]; - GTMLogger *stdoutLogger = - [self loggerWithWriter:[NSFileHandle fileHandleWithStandardOutput] - formatter:formatter - filter:[[[GTMLogMaximumLevelFilter alloc] - initWithMaximumLevel:kGTMLoggerLevelInfo] - autorelease]]; - GTMLogger *stderrLogger = - [self loggerWithWriter:[NSFileHandle fileHandleWithStandardError] - formatter:formatter - filter:[[[GTMLogMininumLevelFilter alloc] - initWithMinimumLevel:kGTMLoggerLevelError] - autorelease]]; - GTMLogger *compositeWriter = - [self loggerWithWriter:[NSArray arrayWithObjects: - stdoutLogger, stderrLogger, nil] - formatter:formatter - filter:[[[GTMLogNoFilter alloc] init] autorelease]]; - GTMLogger *outerLogger = [self standardLogger]; - [outerLogger setWriter:compositeWriter]; - return outerLogger; - } - @catch (id e) { - // Ignored - } - return nil; -} - -+ (id)standardLoggerWithPath:(NSString *)path { - @try { - NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644]; - if (fh == nil) return nil; - id me = [self standardLogger]; - [me setWriter:fh]; - return me; - } - @catch (id e) { - // Ignored - } - return nil; -} - -+ (id)loggerWithWriter:(id<GTMLogWriter>)writer - formatter:(id<GTMLogFormatter>)formatter - filter:(id<GTMLogFilter>)filter { - return [[[self alloc] initWithWriter:writer - formatter:formatter - filter:filter] autorelease]; -} - -+ (id)logger { - return [[[self alloc] init] autorelease]; -} - -- (id)init { - return [self initWithWriter:nil formatter:nil filter:nil]; -} - -- (id)initWithWriter:(id<GTMLogWriter>)writer - formatter:(id<GTMLogFormatter>)formatter - filter:(id<GTMLogFilter>)filter { - if ((self = [super init])) { - [self setWriter:writer]; - [self setFormatter:formatter]; - [self setFilter:filter]; - } - return self; -} - -- (void)dealloc { - // Unlikely, but |writer_| may be an NSFileHandle, which can throw - @try { - [formatter_ release]; - [filter_ release]; - [writer_ release]; - } - @catch (id e) { - // Ignored - } - [super dealloc]; -} - -- (id<GTMLogWriter>)writer { - return [[writer_ retain] autorelease]; -} - -- (void)setWriter:(id<GTMLogWriter>)writer { - @synchronized(self) { - [writer_ autorelease]; - writer_ = nil; - if (writer == nil) { - // Try to use stdout, but don't trust NSFileHandle - @try { - writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain]; - } - @catch (id e) { - // Leave |writer_| nil - } - } else { - writer_ = [writer retain]; - } - } -} - -- (id<GTMLogFormatter>)formatter { - return [[formatter_ retain] autorelease]; -} - -- (void)setFormatter:(id<GTMLogFormatter>)formatter { - @synchronized(self) { - [formatter_ autorelease]; - formatter_ = nil; - if (formatter == nil) { - @try { - formatter_ = [[GTMLogBasicFormatter alloc] init]; - } - @catch (id e) { - // Leave |formatter_| nil - } - } else { - formatter_ = [formatter retain]; - } - } -} - -- (id<GTMLogFilter>)filter { - return [[filter_ retain] autorelease]; -} - -- (void)setFilter:(id<GTMLogFilter>)filter { - @synchronized(self) { - [filter_ autorelease]; - filter_ = nil; - if (filter == nil) { - @try { - filter_ = [[GTMLogNoFilter alloc] init]; - } - @catch (id e) { - // Leave |filter_| nil - } - } else { - filter_ = [filter retain]; - } - } -} - -- (void)logDebug:(NSString *)fmt, ... { - va_list args; - va_start(args, fmt); - [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelDebug]; - va_end(args); -} - -- (void)logInfo:(NSString *)fmt, ... { - va_list args; - va_start(args, fmt); - [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelInfo]; - va_end(args); -} - -- (void)logError:(NSString *)fmt, ... { - va_list args; - va_start(args, fmt); - [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelError]; - va_end(args); -} - -- (void)logAssert:(NSString *)fmt, ... { - va_list args; - va_start(args, fmt); - [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelAssert]; - va_end(args); -} - -@end // GTMLogger - -@implementation GTMLogger (GTMLoggerMacroHelpers) - -- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... { - va_list args; - va_start(args, fmt); - [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelDebug]; - va_end(args); -} - -- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ... { - va_list args; - va_start(args, fmt); - [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelInfo]; - va_end(args); -} - -- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ... { - va_list args; - va_start(args, fmt); - [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelError]; - va_end(args); -} - -- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ... { - va_list args; - va_start(args, fmt); - [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelAssert]; - va_end(args); -} - -@end // GTMLoggerMacroHelpers - -@implementation GTMLogger (PrivateMethods) - -- (void)logInternalFunc:(const char *)func - format:(NSString *)fmt - valist:(va_list)args - level:(GTMLoggerLevel)level { - // Primary point where logging happens, logging should never throw, catch - // everything. - @try { - NSString *fname = func ? [NSString stringWithUTF8String:func] : nil; - NSString *msg = [formatter_ stringForFunc:fname - withFormat:fmt - valist:args - level:level]; - if (msg && [filter_ filterAllowsMessage:msg level:level]) - [writer_ logMessage:msg level:level]; - } - @catch (id e) { - // Ignored - } -} - -@end // PrivateMethods - - -@implementation NSFileHandle (GTMFileHandleLogWriter) - -+ (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode { - int fd = -1; - if (path) { - int flags = O_WRONLY | O_APPEND | O_CREAT; - fd = open([path fileSystemRepresentation], flags, mode); - } - if (fd == -1) return nil; - return [[[self alloc] initWithFileDescriptor:fd - closeOnDealloc:YES] autorelease]; -} - -- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level { - @synchronized(self) { - // Closed pipes should not generate exceptions in our caller. Catch here - // as well [GTMLogger logInternalFunc:...] so that an exception in this - // writer does not prevent other writers from having a chance. - @try { - NSString *line = [NSString stringWithFormat:@"%@\n", msg]; - [self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]]; - } - @catch (id e) { - // Ignored - } - } -} - -@end // GTMFileHandleLogWriter - - -@implementation NSArray (GTMArrayCompositeLogWriter) - -- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level { - @synchronized(self) { - id<GTMLogWriter> child = nil; - GTM_FOREACH_OBJECT(child, self) { - if ([child conformsToProtocol:@protocol(GTMLogWriter)]) - [child logMessage:msg level:level]; - } - } -} - -@end // GTMArrayCompositeLogWriter - - -@implementation GTMLogger (GTMLoggerLogWriter) - -- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level { - switch (level) { - case kGTMLoggerLevelDebug: - [self logDebug:@"%@", msg]; - break; - case kGTMLoggerLevelInfo: - [self logInfo:@"%@", msg]; - break; - case kGTMLoggerLevelError: - [self logError:@"%@", msg]; - break; - case kGTMLoggerLevelAssert: - [self logAssert:@"%@", msg]; - break; - default: - // Ignore the message. - break; - } -} - -@end // GTMLoggerLogWriter - - -@implementation GTMLogBasicFormatter - -- (NSString *)prettyNameForFunc:(NSString *)func { - NSString *name = [func stringByTrimmingCharactersInSet: - [NSCharacterSet whitespaceAndNewlineCharacterSet]]; - NSString *function = @"(unknown)"; - if ([name length]) { - if (// Objective C __func__ and __PRETTY_FUNCTION__ - [name hasPrefix:@"-["] || [name hasPrefix:@"+["] || - // C++ __PRETTY_FUNCTION__ and other preadorned formats - [name hasSuffix:@")"]) { - function = name; - } else { - // Assume C99 __func__ - function = [NSString stringWithFormat:@"%@()", name]; - } - } - return function; -} - -- (NSString *)stringForFunc:(NSString *)func - withFormat:(NSString *)fmt - valist:(va_list)args - level:(GTMLoggerLevel)level { - // Performance note: We may want to do a quick check here to see if |fmt| - // contains a '%', and if not, simply return 'fmt'. - if (!(fmt && args)) return nil; - return [[[NSString alloc] initWithFormat:fmt arguments:args] autorelease]; -} - -@end // GTMLogBasicFormatter - - -@implementation GTMLogStandardFormatter - -- (id)init { - if ((self = [super init])) { - dateFormatter_ = [[NSDateFormatter alloc] init]; - [dateFormatter_ setFormatterBehavior:NSDateFormatterBehavior10_4]; - [dateFormatter_ setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"]; - pname_ = [[[NSProcessInfo processInfo] processName] copy]; - pid_ = [[NSProcessInfo processInfo] processIdentifier]; - if (!(dateFormatter_ && pname_)) { - [self release]; - return nil; - } - } - return self; -} - -- (void)dealloc { - [dateFormatter_ release]; - [pname_ release]; - [super dealloc]; -} - -- (NSString *)stringForFunc:(NSString *)func - withFormat:(NSString *)fmt - valist:(va_list)args - level:(GTMLoggerLevel)level { - NSString *tstamp = nil; - @synchronized (dateFormatter_) { - tstamp = [dateFormatter_ stringFromDate:[NSDate date]]; - } - return [NSString stringWithFormat:@"%@ %@[%d/%p] [lvl=%d] %@ %@", - tstamp, pname_, pid_, pthread_self(), - level, [self prettyNameForFunc:func], - // |super| has guard for nil |fmt| and |args| - [super stringForFunc:func withFormat:fmt valist:args level:level]]; -} - -@end // GTMLogStandardFormatter - - -@implementation GTMLogLevelFilter - -// Check the environment and the user preferences for the GTMVerboseLogging key -// to see if verbose logging has been enabled. The environment variable will -// override the defaults setting, so check the environment first. -// COV_NF_START -static BOOL IsVerboseLoggingEnabled(void) { - static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging"; - NSString *value = [[[NSProcessInfo processInfo] environment] - objectForKey:kVerboseLoggingKey]; - if (value) { - // Emulate [NSString boolValue] for pre-10.5 - value = [value stringByTrimmingCharactersInSet: - [NSCharacterSet whitespaceAndNewlineCharacterSet]]; - if ([[value uppercaseString] hasPrefix:@"Y"] || - [[value uppercaseString] hasPrefix:@"T"] || - [value intValue]) { - return YES; - } else { - return NO; - } - } - return [[NSUserDefaults standardUserDefaults] boolForKey:kVerboseLoggingKey]; -} -// COV_NF_END - -// In DEBUG builds, log everything. If we're not in a debug build we'll assume -// that we're in a Release build. -- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level { -#if defined(DEBUG) && DEBUG - return YES; -#endif - - BOOL allow = YES; - - switch (level) { - case kGTMLoggerLevelDebug: - allow = NO; - break; - case kGTMLoggerLevelInfo: - allow = IsVerboseLoggingEnabled(); - break; - case kGTMLoggerLevelError: - allow = YES; - break; - case kGTMLoggerLevelAssert: - allow = YES; - break; - default: - allow = YES; - break; - } - - return allow; -} - -@end // GTMLogLevelFilter - - -@implementation GTMLogNoFilter - -- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level { - return YES; // Allow everything through -} - -@end // GTMLogNoFilter - - -@implementation GTMLogAllowedLevelFilter - -// Private designated initializer -- (id)initWithAllowedLevels:(NSIndexSet *)levels { - self = [super init]; - if (self != nil) { - allowedLevels_ = [levels retain]; - // Cap min/max level - if (!allowedLevels_ || - // NSIndexSet is unsigned so only check the high bound, but need to - // check both first and last index because NSIndexSet appears to allow - // wraparound. - ([allowedLevels_ firstIndex] > kGTMLoggerLevelAssert) || - ([allowedLevels_ lastIndex] > kGTMLoggerLevelAssert)) { - [self release]; - return nil; - } - } - return self; -} - -- (id)init { - // Allow all levels in default init - return [self initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange: - NSMakeRange(kGTMLoggerLevelUnknown, - (kGTMLoggerLevelAssert - kGTMLoggerLevelUnknown + 1))]]; -} - -- (void)dealloc { - [allowedLevels_ release]; - [super dealloc]; -} - -- (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level { - return [allowedLevels_ containsIndex:level]; -} - -@end // GTMLogAllowedLevelFilter - - -@implementation GTMLogMininumLevelFilter - -- (id)initWithMinimumLevel:(GTMLoggerLevel)level { - return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange: - NSMakeRange(level, - (kGTMLoggerLevelAssert - level + 1))]]; -} - -@end // GTMLogMininumLevelFilter - - -@implementation GTMLogMaximumLevelFilter - -- (id)initWithMaximumLevel:(GTMLoggerLevel)level { - return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange: - NSMakeRange(kGTMLoggerLevelUnknown, level + 1)]]; -} - -@end // GTMLogMaximumLevelFilter - -#if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42) -// See comment at top of file. -#pragma GCC diagnostic error "-Wmissing-format-attribute" -#endif // !__clang__ - diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.h b/toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.h deleted file mode 100644 index 42e8fed39..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.h +++ /dev/null @@ -1,61 +0,0 @@ -// 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. - -// HTTPMultipartUpload: A multipart/form-data HTTP uploader. -// Each parameter pair is sent as a boundary -// Each file is sent with a name field in addition to the filename and data -// The data will be sent synchronously. - -#import <Foundation/Foundation.h> - -@interface HTTPMultipartUpload : NSObject { - @protected - NSURL *url_; // The destination URL (STRONG) - NSDictionary *parameters_; // The key/value pairs for sending data (STRONG) - NSMutableDictionary *files_; // Dictionary of name/file-path (STRONG) - NSString *boundary_; // The boundary string (STRONG) - NSHTTPURLResponse *response_; // The response from the send (STRONG) -} - -- (id)initWithURL:(NSURL *)url; - -- (NSURL *)URL; - -- (void)setParameters:(NSDictionary *)parameters; -- (NSDictionary *)parameters; - -- (void)addFileAtPath:(NSString *)path name:(NSString *)name; -- (void)addFileContents:(NSData *)data name:(NSString *)name; -- (NSDictionary *)files; - -// Set the data and return the response -- (NSData *)send:(NSError **)error; -- (NSHTTPURLResponse *)response; - -@end diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.m b/toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.m deleted file mode 100644 index 9ac886d53..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/HTTPMultipartUpload.m +++ /dev/null @@ -1,269 +0,0 @@ -// 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. - -#import "HTTPMultipartUpload.h" -#import "GTMDefines.h" - -// As -[NSString stringByAddingPercentEscapesUsingEncoding:] has been -// deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements it -// using -[NSString stringByAddingPercentEncodingWithAllowedCharacters:] when -// using those SDKs. -static NSString *PercentEncodeNSString(NSString *key) { -#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \ - __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \ - (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ - defined(MAC_OS_X_VERSION_10_11) && \ - MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11) - return [key stringByAddingPercentEncodingWithAllowedCharacters: - [NSCharacterSet URLQueryAllowedCharacterSet]]; -#else - return [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; -#endif -} - -// As -[NSURLConnection sendSynchronousRequest:returningResponse:error:] has -// been deprecated with iOS 9.0 / OS X 10.11 SDKs, this function re-implements -// it using -[NSURLSession dataTaskWithRequest:completionHandler:] when using -// those SDKs. -static NSData *SendSynchronousNSURLRequest(NSURLRequest *req, - NSURLResponse **out_response, - NSError **out_error) { -#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && defined(__IPHONE_9_0) && \ - __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_9_0) || \ - (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && \ - defined(MAC_OS_X_VERSION_10_11) && \ - MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_11) - __block NSData* result = nil; - __block NSError* error = nil; - __block NSURLResponse* response = nil; - dispatch_semaphore_t wait_semaphone = dispatch_semaphore_create(0); - [[[NSURLSession sharedSession] - dataTaskWithRequest:req - completionHandler:^(NSData *data, - NSURLResponse *resp, - NSError *err) { - if (out_error) - error = [err retain]; - if (out_response) - response = [resp retain]; - if (err == nil) - result = [data retain]; - dispatch_semaphore_signal(wait_semaphone); - }] resume]; - dispatch_semaphore_wait(wait_semaphone, DISPATCH_TIME_FOREVER); - dispatch_release(wait_semaphone); - if (out_error) - *out_error = [error autorelease]; - if (out_response) - *out_response = [response autorelease]; - return [result autorelease]; -#else - return [NSURLConnection sendSynchronousRequest:req - returningResponse:out_response - error:out_error]; -#endif -} -@interface HTTPMultipartUpload(PrivateMethods) -- (NSString *)multipartBoundary; -// Each of the following methods will append the starting multipart boundary, -// but not the ending one. -- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value; -- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name; -- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name; -@end - -@implementation HTTPMultipartUpload -//============================================================================= -#pragma mark - -#pragma mark || Private || -//============================================================================= -- (NSString *)multipartBoundary { - // The boundary has 27 '-' characters followed by 16 hex digits - return [NSString stringWithFormat:@"---------------------------%08X%08X", - rand(), rand()]; -} - -//============================================================================= -- (NSData *)formDataForKey:(NSString *)key value:(NSString *)value { - NSString *escaped = PercentEncodeNSString(key); - NSString *fmt = - @"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n"; - NSString *form = [NSString stringWithFormat:fmt, boundary_, escaped, value]; - - return [form dataUsingEncoding:NSUTF8StringEncoding]; -} - -//============================================================================= -- (NSData *)formDataForFileContents:(NSData *)contents name:(NSString *)name { - NSMutableData *data = [NSMutableData data]; - NSString *escaped = PercentEncodeNSString(name); - NSString *fmt = @"--%@\r\nContent-Disposition: form-data; name=\"%@\"; " - "filename=\"minidump.dmp\"\r\nContent-Type: application/octet-stream\r\n\r\n"; - NSString *pre = [NSString stringWithFormat:fmt, boundary_, escaped]; - - [data appendData:[pre dataUsingEncoding:NSUTF8StringEncoding]]; - [data appendData:contents]; - - return data; -} - -//============================================================================= -- (NSData *)formDataForFile:(NSString *)file name:(NSString *)name { - NSData *contents = [NSData dataWithContentsOfFile:file]; - - return [self formDataForFileContents:contents name:name]; -} - -//============================================================================= -#pragma mark - -#pragma mark || Public || -//============================================================================= -- (id)initWithURL:(NSURL *)url { - if ((self = [super init])) { - url_ = [url copy]; - boundary_ = [[self multipartBoundary] retain]; - files_ = [[NSMutableDictionary alloc] init]; - } - - return self; -} - -//============================================================================= -- (void)dealloc { - [url_ release]; - [parameters_ release]; - [files_ release]; - [boundary_ release]; - [response_ release]; - - [super dealloc]; -} - -//============================================================================= -- (NSURL *)URL { - return url_; -} - -//============================================================================= -- (void)setParameters:(NSDictionary *)parameters { - if (parameters != parameters_) { - [parameters_ release]; - parameters_ = [parameters copy]; - } -} - -//============================================================================= -- (NSDictionary *)parameters { - return parameters_; -} - -//============================================================================= -- (void)addFileAtPath:(NSString *)path name:(NSString *)name { - [files_ setObject:path forKey:name]; -} - -//============================================================================= -- (void)addFileContents:(NSData *)data name:(NSString *)name { - [files_ setObject:data forKey:name]; -} - -//============================================================================= -- (NSDictionary *)files { - return files_; -} - -//============================================================================= -- (NSData *)send:(NSError **)error { - NSMutableURLRequest *req = - [[NSMutableURLRequest alloc] - initWithURL:url_ cachePolicy:NSURLRequestUseProtocolCachePolicy - timeoutInterval:10.0 ]; - - NSMutableData *postBody = [NSMutableData data]; - - [req setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", - boundary_] forHTTPHeaderField:@"Content-type"]; - - // Add any parameters to the message - NSArray *parameterKeys = [parameters_ allKeys]; - NSString *key; - - NSInteger count = [parameterKeys count]; - for (NSInteger i = 0; i < count; ++i) { - key = [parameterKeys objectAtIndex:i]; - [postBody appendData:[self formDataForKey:key - value:[parameters_ objectForKey:key]]]; - } - - // Add any files to the message - NSArray *fileNames = [files_ allKeys]; - count = [fileNames count]; - for (NSInteger i = 0; i < count; ++i) { - NSString *name = [fileNames objectAtIndex:i]; - id fileOrData = [files_ objectForKey:name]; - NSData *fileData; - - // The object can be either the path to a file (NSString) or the contents - // of the file (NSData). - if ([fileOrData isKindOfClass:[NSData class]]) - fileData = [self formDataForFileContents:fileOrData name:name]; - else - fileData = [self formDataForFile:fileOrData name:name]; - - [postBody appendData:fileData]; - } - - NSString *epilogue = [NSString stringWithFormat:@"\r\n--%@--\r\n", boundary_]; - [postBody appendData:[epilogue dataUsingEncoding:NSUTF8StringEncoding]]; - - [req setHTTPBody:postBody]; - [req setHTTPMethod:@"POST"]; - - [response_ release]; - response_ = nil; - - NSData *data = nil; - if ([[req URL] isFileURL]) { - [[req HTTPBody] writeToURL:[req URL] options:0 error:error]; - } else { - NSURLResponse *response = nil; - data = SendSynchronousNSURLRequest(req, &response, error); - response_ = (NSHTTPURLResponse *)[response retain]; - } - [req release]; - - return data; -} - -//============================================================================= -- (NSHTTPURLResponse *)response { - return response_; -} - -@end diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.h b/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.h deleted file mode 100644 index 8df9165bb..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.h +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright (c) 2007, 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. -// -// MachIPC.h -// -// Some helpful wrappers for using Mach IPC calls - -#ifndef MACH_IPC_H__ -#define MACH_IPC_H__ - -#import <mach/mach.h> -#import <mach/message.h> -#import <servers/bootstrap.h> -#import <sys/types.h> - -#import <CoreServices/CoreServices.h> - -//============================================================================== -// DISCUSSION: -// -// The three main classes of interest are -// -// MachMessage: a wrapper for a mach message of the following form -// mach_msg_header_t -// mach_msg_body_t -// optional descriptors -// optional extra message data -// -// MachReceiveMessage and MachSendMessage subclass MachMessage -// and are used instead of MachMessage which is an abstract base class -// -// ReceivePort: -// Represents a mach port for which we have receive rights -// -// MachPortSender: -// Represents a mach port for which we have send rights -// -// Here's an example to receive a message on a server port: -// -// // This creates our named server port -// ReceivePort receivePort("com.Google.MyService"); -// -// MachReceiveMessage message; -// kern_return_t result = receivePort.WaitForMessage(&message, 0); -// -// if (result == KERN_SUCCESS && message.GetMessageID() == 57) { -// mach_port_t task = message.GetTranslatedPort(0); -// mach_port_t thread = message.GetTranslatedPort(1); -// -// char *messageString = message.GetData(); -// -// printf("message string = %s\n", messageString); -// } -// -// Here is an example of using these classes to send a message to this port: -// -// // send to already named port -// MachPortSender sender("com.Google.MyService"); -// MachSendMessage message(57); // our message ID is 57 -// -// // add some ports to be translated for us -// message.AddDescriptor(mach_task_self()); // our task -// message.AddDescriptor(mach_thread_self()); // this thread -// -// char messageString[] = "Hello server!\n"; -// message.SetData(messageString, strlen(messageString)+1); -// -// kern_return_t result = sender.SendMessage(message, 1000); // timeout 1000ms -// - -namespace google_breakpad { -#define PRINT_MACH_RESULT(result_, message_) \ - printf(message_" %s (%d)\n", mach_error_string(result_), result_ ); - -//============================================================================== -// A wrapper class for mach_msg_port_descriptor_t (with same memory layout) -// with convenient constructors and accessors -class MachMsgPortDescriptor : public mach_msg_port_descriptor_t { - public: - // General-purpose constructor - MachMsgPortDescriptor(mach_port_t in_name, - mach_msg_type_name_t in_disposition) { - name = in_name; - pad1 = 0; - pad2 = 0; - disposition = in_disposition; - type = MACH_MSG_PORT_DESCRIPTOR; - } - - // For passing send rights to a port - MachMsgPortDescriptor(mach_port_t in_name) { - name = in_name; - pad1 = 0; - pad2 = 0; - disposition = MACH_MSG_TYPE_COPY_SEND; - type = MACH_MSG_PORT_DESCRIPTOR; - } - - // Copy constructor - MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) { - name = desc.name; - pad1 = desc.pad1; - pad2 = desc.pad2; - disposition = desc.disposition; - type = desc.type; - } - - mach_port_t GetMachPort() const { - return name; - } - - mach_msg_type_name_t GetDisposition() const { - return disposition; - } - - // For convenience - operator mach_port_t() const { - return GetMachPort(); - } -}; - -//============================================================================== -// MachMessage: a wrapper for a mach message -// (mach_msg_header_t, mach_msg_body_t, extra data) -// -// This considerably simplifies the construction of a message for sending -// and the getting at relevant data and descriptors for the receiver. -// -// Currently the combined size of the descriptors plus data must be -// less than 1024. But as a benefit no memory allocation is necessary. -// -// TODO: could consider adding malloc() support for very large messages -// -// A MachMessage object is used by ReceivePort::WaitForMessage -// and MachPortSender::SendMessage -// -class MachMessage { - public: - - // The receiver of the message can retrieve the raw data this way - uint8_t *GetData() { - return GetDataLength() > 0 ? GetDataPacket()->data : NULL; - } - - uint32_t GetDataLength() { - return EndianU32_LtoN(GetDataPacket()->data_length); - } - - // The message ID may be used as a code identifying the type of message - void SetMessageID(int32_t message_id) { - GetDataPacket()->id = EndianU32_NtoL(message_id); - } - - int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); } - - // Adds a descriptor (typically a mach port) to be translated - // returns true if successful, otherwise not enough space - bool AddDescriptor(const MachMsgPortDescriptor &desc); - - int GetDescriptorCount() const { return body.msgh_descriptor_count; } - MachMsgPortDescriptor *GetDescriptor(int n); - - // Convenience method which gets the mach port described by the descriptor - mach_port_t GetTranslatedPort(int n); - - // A simple message is one with no descriptors - bool IsSimpleMessage() const { return GetDescriptorCount() == 0; } - - // Sets raw data for the message (returns false if not enough space) - bool SetData(void *data, int32_t data_length); - - protected: - // Consider this an abstract base class - must create an actual instance - // of MachReceiveMessage or MachSendMessage - - MachMessage() { - memset(this, 0, sizeof(MachMessage)); - } - - friend class ReceivePort; - friend class MachPortSender; - - // Represents raw data in our message - struct MessageDataPacket { - int32_t id; // little-endian - int32_t data_length; // little-endian - uint8_t data[1]; // actual size limited by sizeof(MachMessage) - }; - - MessageDataPacket* GetDataPacket(); - - void SetDescriptorCount(int n); - void SetDescriptor(int n, const MachMsgPortDescriptor &desc); - - // Returns total message size setting msgh_size in the header to this value - mach_msg_size_t CalculateSize(); - - mach_msg_header_t head; - mach_msg_body_t body; - uint8_t padding[1024]; // descriptors and data may be embedded here -}; - -//============================================================================== -// MachReceiveMessage and MachSendMessage are useful to separate the idea -// of a mach message being sent and being received, and adds increased type -// safety: -// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage -// MachPortSender::SendMessage() only accepts a MachSendMessage - -//============================================================================== -class MachReceiveMessage : public MachMessage { - public: - MachReceiveMessage() : MachMessage() {}; -}; - -//============================================================================== -class MachSendMessage : public MachMessage { - public: - MachSendMessage(int32_t message_id); -}; - -//============================================================================== -// Represents a mach port for which we have receive rights -class ReceivePort { - public: - // Creates a new mach port for receiving messages and registers a name for it - explicit ReceivePort(const char *receive_port_name); - - // Given an already existing mach port, use it. We take ownership of the - // port and deallocate it in our destructor. - explicit ReceivePort(mach_port_t receive_port); - - // Create a new mach port for receiving messages - ReceivePort(); - - ~ReceivePort(); - - // Waits on the mach port until message received or timeout - kern_return_t WaitForMessage(MachReceiveMessage *out_message, - mach_msg_timeout_t timeout); - - // The underlying mach port that we wrap - mach_port_t GetPort() const { return port_; } - - private: - ReceivePort(const ReceivePort&); // disable copy c-tor - - mach_port_t port_; - kern_return_t init_result_; -}; - -//============================================================================== -// Represents a mach port for which we have send rights -class MachPortSender { - public: - // get a port with send rights corresponding to a named registered service - explicit MachPortSender(const char *receive_port_name); - - - // Given an already existing mach port, use it. - explicit MachPortSender(mach_port_t send_port); - - kern_return_t SendMessage(MachSendMessage &message, - mach_msg_timeout_t timeout); - - private: - MachPortSender(const MachPortSender&); // disable copy c-tor - - mach_port_t send_port_; - kern_return_t init_result_; -}; - -} // namespace google_breakpad - -#endif // MACH_IPC_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.mm b/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.mm deleted file mode 100644 index dc9773f77..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/MachIPC.mm +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright (c) 2007, 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. -// -// MachIPC.mm -// Wrapper for mach IPC calls - -#import <stdio.h> -#import "MachIPC.h" -#include "common/mac/bootstrap_compat.h" - -namespace google_breakpad { -//============================================================================== -MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() { - head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0); - - // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage() - head.msgh_local_port = MACH_PORT_NULL; - head.msgh_reserved = 0; - head.msgh_id = 0; - - SetDescriptorCount(0); // start out with no descriptors - - SetMessageID(message_id); - SetData(NULL, 0); // client may add data later -} - -//============================================================================== -// returns true if successful -bool MachMessage::SetData(void *data, - int32_t data_length) { - // first check to make sure we have enough space - size_t size = CalculateSize(); - size_t new_size = size + data_length; - - if (new_size > sizeof(MachMessage)) { - return false; // not enough space - } - - GetDataPacket()->data_length = EndianU32_NtoL(data_length); - if (data) memcpy(GetDataPacket()->data, data, data_length); - - CalculateSize(); - - return true; -} - -//============================================================================== -// calculates and returns the total size of the message -// Currently, the entire message MUST fit inside of the MachMessage -// messsage size <= sizeof(MachMessage) -mach_msg_size_t MachMessage::CalculateSize() { - size_t size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t); - - // add space for MessageDataPacket - int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3; - size += 2*sizeof(int32_t) + alignedDataLength; - - // add space for descriptors - size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor); - - head.msgh_size = static_cast<mach_msg_size_t>(size); - - return head.msgh_size; -} - -//============================================================================== -MachMessage::MessageDataPacket *MachMessage::GetDataPacket() { - size_t desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount(); - MessageDataPacket *packet = - reinterpret_cast<MessageDataPacket*>(padding + desc_size); - - return packet; -} - -//============================================================================== -void MachMessage::SetDescriptor(int n, - const MachMsgPortDescriptor &desc) { - MachMsgPortDescriptor *desc_array = - reinterpret_cast<MachMsgPortDescriptor*>(padding); - desc_array[n] = desc; -} - -//============================================================================== -// returns true if successful otherwise there was not enough space -bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) { - // first check to make sure we have enough space - int size = CalculateSize(); - size_t new_size = size + sizeof(MachMsgPortDescriptor); - - if (new_size > sizeof(MachMessage)) { - return false; // not enough space - } - - // unfortunately, we need to move the data to allow space for the - // new descriptor - u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket()); - bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t)); - - SetDescriptor(GetDescriptorCount(), desc); - SetDescriptorCount(GetDescriptorCount() + 1); - - CalculateSize(); - - return true; -} - -//============================================================================== -void MachMessage::SetDescriptorCount(int n) { - body.msgh_descriptor_count = n; - - if (n > 0) { - head.msgh_bits |= MACH_MSGH_BITS_COMPLEX; - } else { - head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX; - } -} - -//============================================================================== -MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) { - if (n < GetDescriptorCount()) { - MachMsgPortDescriptor *desc = - reinterpret_cast<MachMsgPortDescriptor*>(padding); - return desc + n; - } - - return nil; -} - -//============================================================================== -mach_port_t MachMessage::GetTranslatedPort(int n) { - if (n < GetDescriptorCount()) { - return GetDescriptor(n)->GetMachPort(); - } - return MACH_PORT_NULL; -} - -#pragma mark - - -//============================================================================== -// create a new mach port for receiving messages and register a name for it -ReceivePort::ReceivePort(const char *receive_port_name) { - mach_port_t current_task = mach_task_self(); - - init_result_ = mach_port_allocate(current_task, - MACH_PORT_RIGHT_RECEIVE, - &port_); - - if (init_result_ != KERN_SUCCESS) - return; - - init_result_ = mach_port_insert_right(current_task, - port_, - port_, - MACH_MSG_TYPE_MAKE_SEND); - - if (init_result_ != KERN_SUCCESS) - return; - - mach_port_t task_bootstrap_port = 0; - init_result_ = task_get_bootstrap_port(current_task, &task_bootstrap_port); - - if (init_result_ != KERN_SUCCESS) - return; - - init_result_ = breakpad::BootstrapRegister( - bootstrap_port, - const_cast<char*>(receive_port_name), - port_); -} - -//============================================================================== -// create a new mach port for receiving messages -ReceivePort::ReceivePort() { - mach_port_t current_task = mach_task_self(); - - init_result_ = mach_port_allocate(current_task, - MACH_PORT_RIGHT_RECEIVE, - &port_); - - if (init_result_ != KERN_SUCCESS) - return; - - init_result_ = mach_port_insert_right(current_task, - port_, - port_, - MACH_MSG_TYPE_MAKE_SEND); -} - -//============================================================================== -// Given an already existing mach port, use it. We take ownership of the -// port and deallocate it in our destructor. -ReceivePort::ReceivePort(mach_port_t receive_port) - : port_(receive_port), - init_result_(KERN_SUCCESS) { -} - -//============================================================================== -ReceivePort::~ReceivePort() { - if (init_result_ == KERN_SUCCESS) - mach_port_deallocate(mach_task_self(), port_); -} - -//============================================================================== -kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message, - mach_msg_timeout_t timeout) { - if (!out_message) { - return KERN_INVALID_ARGUMENT; - } - - // return any error condition encountered in constructor - if (init_result_ != KERN_SUCCESS) - return init_result_; - - out_message->head.msgh_bits = 0; - out_message->head.msgh_local_port = port_; - out_message->head.msgh_remote_port = MACH_PORT_NULL; - out_message->head.msgh_reserved = 0; - out_message->head.msgh_id = 0; - - mach_msg_option_t options = MACH_RCV_MSG; - if (timeout != MACH_MSG_TIMEOUT_NONE) - options |= MACH_RCV_TIMEOUT; - kern_return_t result = mach_msg(&out_message->head, - options, - 0, - sizeof(MachMessage), - port_, - timeout, // timeout in ms - MACH_PORT_NULL); - - return result; -} - -#pragma mark - - -//============================================================================== -// get a port with send rights corresponding to a named registered service -MachPortSender::MachPortSender(const char *receive_port_name) { - mach_port_t task_bootstrap_port = 0; - init_result_ = task_get_bootstrap_port(mach_task_self(), - &task_bootstrap_port); - - if (init_result_ != KERN_SUCCESS) - return; - - init_result_ = bootstrap_look_up(task_bootstrap_port, - const_cast<char*>(receive_port_name), - &send_port_); -} - -//============================================================================== -MachPortSender::MachPortSender(mach_port_t send_port) - : send_port_(send_port), - init_result_(KERN_SUCCESS) { -} - -//============================================================================== -kern_return_t MachPortSender::SendMessage(MachSendMessage &message, - mach_msg_timeout_t timeout) { - if (message.head.msgh_size == 0) { - return KERN_INVALID_VALUE; // just for safety -- never should occur - }; - - if (init_result_ != KERN_SUCCESS) - return init_result_; - - message.head.msgh_remote_port = send_port_; - - kern_return_t result = mach_msg(&message.head, - MACH_SEND_MSG | MACH_SEND_TIMEOUT, - message.head.msgh_size, - 0, - MACH_PORT_NULL, - timeout, // timeout in ms - MACH_PORT_NULL); - - return result; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.cc deleted file mode 100644 index 4e5f5534a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.cc +++ /dev/null @@ -1,211 +0,0 @@ -// 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/mac/arch_utilities.h" - -#include <mach-o/arch.h> -#include <mach-o/fat.h> -#include <stdio.h> -#include <string.h> - -#ifndef CPU_SUBTYPE_ARM_V7S -#define CPU_SUBTYPE_ARM_V7S (static_cast<cpu_subtype_t>(11)) -#endif // CPU_SUBTYPE_ARM_V7S - -#ifndef CPU_TYPE_ARM64 -#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) -#endif // CPU_TYPE_ARM64 - -#ifndef CPU_SUBTYPE_ARM64_ALL -#define CPU_SUBTYPE_ARM64_ALL (static_cast<cpu_subtype_t>(0)) -#endif // CPU_SUBTYPE_ARM64_ALL - -namespace { - -const NXArchInfo* ArchInfo_arm64() { - NXArchInfo* arm64 = new NXArchInfo; - *arm64 = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM, - CPU_SUBTYPE_ARM_V7); - arm64->name = "arm64"; - arm64->cputype = CPU_TYPE_ARM64; - arm64->cpusubtype = CPU_SUBTYPE_ARM64_ALL; - arm64->description = "arm 64"; - return arm64; -} - -const NXArchInfo* ArchInfo_armv7s() { - NXArchInfo* armv7s = new NXArchInfo; - *armv7s = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM, - CPU_SUBTYPE_ARM_V7); - armv7s->name = "armv7s"; - armv7s->cpusubtype = CPU_SUBTYPE_ARM_V7S; - armv7s->description = "arm v7s"; - return armv7s; -} - -} // namespace - -namespace google_breakpad { - -const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name) { - // TODO: Remove this when the OS knows about arm64. - if (!strcmp("arm64", arch_name)) - return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM64, - CPU_SUBTYPE_ARM64_ALL); - - // TODO: Remove this when the OS knows about armv7s. - if (!strcmp("armv7s", arch_name)) - return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S); - - return NXGetArchInfoFromName(arch_name); -} - -const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype) { - // TODO: Remove this when the OS knows about arm64. - if (cpu_type == CPU_TYPE_ARM64 && cpu_subtype == CPU_SUBTYPE_ARM64_ALL) { - static const NXArchInfo* arm64 = ArchInfo_arm64(); - return arm64; - } - - // TODO: Remove this when the OS knows about armv7s. - if (cpu_type == CPU_TYPE_ARM && cpu_subtype == CPU_SUBTYPE_ARM_V7S) { - static const NXArchInfo* armv7s = ArchInfo_armv7s(); - return armv7s; - } - - return NXGetArchInfoFromCpuType(cpu_type, cpu_subtype); -} - -} // namespace google_breakpad - -#ifndef __APPLE__ -namespace { - -enum Architecture { - kArch_i386 = 0, - kArch_x86_64, - kArch_arm, - kArch_arm64, - kArch_ppc, - // This must be last. - kNumArchitectures -}; - -// enum Architecture above and kKnownArchitectures below -// must be kept in sync. -const NXArchInfo kKnownArchitectures[] = { - { - "i386", - CPU_TYPE_I386, - CPU_SUBTYPE_I386_ALL, - NX_LittleEndian, - "Intel 80x86" - }, - { - "x86_64", - CPU_TYPE_X86_64, - CPU_SUBTYPE_X86_64_ALL, - NX_LittleEndian, - "Intel x86-64" - }, - { - "arm", - CPU_TYPE_ARM, - CPU_SUBTYPE_ARM_ALL, - NX_LittleEndian, - "ARM" - }, - { - "arm64", - CPU_TYPE_ARM64, - CPU_SUBTYPE_ARM64_ALL, - NX_LittleEndian, - "ARM64" - }, - { - "ppc", - CPU_TYPE_POWERPC, - CPU_SUBTYPE_POWERPC_ALL, - NX_BigEndian, - "PowerPC" - } -}; - -} // namespace - -const NXArchInfo *NXGetLocalArchInfo(void) { - Architecture arch; -#if defined(__i386__) - arch = kArch_i386; -#elif defined(__x86_64__) - arch = kArch_x86_64; -#elif defined(__arm64) - arch = kArch_arm64; -#elif defined(__arm__) - arch = kArch_arm; -#elif defined(__powerpc__) - arch = kArch_ppc; -#else - #error "Unsupported CPU architecture" -#endif - return &kKnownArchitectures[arch]; -} - -const NXArchInfo *NXGetArchInfoFromName(const char *name) { - for (int arch = 0; arch < kNumArchitectures; ++arch) { - if (!strcmp(name, kKnownArchitectures[arch].name)) { - return &kKnownArchitectures[arch]; - } - } - return NULL; -} - -const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype, - cpu_subtype_t cpusubtype) { - for (int arch = 0; arch < kNumArchitectures; ++arch) { - if (kKnownArchitectures[arch].cputype == cputype) { - return &kKnownArchitectures[arch]; - } - } - return NULL; -} - -struct fat_arch *NXFindBestFatArch(cpu_type_t cputype, - cpu_subtype_t cpusubtype, - struct fat_arch *fat_archs, - uint32_t nfat_archs) { - for (uint32_t f = 0; f < nfat_archs; ++f) { - if (fat_archs[f].cputype == cputype) { - return &fat_archs[f]; - } - } - return NULL; -} -#endif // !__APPLE__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.h b/toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.h deleted file mode 100644 index 397c1f587..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/arch_utilities.h +++ /dev/null @@ -1,47 +0,0 @@ -// 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. - -// arch_utilities.h: Utilities for architecture introspection for Mac platform. - -#ifndef COMMON_MAC_ARCH_UTILITIES_H__ -#define COMMON_MAC_ARCH_UTILITIES_H__ - -#include <mach-o/arch.h> - -namespace google_breakpad { - -// Custom implementation of |NXGetArchInfoFromName| and -// |NXGetArchInfoFromCpuType| that handle newer CPU on older OSes. -const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name); -const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype); - -} // namespace google_breakpad - -#endif // COMMON_MAC_ARCH_UTILITIES_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.cc deleted file mode 100644 index d875d95b5..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.cc +++ /dev/null @@ -1,42 +0,0 @@ -// 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/mac/bootstrap_compat.h" - -namespace breakpad { - -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" -kern_return_t BootstrapRegister(mach_port_t bp, - name_t service_name, - mach_port_t sp) { - return bootstrap_register(bp, service_name, sp); -} -#pragma GCC diagnostic warning "-Wdeprecated-declarations" - -} // namesapce breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.h b/toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.h deleted file mode 100644 index 8ca7357c3..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/bootstrap_compat.h +++ /dev/null @@ -1,54 +0,0 @@ -// 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_MAC_BOOTSTRAP_COMPAT_H_ -#define COMMON_MAC_BOOTSTRAP_COMPAT_H_ - -#include <servers/bootstrap.h> - -namespace breakpad { - -// Wrapper for bootstrap_register to avoid deprecation warnings. -// -// In 10.6, it's possible to call bootstrap_check_in as the one-stop-shop for -// handling what bootstrap_register is used for. In 10.5, bootstrap_check_in -// can't check in a service whose name has not yet been registered, despite -// bootstrap_register being marked as deprecated in that OS release. Breakpad -// needs to register new service names, and in 10.5, calling -// bootstrap_register is the only way to achieve that. Attempts to call -// bootstrap_check_in for a new service name on 10.5 will result in -// BOOTSTRAP_UNKNOWN_SERVICE being returned rather than registration of the -// new service name. -kern_return_t BootstrapRegister(mach_port_t bp, - name_t service_name, - mach_port_t sp); - -} // namespace breakpad - -#endif // COMMON_MAC_BOOTSTRAP_COMPAT_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/byteswap.h b/toolkit/crashreporter/google-breakpad/src/common/mac/byteswap.h deleted file mode 100644 index b7bbc0b95..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/byteswap.h +++ /dev/null @@ -1,73 +0,0 @@ -// -*- mode: c++ -*- - -// 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. - -// Original author: Jim Blandy <jim@mozilla.com> <jimb@red-bean.com> - -// byteswap.h: Overloaded functions for conveniently byteswapping values. - -#ifndef COMMON_MAC_BYTESWAP_H_ -#define COMMON_MAC_BYTESWAP_H_ - -#ifdef __APPLE__ -#include <libkern/OSByteOrder.h> - -static inline uint16_t ByteSwap(uint16_t v) { return OSSwapInt16(v); } -static inline uint32_t ByteSwap(uint32_t v) { return OSSwapInt32(v); } -static inline uint64_t ByteSwap(uint64_t v) { return OSSwapInt64(v); } -static inline int16_t ByteSwap(int16_t v) { return OSSwapInt16(v); } -static inline int32_t ByteSwap(int32_t v) { return OSSwapInt32(v); } -static inline int64_t ByteSwap(int64_t v) { return OSSwapInt64(v); } - -#elif defined(__linux__) -// For NXByteOrder -#include <architecture/byte_order.h> -#include <stdint.h> -#include <endian.h> -#include_next <byteswap.h> - -static inline uint16_t ByteSwap(uint16_t v) { return bswap_16(v); } -static inline uint32_t ByteSwap(uint32_t v) { return bswap_32(v); } -static inline uint64_t ByteSwap(uint64_t v) { return bswap_64(v); } -static inline int16_t ByteSwap(int16_t v) { return bswap_16(v); } -static inline int32_t ByteSwap(int32_t v) { return bswap_32(v); } -static inline int64_t ByteSwap(int64_t v) { return bswap_64(v); } - -static inline NXByteOrder NXHostByteOrder() { -#ifdef __LITTLE_ENDIAN - return NX_LittleEndian; -#else - return NX_BigEndian; -#endif -} - -#endif // __APPLE__ - -#endif // COMMON_MAC_BYTESWAP_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.cc deleted file mode 100644 index b20a05586..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.cc +++ /dev/null @@ -1,646 +0,0 @@ -// -*- 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. - -// Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dump_syms.mm: Create a symbol file for use with minidumps - -#include "common/mac/dump_syms.h" - -#include <assert.h> -#include <dirent.h> -#include <errno.h> -#include <libgen.h> -#include <mach-o/arch.h> -#include <mach-o/fat.h> -#include <stdint.h> -#include <stdio.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include <ostream> -#include <string> -#include <vector> - -#include "common/dwarf/bytereader-inl.h" -#include "common/dwarf/dwarf2reader.h" -#include "common/dwarf_cfi_to_module.h" -#include "common/dwarf_cu_to_module.h" -#include "common/dwarf_line_to_module.h" -#include "common/mac/file_id.h" -#include "common/mac/arch_utilities.h" -#include "common/mac/macho_reader.h" -#include "common/module.h" -#include "common/scoped_ptr.h" -#include "common/stabs_reader.h" -#include "common/stabs_to_module.h" -#include "common/symbol_data.h" - -#ifndef CPU_TYPE_ARM -#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12)) -#endif // CPU_TYPE_ARM - -#ifndef CPU_TYPE_ARM64 -#define CPU_TYPE_ARM64 (static_cast<cpu_type_t>(16777228)) -#endif // CPU_TYPE_ARM64 - -using dwarf2reader::ByteReader; -using google_breakpad::DwarfCUToModule; -using google_breakpad::DwarfLineToModule; -using google_breakpad::FileID; -using google_breakpad::mach_o::FatReader; -using google_breakpad::mach_o::Section; -using google_breakpad::mach_o::Segment; -using google_breakpad::Module; -using google_breakpad::StabsReader; -using google_breakpad::StabsToModule; -using google_breakpad::scoped_ptr; -using std::make_pair; -using std::pair; -using std::string; -using std::vector; - -namespace { -// Return a vector<string> with absolute paths to all the entries -// in directory (excluding . and ..). -vector<string> list_directory(const string& directory) { - vector<string> entries; - DIR* dir = opendir(directory.c_str()); - if (!dir) { - return entries; - } - - string path = directory; - if (path[path.length() - 1] != '/') { - path += '/'; - } - - struct dirent* entry = NULL; - while ((entry = readdir(dir))) { - if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { - entries.push_back(path + entry->d_name); - } - } - - closedir(dir); - return entries; -} -} - -namespace google_breakpad { - -bool DumpSymbols::Read(const string &filename) { - struct stat st; - if (stat(filename.c_str(), &st) == -1) { - fprintf(stderr, "Could not access object file %s: %s\n", - filename.c_str(), strerror(errno)); - return false; - } - - input_pathname_ = filename; - - // Does this filename refer to a dSYM bundle? - string contents_path = input_pathname_ + "/Contents/Resources/DWARF"; - if (S_ISDIR(st.st_mode) && - access(contents_path.c_str(), F_OK) == 0) { - // If there's one file under Contents/Resources/DWARF then use that, - // otherwise bail out. - const vector<string> entries = list_directory(contents_path); - if (entries.size() == 0) { - fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n", - input_pathname_.c_str()); - return false; - } - if (entries.size() > 1) { - fprintf(stderr, "Too many DWARF files in bundle: %s\n", - input_pathname_.c_str()); - return false; - } - - object_filename_ = entries[0]; - } else { - object_filename_ = input_pathname_; - } - - // Read the file's contents into memory. - bool read_ok = true; - string error; - if (stat(object_filename_.c_str(), &st) != -1) { - FILE* f = fopen(object_filename_.c_str(), "rb"); - if (f) { - contents_.reset(new uint8_t[st.st_size]); - off_t total = 0; - while (total < st.st_size && !feof(f)) { - size_t read = fread(&contents_[0] + total, 1, st.st_size - total, f); - if (read == 0) { - if (ferror(f)) { - read_ok = false; - error = strerror(errno); - } - break; - } - total += read; - } - fclose(f); - } else { - error = strerror(errno); - } - } - - if (!read_ok) { - fprintf(stderr, "Error reading object file: %s: %s\n", - object_filename_.c_str(), - error.c_str()); - return false; - } - - // Get the list of object files present in the file. - FatReader::Reporter fat_reporter(object_filename_); - FatReader fat_reader(&fat_reporter); - if (!fat_reader.Read(&contents_[0], - st.st_size)) { - return false; - } - - // Get our own copy of fat_reader's object file list. - size_t object_files_count; - const SuperFatArch *object_files = - fat_reader.object_files(&object_files_count); - if (object_files_count == 0) { - fprintf(stderr, "Fat binary file contains *no* architectures: %s\n", - object_filename_.c_str()); - return false; - } - object_files_.resize(object_files_count); - memcpy(&object_files_[0], object_files, - sizeof(SuperFatArch) * object_files_count); - - return true; -} - -bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype) { - // Find the best match for the architecture the user requested. - const SuperFatArch *best_match = FindBestMatchForArchitecture( - cpu_type, cpu_subtype); - if (!best_match) return false; - - // Record the selected object file. - selected_object_file_ = best_match; - return true; -} - -bool DumpSymbols::SetArchitecture(const std::string &arch_name) { - bool arch_set = false; - const NXArchInfo *arch_info = - google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str()); - if (arch_info) { - arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype); - } - return arch_set; -} - -SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( - cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { - // Check if all the object files can be converted to struct fat_arch. - bool can_convert_to_fat_arch = true; - vector<struct fat_arch> fat_arch_vector; - for (vector<SuperFatArch>::const_iterator it = object_files_.begin(); - it != object_files_.end(); - ++it) { - struct fat_arch arch; - bool success = it->ConvertToFatArch(&arch); - if (!success) { - can_convert_to_fat_arch = false; - break; - } - fat_arch_vector.push_back(arch); - } - - // If all the object files can be converted to struct fat_arch, use - // NXFindBestFatArch. - if (can_convert_to_fat_arch) { - const struct fat_arch *best_match - = NXFindBestFatArch(cpu_type, cpu_subtype, &fat_arch_vector[0], - static_cast<uint32_t>(fat_arch_vector.size())); - - for (size_t i = 0; i < fat_arch_vector.size(); ++i) { - if (best_match == &fat_arch_vector[i]) - return &object_files_[i]; - } - assert(best_match == NULL); - return NULL; - } - - // Check for an exact match with cpu_type and cpu_subtype. - for (vector<SuperFatArch>::iterator it = object_files_.begin(); - it != object_files_.end(); - ++it) { - if (static_cast<cpu_type_t>(it->cputype) == cpu_type && - static_cast<cpu_subtype_t>(it->cpusubtype) == cpu_subtype) - return &*it; - } - - // No exact match found. - // TODO(erikchen): If it becomes necessary, we can copy the implementation of - // NXFindBestFatArch, located at - // http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c. - fprintf(stderr, "Failed to find an exact match for an object file with cpu " - "type: %d and cpu subtype: %d. Furthermore, at least one object file is " - "larger than 2**32.\n", cpu_type, cpu_subtype); - return NULL; -} - -string DumpSymbols::Identifier() { - FileID file_id(object_filename_.c_str()); - unsigned char identifier_bytes[16]; - cpu_type_t cpu_type = selected_object_file_->cputype; - cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype; - if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) { - fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n", - object_filename_.c_str()); - return ""; - } - - char identifier_string[40]; - FileID::ConvertIdentifierToString(identifier_bytes, identifier_string, - sizeof(identifier_string)); - - string compacted(identifier_string); - for(size_t i = compacted.find('-'); i != string::npos; - i = compacted.find('-', i)) - compacted.erase(i, 1); - - return compacted; -} - -// A line-to-module loader that accepts line number info parsed by -// dwarf2reader::LineInfo and populates a Module and a line vector -// with the results. -class DumpSymbols::DumperLineToModule: - public DwarfCUToModule::LineToModuleHandler { - public: - // Create a line-to-module converter using BYTE_READER. - DumperLineToModule(dwarf2reader::ByteReader *byte_reader) - : byte_reader_(byte_reader) { } - - void StartCompilationUnit(const string& compilation_dir) { - compilation_dir_ = compilation_dir; - } - - void ReadProgram(const uint8_t *program, uint64 length, - Module *module, vector<Module::Line> *lines) { - DwarfLineToModule handler(module, compilation_dir_, lines); - dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler); - parser.Start(); - } - private: - string compilation_dir_; - dwarf2reader::ByteReader *byte_reader_; // WEAK -}; - -bool DumpSymbols::CreateEmptyModule(scoped_ptr<Module>& module) { - // Select an object file, if SetArchitecture hasn't been called to set one - // explicitly. - if (!selected_object_file_) { - // If there's only one architecture, that's the one. - if (object_files_.size() == 1) - selected_object_file_ = &object_files_[0]; - else { - // Look for an object file whose architecture matches our own. - const NXArchInfo *local_arch = NXGetLocalArchInfo(); - if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) { - fprintf(stderr, "%s: object file contains more than one" - " architecture, none of which match the current" - " architecture; specify an architecture explicitly" - " with '-a ARCH' to resolve the ambiguity\n", - object_filename_.c_str()); - return false; - } - } - } - - assert(selected_object_file_); - - // Find the name of the selected file's architecture, to appear in - // the MODULE record and in error messages. - const NXArchInfo *selected_arch_info = - google_breakpad::BreakpadGetArchInfoFromCpuType( - selected_object_file_->cputype, selected_object_file_->cpusubtype); - - const char *selected_arch_name = selected_arch_info->name; - if (strcmp(selected_arch_name, "i386") == 0) - selected_arch_name = "x86"; - - // Produce a name to use in error messages that includes the - // filename, and the architecture, if there is more than one. - selected_object_name_ = object_filename_; - if (object_files_.size() > 1) { - selected_object_name_ += ", architecture "; - selected_object_name_ + selected_arch_name; - } - - // Compute a module name, to appear in the MODULE record. - string module_name = object_filename_; - module_name = basename(&module_name[0]); - - // Choose an identifier string, to appear in the MODULE record. - string identifier = Identifier(); - if (identifier.empty()) - return false; - identifier += "0"; - - // Create a module to hold the debugging information. - module.reset(new Module(module_name, - "mac", - selected_arch_name, - identifier)); - return true; -} - -bool DumpSymbols::ReadDwarf(google_breakpad::Module *module, - const mach_o::Reader &macho_reader, - const mach_o::SectionMap &dwarf_sections, - bool handle_inter_cu_refs) const { - // Build a byte reader of the appropriate endianness. - ByteReader byte_reader(macho_reader.big_endian() - ? dwarf2reader::ENDIANNESS_BIG - : dwarf2reader::ENDIANNESS_LITTLE); - - // Construct a context for this file. - DwarfCUToModule::FileContext file_context(selected_object_name_, - module, - handle_inter_cu_refs); - - // Build a dwarf2reader::SectionMap from our mach_o::SectionMap. - for (mach_o::SectionMap::const_iterator it = dwarf_sections.begin(); - it != dwarf_sections.end(); ++it) { - file_context.AddSectionToSectionMap( - it->first, - it->second.contents.start, - it->second.contents.Size()); - } - - // Find the __debug_info section. - dwarf2reader::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>& debug_info_section = - debug_info_entry->second; - // There had better be a __debug_info section! - if (!debug_info_section.first) { - fprintf(stderr, "%s: __DWARF segment of file has no __debug_info section\n", - selected_object_name_.c_str()); - return false; - } - - // Build a line-to-module loader for the root handler to use. - DumperLineToModule line_to_module(&byte_reader); - - // Walk the __debug_info section, one compilation unit at a time. - uint64 debug_info_length = debug_info_section.second; - for (uint64 offset = 0; offset < debug_info_length;) { - // Make a handler for the root DIE that populates MODULE with the - // debug info. - DwarfCUToModule::WarningReporter reporter(selected_object_name_, - offset); - DwarfCUToModule root_handler(&file_context, &line_to_module, &reporter); - // Make a Dwarf2Handler that drives our DIEHandler. - dwarf2reader::DIEDispatcher die_dispatcher(&root_handler); - // Make a DWARF parser for the compilation unit at OFFSET. - dwarf2reader::CompilationUnit dwarf_reader(selected_object_name_, - file_context.section_map(), - offset, - &byte_reader, - &die_dispatcher); - // Process the entire compilation unit; get the offset of the next. - offset += dwarf_reader.Start(); - } - - return true; -} - -bool DumpSymbols::ReadCFI(google_breakpad::Module *module, - const mach_o::Reader &macho_reader, - const mach_o::Section §ion, - bool eh_frame) const { - // Find the appropriate set of register names for this file's - // architecture. - vector<string> register_names; - switch (macho_reader.cpu_type()) { - case CPU_TYPE_X86: - register_names = DwarfCFIToModule::RegisterNames::I386(); - break; - case CPU_TYPE_X86_64: - register_names = DwarfCFIToModule::RegisterNames::X86_64(); - break; - case CPU_TYPE_ARM: - register_names = DwarfCFIToModule::RegisterNames::ARM(); - break; - case CPU_TYPE_ARM64: - register_names = DwarfCFIToModule::RegisterNames::ARM64(); - break; - default: { - const NXArchInfo *arch = google_breakpad::BreakpadGetArchInfoFromCpuType( - macho_reader.cpu_type(), macho_reader.cpu_subtype()); - fprintf(stderr, "%s: cannot convert DWARF call frame information for ", - selected_object_name_.c_str()); - if (arch) - fprintf(stderr, "architecture '%s'", arch->name); - else - fprintf(stderr, "architecture %d,%d", - macho_reader.cpu_type(), macho_reader.cpu_subtype()); - fprintf(stderr, " to Breakpad symbol file: no register name table\n"); - return false; - } - } - - // Find the call frame information and its size. - const uint8_t *cfi = section.contents.start; - size_t cfi_size = section.contents.Size(); - - // Plug together the parser, handler, and their entourages. - DwarfCFIToModule::Reporter module_reporter(selected_object_name_, - section.section_name); - DwarfCFIToModule handler(module, register_names, &module_reporter); - dwarf2reader::ByteReader byte_reader(macho_reader.big_endian() ? - dwarf2reader::ENDIANNESS_BIG : - dwarf2reader::ENDIANNESS_LITTLE); - byte_reader.SetAddressSize(macho_reader.bits_64() ? 8 : 4); - // At the moment, according to folks at Apple and some cursory - // investigation, Mac OS X only uses DW_EH_PE_pcrel-based pointers, so - // this is the only base address the CFI parser will need. - byte_reader.SetCFIDataBase(section.address, cfi); - - dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(selected_object_name_, - section.section_name); - dwarf2reader::CallFrameInfo parser(cfi, cfi_size, - &byte_reader, &handler, &dwarf_reporter, - eh_frame); - parser.Start(); - return true; -} - -// A LoadCommandHandler that loads whatever debugging data it finds into a -// Module. -class DumpSymbols::LoadCommandDumper: - public mach_o::Reader::LoadCommandHandler { - public: - // Create a load command dumper handling load commands from READER's - // file, and adding data to MODULE. - LoadCommandDumper(const DumpSymbols &dumper, - google_breakpad::Module *module, - const mach_o::Reader &reader, - SymbolData symbol_data, - bool handle_inter_cu_refs) - : dumper_(dumper), - module_(module), - reader_(reader), - symbol_data_(symbol_data), - handle_inter_cu_refs_(handle_inter_cu_refs) { } - - bool SegmentCommand(const mach_o::Segment &segment); - bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings); - - private: - const DumpSymbols &dumper_; - google_breakpad::Module *module_; // WEAK - const mach_o::Reader &reader_; - const SymbolData symbol_data_; - const bool handle_inter_cu_refs_; -}; - -bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) { - mach_o::SectionMap section_map; - if (!reader_.MapSegmentSections(segment, §ion_map)) - return false; - - if (segment.name == "__TEXT") { - module_->SetLoadAddress(segment.vmaddr); - if (symbol_data_ != NO_CFI) { - mach_o::SectionMap::const_iterator eh_frame = - section_map.find("__eh_frame"); - if (eh_frame != section_map.end()) { - // If there is a problem reading this, don't treat it as a fatal error. - dumper_.ReadCFI(module_, reader_, eh_frame->second, true); - } - } - return true; - } - - if (segment.name == "__DWARF") { - if (symbol_data_ != ONLY_CFI) { - if (!dumper_.ReadDwarf(module_, reader_, section_map, - handle_inter_cu_refs_)) { - return false; - } - } - if (symbol_data_ != NO_CFI) { - mach_o::SectionMap::const_iterator debug_frame - = section_map.find("__debug_frame"); - if (debug_frame != section_map.end()) { - // If there is a problem reading this, don't treat it as a fatal error. - dumper_.ReadCFI(module_, reader_, debug_frame->second, false); - } - } - } - - return true; -} - -bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries, - const ByteBuffer &strings) { - StabsToModule stabs_to_module(module_); - // Mac OS X STABS are never "unitized", and the size of the 'value' field - // matches the address size of the executable. - StabsReader stabs_reader(entries.start, entries.Size(), - strings.start, strings.Size(), - reader_.big_endian(), - reader_.bits_64() ? 8 : 4, - true, - &stabs_to_module); - if (!stabs_reader.Process()) - return false; - stabs_to_module.Finalize(); - return true; -} - -bool DumpSymbols::ReadSymbolData(Module** out_module) { - scoped_ptr<Module> module; - if (!CreateEmptyModule(module)) - return false; - - // Parse the selected object file. - mach_o::Reader::Reporter reporter(selected_object_name_); - mach_o::Reader reader(&reporter); - if (!reader.Read(&contents_[0] - + selected_object_file_->offset, - selected_object_file_->size, - selected_object_file_->cputype, - selected_object_file_->cpusubtype)) - return false; - - // Walk its load commands, and deal with whatever is there. - LoadCommandDumper load_command_dumper(*this, module.get(), reader, - symbol_data_, handle_inter_cu_refs_); - if (!reader.WalkLoadCommands(&load_command_dumper)) - return false; - - *out_module = module.release(); - - return true; -} - -bool DumpSymbols::WriteSymbolFile(std::ostream &stream) { - Module* module = NULL; - - if (ReadSymbolData(&module) && module) { - bool res = module->Write(stream, symbol_data_); - delete module; - return res; - } - - return false; -} - -// 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 DumpSymbols::WriteSymbolFileHeader(std::ostream &stream) { - scoped_ptr<Module> module; - if (!CreateEmptyModule(module)) - return false; - - return module->Write(stream, symbol_data_); -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.h b/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.h deleted file mode 100644 index 9463f7dc0..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/dump_syms.h +++ /dev/null @@ -1,196 +0,0 @@ -// -*- 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. - -// Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dump_syms.h: Declaration of google_breakpad::DumpSymbols, a class for -// reading debugging information from Mach-O files and writing it out as a -// Breakpad symbol file. - -#include <mach-o/loader.h> -#include <stdio.h> -#include <stdlib.h> - -#include <ostream> -#include <string> -#include <vector> - -#include "common/byte_cursor.h" -#include "common/mac/macho_reader.h" -#include "common/mac/super_fat_arch.h" -#include "common/module.h" -#include "common/scoped_ptr.h" -#include "common/symbol_data.h" - -namespace google_breakpad { - -class DumpSymbols { - public: - DumpSymbols(SymbolData symbol_data, bool handle_inter_cu_refs) - : symbol_data_(symbol_data), - handle_inter_cu_refs_(handle_inter_cu_refs), - input_pathname_(), - object_filename_(), - contents_(), - object_files_(), - selected_object_file_(), - selected_object_name_() { } - ~DumpSymbols() { - } - - // Prepare to read debugging information from |filename|. |filename| may be - // the name of a universal binary, a Mach-O file, or a dSYM bundle - // containing either of the above. On success, return true; if there is a - // problem reading |filename|, report it and return false. - bool Read(const std::string &filename); - - // If this dumper's file includes an object file for |cpu_type| and - // |cpu_subtype|, then select that object file for dumping, and return - // true. Otherwise, return false, and leave this dumper's selected - // architecture unchanged. - // - // By default, if this dumper's file contains only one object file, then - // the dumper will dump those symbols; and if it contains more than one - // object file, then the dumper will dump the object file whose - // architecture matches that of this dumper program. - bool SetArchitecture(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); - - // If this dumper's file includes an object file for |arch_name|, then select - // that object file for dumping, and return true. Otherwise, return false, - // and leave this dumper's selected architecture unchanged. - // - // By default, if this dumper's file contains only one object file, then - // the dumper will dump those symbols; and if it contains more than one - // object file, then the dumper will dump the object file whose - // architecture matches that of this dumper program. - bool SetArchitecture(const std::string &arch_name); - - // Return a pointer to an array of SuperFatArch structures describing the - // object files contained in this dumper's file. Set *|count| to the number - // of elements in the array. The returned array is owned by this DumpSymbols - // instance. - // - // If there are no available architectures, this function - // may return NULL. - const SuperFatArch* AvailableArchitectures(size_t *count) { - *count = object_files_.size(); - if (object_files_.size() > 0) - return &object_files_[0]; - return NULL; - } - - // Read the selected object file's debugging information, and write it out to - // |stream|. Return true on success; if an error occurs, report it and - // return false. - bool WriteSymbolFile(std::ostream &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. - bool WriteSymbolFileHeader(std::ostream &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(Module** module); - - private: - // Used internally. - class DumperLineToModule; - class LoadCommandDumper; - - // This method behaves similarly to NXFindBestFatArch, but it supports - // SuperFatArch. - SuperFatArch* FindBestMatchForArchitecture( - cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); - - // Return an identifier string for the file this DumpSymbols is dumping. - std::string Identifier(); - - - // Creates an empty module object. - bool CreateEmptyModule(scoped_ptr<Module>& module); - - // Read debugging information from |dwarf_sections|, which was taken from - // |macho_reader|, and add it to |module|. On success, return true; - // on failure, report the problem and return false. - bool ReadDwarf(google_breakpad::Module *module, - const mach_o::Reader &macho_reader, - const mach_o::SectionMap &dwarf_sections, - bool handle_inter_cu_refs) const; - - // Read DWARF CFI or .eh_frame data from |section|, belonging to - // |macho_reader|, and record it in |module|. If |eh_frame| is true, - // then the data is .eh_frame-format data; otherwise, it is standard DWARF - // .debug_frame data. On success, return true; on failure, report - // the problem and return false. - bool ReadCFI(google_breakpad::Module *module, - const mach_o::Reader &macho_reader, - const mach_o::Section §ion, - bool eh_frame) const; - - // The selection of what type of symbol data to read/write. - const SymbolData symbol_data_; - - // Whether to handle references between compilation units. - const bool handle_inter_cu_refs_; - - // The name of the file or bundle whose symbols this will dump. - // This is the path given to Read, for use in error messages. - std::string input_pathname_; - - // The name of the file this DumpSymbols will actually read debugging - // information from. Normally, this is the same as input_pathname_, but if - // filename refers to a dSYM bundle, then this is the resource file - // within that bundle. - std::string object_filename_; - - // The complete contents of object_filename_, mapped into memory. - scoped_array<uint8_t> contents_; - - // A vector of SuperFatArch structures describing the object files - // object_filename_ contains. If object_filename_ refers to a fat binary, - // this may have more than one element; if it refers to a Mach-O file, this - // has exactly one element. - vector<SuperFatArch> object_files_; - - // The object file in object_files_ selected to dump, or NULL if - // SetArchitecture hasn't been called yet. - const SuperFatArch *selected_object_file_; - - // A string that identifies the selected object file, for use in error - // messages. This is usually object_filename_, but if that refers to a - // fat binary, it includes an indication of the particular architecture - // within that binary. - string selected_object_name_; -}; - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.cc deleted file mode 100644 index 4661d5d62..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.cc +++ /dev/null @@ -1,106 +0,0 @@ -// 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 -// -// Author: Dan Waylonis - -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#include "common/mac/file_id.h" -#include "common/mac/macho_id.h" - -using MacFileUtilities::MachoID; - -namespace google_breakpad { - -FileID::FileID(const char *path) { - snprintf(path_, sizeof(path_), "%s", path); -} - -bool FileID::FileIdentifier(unsigned char identifier[16]) { - int fd = open(path_, O_RDONLY); - if (fd == -1) - return false; - - MD5Context md5; - MD5Init(&md5); - - // Read 4k x 2 bytes at a time. This is faster than just 4k bytes, but - // doesn't seem to be an unreasonable size for the stack. - unsigned char buffer[4096 * 2]; - size_t buffer_size = sizeof(buffer); - while ((buffer_size = read(fd, buffer, buffer_size) > 0)) { - MD5Update(&md5, buffer, static_cast<unsigned>(buffer_size)); - } - - close(fd); - MD5Final(identifier, &md5); - - return true; -} - -bool FileID::MachoIdentifier(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - unsigned char identifier[16]) { - MachoID macho(path_); - - if (macho.UUIDCommand(cpu_type, cpu_subtype, identifier)) - return true; - - return macho.MD5(cpu_type, cpu_subtype, identifier); -} - -// static -void FileID::ConvertIdentifierToString(const unsigned char identifier[16], - char *buffer, int buffer_length) { - int buffer_idx = 0; - for (int idx = 0; (buffer_idx < buffer_length) && (idx < 16); ++idx) { - int hi = (identifier[idx] >> 4) & 0x0F; - int lo = (identifier[idx]) & 0x0F; - - if (idx == 4 || idx == 6 || idx == 8 || idx == 10) - buffer[buffer_idx++] = '-'; - - buffer[buffer_idx++] = - static_cast<char>((hi >= 10) ? ('A' + hi - 10) : ('0' + hi)); - buffer[buffer_idx++] = - static_cast<char>((lo >= 10) ? ('A' + lo - 10) : ('0' + lo)); - } - - // NULL terminate - buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.h b/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.h deleted file mode 100644 index 1d6dfde1b..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/file_id.h +++ /dev/null @@ -1,81 +0,0 @@ -// 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 -// -// Author: Dan Waylonis - -#ifndef COMMON_MAC_FILE_ID_H__ -#define COMMON_MAC_FILE_ID_H__ - -#include <limits.h> -#include <mach/machine.h> - -namespace google_breakpad { - -class FileID { - public: - FileID(const char *path); - ~FileID() {}; - - // Load the identifier for the file path specified in the constructor into - // |identifier|. Return false if the identifier could not be created for the - // file. - // The current implementation will return the MD5 hash of the file's bytes. - bool FileIdentifier(unsigned char identifier[16]); - - // Treat the file as a mach-o file that will contain one or more archicture. - // Accepted values for |cpu_type| and |cpu_subtype| (e.g., CPU_TYPE_X86 or - // CPU_TYPE_POWERPC) are listed in /usr/include/mach/machine.h. - // If |cpu_type| is 0, then the native cpu type is used. If |cpu_subtype| is - // CPU_SUBTYPE_MULTIPLE, the match is only done on |cpu_type|. - // Returns false if opening the file failed or if the |cpu_type|/|cpu_subtype| - // is not present in the file. - // Return the unique identifier in |identifier|. - // The current implementation will look for the (in order of priority): - // LC_UUID, LC_ID_DYLIB, or MD5 hash of the given |cpu_type|. - bool MachoIdentifier(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - unsigned char identifier[16]); - - // Convert the |identifier| data to a NULL terminated string. The string will - // be formatted as a UUID (e.g., 22F065BB-FC9C-49F7-80FE-26A7CEBD7BCE). - // The |buffer| should be at least 37 bytes long to receive all of the data - // and termination. Shorter buffers will contain truncated data. - static void ConvertIdentifierToString(const unsigned char identifier[16], - char *buffer, int buffer_length); - - private: - // Storage for the path specified - char path_[PATH_MAX]; -}; - -} // namespace google_breakpad - -#endif // COMMON_MAC_FILE_ID_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.cc deleted file mode 100644 index 245be8265..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.cc +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 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 <stdio.h> -#include <sys/wait.h> -#include <unistd.h> - -namespace google_breakpad { - -void LaunchReporter(const char *reporter_executable_path, - const char *config_file_path) { - const char* argv[] = { reporter_executable_path, config_file_path, NULL }; - - // Launch the reporter - pid_t pid = fork(); - - if (pid == -1) { - perror("fork"); - fprintf(stderr, "Failed to fork reporter process\n"); - return; - } - - // If we're in the child, load in our new executable and run. - // The parent will not wait for the child to complete. - if (pid == 0) { - execv(argv[0], (char* const*)argv); - perror("exec"); - fprintf(stderr, - "Failed to launch reporter process from path %s\n", - reporter_executable_path); - unlink(config_file_path); // launch failed - get rid of config file - _exit(1); - } - - // Wait until the Reporter child process exits. - // - - // We'll use a timeout of one minute. - int timeout_count = 60; // 60 seconds - - while (timeout_count-- > 0) { - int status; - pid_t result = waitpid(pid, &status, WNOHANG); - - if (result == 0) { - // The child has not yet finished. - sleep(1); - } else if (result == -1) { - // error occurred. - break; - } else { - // child has finished - break; - } - } -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.h b/toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.h deleted file mode 100644 index 4531123c2..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/launch_reporter.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 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_MAC_LAUNCH_REPORTER_H__ -#define COMMON_MAC_LAUNCH_REPORTER_H__ - -namespace google_breakpad { - -// Launch the crash dump sender app. -// |reporter_executable_path| is the path to the sender executable. -// |config_file_path| is the path to the config file. -void LaunchReporter(const char *reporter_executable_path, - const char *config_file_path); - -} // namespace google_breakpad - -#endif // COMMON_MAC_LAUNCH_REPORTER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.cc deleted file mode 100644 index c396ad888..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.cc +++ /dev/null @@ -1,369 +0,0 @@ -// 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. - -// macho_id.cc: Functions to gather identifying information from a macho file -// -// See macho_id.h for documentation -// -// Author: Dan Waylonis - - -#include <fcntl.h> -#include <mach-o/loader.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/time.h> -#include <sys/types.h> -#include <unistd.h> - -#include "common/mac/macho_id.h" -#include "common/mac/macho_walker.h" -#include "common/mac/macho_utilities.h" - -namespace MacFileUtilities { - -using google_breakpad::MD5Init; -using google_breakpad::MD5Update; -using google_breakpad::MD5Final; - -MachoID::MachoID(const char *path) - : memory_(0), - memory_size_(0), - crc_(0), - md5_context_(), - update_function_(NULL) { - snprintf(path_, sizeof(path_), "%s", path); -} - -MachoID::MachoID(const char *path, void *memory, size_t size) - : memory_(memory), - memory_size_(size), - crc_(0), - md5_context_(), - update_function_(NULL) { - snprintf(path_, sizeof(path_), "%s", path); -} - -MachoID::~MachoID() { -} - -// The CRC info is from http://en.wikipedia.org/wiki/Adler-32 -// With optimizations from http://www.zlib.net/ - -// The largest prime smaller than 65536 -#define MOD_ADLER 65521 -// MAX_BLOCK is the largest n such that 255n(n+1)/2 + (n+1)(MAX_BLOCK-1) <= 2^32-1 -#define MAX_BLOCK 5552 - -void MachoID::UpdateCRC(unsigned char *bytes, size_t size) { -// Unrolled loops for summing -#define DO1(buf,i) {sum1 += (buf)[i]; sum2 += sum1;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - // Split up the crc - uint32_t sum1 = crc_ & 0xFFFF; - uint32_t sum2 = (crc_ >> 16) & 0xFFFF; - - // Do large blocks - while (size >= MAX_BLOCK) { - size -= MAX_BLOCK; - int block_count = MAX_BLOCK / 16; - do { - DO16(bytes); - bytes += 16; - } while (--block_count); - sum1 %= MOD_ADLER; - sum2 %= MOD_ADLER; - } - - // Do remaining bytes - if (size) { - while (size >= 16) { - size -= 16; - DO16(bytes); - bytes += 16; - } - while (size--) { - sum1 += *bytes++; - sum2 += sum1; - } - sum1 %= MOD_ADLER; - sum2 %= MOD_ADLER; - crc_ = (sum2 << 16) | sum1; - } -} - -void MachoID::UpdateMD5(unsigned char *bytes, size_t size) { - MD5Update(&md5_context_, bytes, static_cast<unsigned>(size)); -} - -void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) { - if (!update_function_ || !size) - return; - - // Read up to 4k bytes at a time - unsigned char buffer[4096]; - size_t buffer_size; - off_t file_offset = offset; - while (size > 0) { - if (size > sizeof(buffer)) { - buffer_size = sizeof(buffer); - size -= buffer_size; - } else { - buffer_size = size; - size = 0; - } - - if (!walker->ReadBytes(buffer, buffer_size, file_offset)) - return; - - (this->*update_function_)(buffer, buffer_size); - file_offset += buffer_size; - } -} - -bool MachoID::UUIDCommand(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - unsigned char bytes[16]) { - struct breakpad_uuid_command uuid_cmd; - uuid_cmd.cmd = 0; - if (!WalkHeader(cpu_type, cpu_subtype, UUIDWalkerCB, &uuid_cmd)) - return false; - - // If we found the command, we'll have initialized the uuid_command - // structure - if (uuid_cmd.cmd == LC_UUID) { - memcpy(bytes, uuid_cmd.uuid, sizeof(uuid_cmd.uuid)); - return true; - } - - return false; -} - -bool MachoID::IDCommand(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - unsigned char identifier[16]) { - struct dylib_command dylib_cmd; - dylib_cmd.cmd = 0; - if (!WalkHeader(cpu_type, cpu_subtype, IDWalkerCB, &dylib_cmd)) - return false; - - // If we found the command, we'll have initialized the dylib_command - // structure - if (dylib_cmd.cmd == LC_ID_DYLIB) { - // Take the hashed filename, version, and compatability version bytes - // to form the first 12 bytes, pad the rest with zeros - - // create a crude hash of the filename to generate the first 4 bytes - identifier[0] = 0; - identifier[1] = 0; - identifier[2] = 0; - identifier[3] = 0; - - for (int j = 0, i = (int)strlen(path_)-1; i>=0 && path_[i]!='/'; ++j, --i) { - identifier[j%4] += path_[i]; - } - - identifier[4] = (dylib_cmd.dylib.current_version >> 24) & 0xFF; - identifier[5] = (dylib_cmd.dylib.current_version >> 16) & 0xFF; - identifier[6] = (dylib_cmd.dylib.current_version >> 8) & 0xFF; - identifier[7] = dylib_cmd.dylib.current_version & 0xFF; - identifier[8] = (dylib_cmd.dylib.compatibility_version >> 24) & 0xFF; - identifier[9] = (dylib_cmd.dylib.compatibility_version >> 16) & 0xFF; - identifier[10] = (dylib_cmd.dylib.compatibility_version >> 8) & 0xFF; - identifier[11] = dylib_cmd.dylib.compatibility_version & 0xFF; - identifier[12] = (cpu_type >> 24) & 0xFF; - identifier[13] = (cpu_type >> 16) & 0xFF; - identifier[14] = (cpu_type >> 8) & 0xFF; - identifier[15] = cpu_type & 0xFF; - - return true; - } - - return false; -} - -uint32_t MachoID::Adler32(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { - update_function_ = &MachoID::UpdateCRC; - crc_ = 0; - - if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this)) - return 0; - - return crc_; -} - -bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) { - update_function_ = &MachoID::UpdateMD5; - - MD5Init(&md5_context_); - - if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this)) - return false; - - MD5Final(identifier, &md5_context_); - return true; -} - -bool MachoID::WalkHeader(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - MachoWalker::LoadCommandCallback callback, - void *context) { - if (memory_) { - MachoWalker walker(memory_, memory_size_, callback, context); - return walker.WalkHeader(cpu_type, cpu_subtype); - } else { - MachoWalker walker(path_, callback, context); - return walker.WalkHeader(cpu_type, cpu_subtype); - } -} - -// static -bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, - bool swap, void *context) { - MachoID *macho_id = (MachoID *)context; - - if (cmd->cmd == LC_SEGMENT) { - struct segment_command seg; - - if (!walker->ReadBytes(&seg, sizeof(seg), offset)) - return false; - - if (swap) - breakpad_swap_segment_command(&seg); - - struct mach_header_64 header; - off_t header_offset; - - if (!walker->CurrentHeader(&header, &header_offset)) - return false; - - // Process segments that have sections: - // (e.g., __TEXT, __DATA, __IMPORT, __OBJC) - offset += sizeof(struct segment_command); - struct section sec; - for (unsigned long i = 0; i < seg.nsects; ++i) { - if (!walker->ReadBytes(&sec, sizeof(sec), offset)) - return false; - - if (swap) - breakpad_swap_section(&sec, 1); - - // sections of type S_ZEROFILL are "virtual" and contain no data - // in the file itself - if ((sec.flags & SECTION_TYPE) != S_ZEROFILL && sec.offset != 0) - macho_id->Update(walker, header_offset + sec.offset, sec.size); - - offset += sizeof(struct section); - } - } else if (cmd->cmd == LC_SEGMENT_64) { - struct segment_command_64 seg64; - - if (!walker->ReadBytes(&seg64, sizeof(seg64), offset)) - return false; - - if (swap) - breakpad_swap_segment_command_64(&seg64); - - struct mach_header_64 header; - off_t header_offset; - - if (!walker->CurrentHeader(&header, &header_offset)) - return false; - - // Process segments that have sections: - // (e.g., __TEXT, __DATA, __IMPORT, __OBJC) - offset += sizeof(struct segment_command_64); - struct section_64 sec64; - for (unsigned long i = 0; i < seg64.nsects; ++i) { - if (!walker->ReadBytes(&sec64, sizeof(sec64), offset)) - return false; - - if (swap) - breakpad_swap_section_64(&sec64, 1); - - // sections of type S_ZEROFILL are "virtual" and contain no data - // in the file itself - if ((sec64.flags & SECTION_TYPE) != S_ZEROFILL && sec64.offset != 0) - macho_id->Update(walker, - header_offset + sec64.offset, - (size_t)sec64.size); - - offset += sizeof(struct section_64); - } - } - - // Continue processing - return true; -} - -// static -bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, - bool swap, void *context) { - if (cmd->cmd == LC_UUID) { - struct breakpad_uuid_command *uuid_cmd = - (struct breakpad_uuid_command *)context; - - if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command), - offset)) - return false; - - if (swap) - breakpad_swap_uuid_command(uuid_cmd); - - return false; - } - - // Continue processing - return true; -} - -// static -bool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, - bool swap, void *context) { - if (cmd->cmd == LC_ID_DYLIB) { - struct dylib_command *dylib_cmd = (struct dylib_command *)context; - - if (!walker->ReadBytes(dylib_cmd, sizeof(struct dylib_command), offset)) - return false; - - if (swap) - breakpad_swap_dylib_command(dylib_cmd); - - return false; - } - - // Continue processing - return true; -} - -} // namespace MacFileUtilities diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.h b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.h deleted file mode 100644 index 103754912..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_id.h +++ /dev/null @@ -1,131 +0,0 @@ -// 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. - -// macho_id.h: Functions to gather identifying information from a macho file -// -// Author: Dan Waylonis - -#ifndef COMMON_MAC_MACHO_ID_H__ -#define COMMON_MAC_MACHO_ID_H__ - -#include <limits.h> -#include <mach/machine.h> -#include <mach-o/loader.h> - -#include "common/mac/macho_walker.h" -#include "common/md5.h" - -namespace MacFileUtilities { - -class MachoID { - public: - MachoID(const char *path); - MachoID(const char *path, void *memory, size_t size); - ~MachoID(); - - // For the given |cpu_type| and |cpu_subtype|, return a UUID from the LC_UUID - // command. - // Return false if there isn't a LC_UUID command. - bool UUIDCommand(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - unsigned char identifier[16]); - - // For the given |cpu_type| and |cpu_subtype|, return a UUID from the - // LC_ID_DYLIB command. - // Return false if there isn't a LC_ID_DYLIB command. - bool IDCommand(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - unsigned char identifier[16]); - - // For the given |cpu_type| and |cpu_subtype|, return the Adler32 CRC for the - // mach-o data segment(s). - // Return 0 on error (e.g., if the file is not a mach-o file) - uint32_t Adler32(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype); - - // For the given |cpu_type|, and |cpu_subtype| return the MD5 for the mach-o - // data segment(s). - // Return true on success, false otherwise - bool MD5(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - unsigned char identifier[16]); - - private: - // Signature of class member function to be called with data read from file - typedef void (MachoID::*UpdateFunction)(unsigned char *bytes, size_t size); - - // Update the CRC value by examining |size| |bytes| and applying the algorithm - // to each byte. - void UpdateCRC(unsigned char *bytes, size_t size); - - // Update the MD5 value by examining |size| |bytes| and applying the algorithm - // to each byte. - void UpdateMD5(unsigned char *bytes, size_t size); - - // Bottleneck for update routines - void Update(MachoWalker *walker, off_t offset, size_t size); - - // Factory for the MachoWalker - bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, - MachoWalker::LoadCommandCallback callback, void *context); - - // The callback from the MachoWalker for CRC and MD5 - static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, - bool swap, void *context); - - // The callback from the MachoWalker for LC_UUID - static bool UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, - bool swap, void *context); - - // The callback from the MachoWalker for LC_ID_DYLIB - static bool IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, - bool swap, void *context); - - // File path - char path_[PATH_MAX]; - - // Memory region to read from - void *memory_; - - // Size of the memory region - size_t memory_size_; - - // The current crc value - uint32_t crc_; - - // The MD5 context - google_breakpad::MD5Context md5_context_; - - // The current update to call from the Update callback - UpdateFunction update_function_; -}; - -} // namespace MacFileUtilities - -#endif // COMMON_MAC_MACHO_ID_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.cc deleted file mode 100644 index 52f3c411b..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.cc +++ /dev/null @@ -1,539 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// macho_reader.cc: Implementation of google_breakpad::Mach_O::FatReader and -// google_breakpad::Mach_O::Reader. See macho_reader.h for details. - -#include "common/mac/macho_reader.h" - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> - -// Unfortunately, CPU_TYPE_ARM is not define for 10.4. -#if !defined(CPU_TYPE_ARM) -#define CPU_TYPE_ARM 12 -#endif - -#if !defined(CPU_TYPE_ARM_64) -#define CPU_TYPE_ARM_64 16777228 -#endif - -namespace google_breakpad { -namespace mach_o { - -// If NDEBUG is #defined, then the 'assert' macro doesn't evaluate its -// arguments, so you can't place expressions that do necessary work in -// the argument of an assert. Nor can you assign the result of the -// expression to a variable and assert that the variable's value is -// true: you'll get unused variable warnings when NDEBUG is #defined. -// -// ASSERT_ALWAYS_EVAL always evaluates its argument, and asserts that -// the result is true if NDEBUG is not #defined. -#if defined(NDEBUG) -#define ASSERT_ALWAYS_EVAL(x) (x) -#else -#define ASSERT_ALWAYS_EVAL(x) assert(x) -#endif - -void FatReader::Reporter::BadHeader() { - fprintf(stderr, "%s: file is neither a fat binary file" - " nor a Mach-O object file\n", filename_.c_str()); -} - -void FatReader::Reporter::TooShort() { - fprintf(stderr, "%s: file too short for the data it claims to contain\n", - filename_.c_str()); -} - -void FatReader::Reporter::MisplacedObjectFile() { - fprintf(stderr, "%s: file too short for the object files it claims" - " to contain\n", filename_.c_str()); -} - -bool FatReader::Read(const uint8_t *buffer, size_t size) { - buffer_.start = buffer; - buffer_.end = buffer + size; - ByteCursor cursor(&buffer_); - - // Fat binaries always use big-endian, so read the magic number in - // that endianness. To recognize Mach-O magic numbers, which can use - // either endianness, check for both the proper and reversed forms - // of the magic numbers. - cursor.set_big_endian(true); - if (cursor >> magic_) { - if (magic_ == FAT_MAGIC) { - // How many object files does this fat binary contain? - uint32_t object_files_count; - if (!(cursor >> object_files_count)) { // nfat_arch - reporter_->TooShort(); - return false; - } - - // Read the list of object files. - object_files_.resize(object_files_count); - for (size_t i = 0; i < object_files_count; i++) { - struct fat_arch objfile; - - // Read this object file entry, byte-swapping as appropriate. - cursor >> objfile.cputype - >> objfile.cpusubtype - >> objfile.offset - >> objfile.size - >> objfile.align; - - SuperFatArch super_fat_arch(objfile); - object_files_[i] = super_fat_arch; - - if (!cursor) { - reporter_->TooShort(); - return false; - } - // Does the file actually have the bytes this entry refers to? - size_t fat_size = buffer_.Size(); - if (objfile.offset > fat_size || - objfile.size > fat_size - objfile.offset) { - reporter_->MisplacedObjectFile(); - return false; - } - } - - return true; - } else if (magic_ == MH_MAGIC || magic_ == MH_MAGIC_64 || - magic_ == MH_CIGAM || magic_ == MH_CIGAM_64) { - // If this is a little-endian Mach-O file, fix the cursor's endianness. - if (magic_ == MH_CIGAM || magic_ == MH_CIGAM_64) - cursor.set_big_endian(false); - // Record the entire file as a single entry in the object file list. - object_files_.resize(1); - - // Get the cpu type and subtype from the Mach-O header. - if (!(cursor >> object_files_[0].cputype - >> object_files_[0].cpusubtype)) { - reporter_->TooShort(); - return false; - } - - object_files_[0].offset = 0; - object_files_[0].size = static_cast<uint64_t>(buffer_.Size()); - // This alignment is correct for 32 and 64-bit x86 and ppc. - // See get_align in the lipo source for other architectures: - // http://www.opensource.apple.com/source/cctools/cctools-773/misc/lipo.c - object_files_[0].align = 12; // 2^12 == 4096 - return true; - } - } - reporter_->BadHeader(); - return false; -} - -void Reader::Reporter::BadHeader() { - fprintf(stderr, "%s: file is not a Mach-O object file\n", filename_.c_str()); -} - -void Reader::Reporter::CPUTypeMismatch(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - cpu_type_t expected_cpu_type, - cpu_subtype_t expected_cpu_subtype) { - fprintf(stderr, "%s: CPU type %d, subtype %d does not match expected" - " type %d, subtype %d\n", - filename_.c_str(), cpu_type, cpu_subtype, - expected_cpu_type, expected_cpu_subtype); -} - -void Reader::Reporter::HeaderTruncated() { - fprintf(stderr, "%s: file does not contain a complete Mach-O header\n", - filename_.c_str()); -} - -void Reader::Reporter::LoadCommandRegionTruncated() { - fprintf(stderr, "%s: file too short to hold load command region" - " given in Mach-O header\n", filename_.c_str()); -} - -void Reader::Reporter::LoadCommandsOverrun(size_t claimed, size_t i, - LoadCommandType type) { - fprintf(stderr, "%s: file's header claims there are %zu" - " load commands, but load command #%zu", - filename_.c_str(), claimed, i); - if (type) fprintf(stderr, ", of type %d,", type); - fprintf(stderr, " extends beyond the end of the load command region\n"); -} - -void Reader::Reporter::LoadCommandTooShort(size_t i, LoadCommandType type) { - fprintf(stderr, "%s: the contents of load command #%zu, of type %d," - " extend beyond the size given in the load command's header\n", - filename_.c_str(), i, type); -} - -void Reader::Reporter::SectionsMissing(const string &name) { - fprintf(stderr, "%s: the load command for segment '%s'" - " is too short to hold the section headers it claims to have\n", - filename_.c_str(), name.c_str()); -} - -void Reader::Reporter::MisplacedSegmentData(const string &name) { - fprintf(stderr, "%s: the segment '%s' claims its contents lie beyond" - " the end of the file\n", filename_.c_str(), name.c_str()); -} - -void Reader::Reporter::MisplacedSectionData(const string §ion, - const string &segment) { - fprintf(stderr, "%s: the section '%s' in segment '%s'" - " claims its contents lie outside the segment's contents\n", - filename_.c_str(), section.c_str(), segment.c_str()); -} - -void Reader::Reporter::MisplacedSymbolTable() { - fprintf(stderr, "%s: the LC_SYMTAB load command claims that the symbol" - " table's contents are located beyond the end of the file\n", - filename_.c_str()); -} - -void Reader::Reporter::UnsupportedCPUType(cpu_type_t cpu_type) { - fprintf(stderr, "%s: CPU type %d is not supported\n", - filename_.c_str(), cpu_type); -} - -bool Reader::Read(const uint8_t *buffer, - size_t size, - cpu_type_t expected_cpu_type, - cpu_subtype_t expected_cpu_subtype) { - assert(!buffer_.start); - buffer_.start = buffer; - buffer_.end = buffer + size; - ByteCursor cursor(&buffer_, true); - uint32_t magic; - if (!(cursor >> magic)) { - reporter_->HeaderTruncated(); - return false; - } - - if (expected_cpu_type != CPU_TYPE_ANY) { - uint32_t expected_magic; - // validate that magic matches the expected cpu type - switch (expected_cpu_type) { - case CPU_TYPE_ARM: - case CPU_TYPE_I386: - expected_magic = MH_CIGAM; - break; - case CPU_TYPE_POWERPC: - expected_magic = MH_MAGIC; - break; - case CPU_TYPE_ARM_64: - case CPU_TYPE_X86_64: - expected_magic = MH_CIGAM_64; - break; - case CPU_TYPE_POWERPC64: - expected_magic = MH_MAGIC_64; - break; - default: - reporter_->UnsupportedCPUType(expected_cpu_type); - return false; - } - - if (expected_magic != magic) { - reporter_->BadHeader(); - return false; - } - } - - // Since the byte cursor is in big-endian mode, a reversed magic number - // always indicates a little-endian file, regardless of our own endianness. - switch (magic) { - case MH_MAGIC: big_endian_ = true; bits_64_ = false; break; - case MH_CIGAM: big_endian_ = false; bits_64_ = false; break; - case MH_MAGIC_64: big_endian_ = true; bits_64_ = true; break; - case MH_CIGAM_64: big_endian_ = false; bits_64_ = true; break; - default: - reporter_->BadHeader(); - return false; - } - cursor.set_big_endian(big_endian_); - uint32_t commands_size, reserved; - cursor >> cpu_type_ >> cpu_subtype_ >> file_type_ >> load_command_count_ - >> commands_size >> flags_; - if (bits_64_) - cursor >> reserved; - if (!cursor) { - reporter_->HeaderTruncated(); - return false; - } - - if (expected_cpu_type != CPU_TYPE_ANY && - (expected_cpu_type != cpu_type_ || - expected_cpu_subtype != cpu_subtype_)) { - reporter_->CPUTypeMismatch(cpu_type_, cpu_subtype_, - expected_cpu_type, expected_cpu_subtype); - return false; - } - - cursor - .PointTo(&load_commands_.start, commands_size) - .PointTo(&load_commands_.end, 0); - if (!cursor) { - reporter_->LoadCommandRegionTruncated(); - return false; - } - - return true; -} - -bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const { - ByteCursor list_cursor(&load_commands_, big_endian_); - - for (size_t index = 0; index < load_command_count_; ++index) { - // command refers to this load command alone, so that cursor will - // refuse to read past the load command's end. But since we haven't - // read the size yet, let command initially refer to the entire - // remainder of the load command series. - ByteBuffer command(list_cursor.here(), list_cursor.Available()); - ByteCursor cursor(&command, big_endian_); - - // Read the command type and size --- fields common to all commands. - uint32_t type, size; - if (!(cursor >> type)) { - reporter_->LoadCommandsOverrun(load_command_count_, index, 0); - return false; - } - if (!(cursor >> size) || size > command.Size()) { - reporter_->LoadCommandsOverrun(load_command_count_, index, type); - return false; - } - - // Now that we've read the length, restrict command's range to this - // load command only. - command.end = command.start + size; - - switch (type) { - case LC_SEGMENT: - case LC_SEGMENT_64: { - Segment segment; - segment.bits_64 = (type == LC_SEGMENT_64); - size_t word_size = segment.bits_64 ? 8 : 4; - cursor.CString(&segment.name, 16); - size_t file_offset, file_size; - cursor - .Read(word_size, false, &segment.vmaddr) - .Read(word_size, false, &segment.vmsize) - .Read(word_size, false, &file_offset) - .Read(word_size, false, &file_size); - cursor >> segment.maxprot - >> segment.initprot - >> segment.nsects - >> segment.flags; - if (!cursor) { - reporter_->LoadCommandTooShort(index, type); - return false; - } - if (file_offset > buffer_.Size() || - file_size > buffer_.Size() - file_offset) { - reporter_->MisplacedSegmentData(segment.name); - return false; - } - // Mach-O files in .dSYM bundles have the contents of the loaded - // segments removed, and their file offsets and file sizes zeroed - // out. To help us handle this special case properly, give such - // segments' contents NULL starting and ending pointers. - if (file_offset == 0 && file_size == 0) { - segment.contents.start = segment.contents.end = NULL; - } else { - segment.contents.start = buffer_.start + file_offset; - segment.contents.end = segment.contents.start + file_size; - } - // The section list occupies the remainder of this load command's space. - segment.section_list.start = cursor.here(); - segment.section_list.end = command.end; - - if (!handler->SegmentCommand(segment)) - return false; - break; - } - - case LC_SYMTAB: { - uint32_t symoff, nsyms, stroff, strsize; - cursor >> symoff >> nsyms >> stroff >> strsize; - if (!cursor) { - reporter_->LoadCommandTooShort(index, type); - return false; - } - // How big are the entries in the symbol table? - // sizeof(struct nlist_64) : sizeof(struct nlist), - // but be paranoid about alignment vs. target architecture. - size_t symbol_size = bits_64_ ? 16 : 12; - // How big is the entire symbol array? - size_t symbols_size = nsyms * symbol_size; - if (symoff > buffer_.Size() || symbols_size > buffer_.Size() - symoff || - stroff > buffer_.Size() || strsize > buffer_.Size() - stroff) { - reporter_->MisplacedSymbolTable(); - return false; - } - ByteBuffer entries(buffer_.start + symoff, symbols_size); - ByteBuffer names(buffer_.start + stroff, strsize); - if (!handler->SymtabCommand(entries, names)) - return false; - break; - } - - default: { - if (!handler->UnknownCommand(type, command)) - return false; - break; - } - } - - list_cursor.set_here(command.end); - } - - return true; -} - -// A load command handler that looks for a segment of a given name. -class Reader::SegmentFinder : public LoadCommandHandler { - public: - // Create a load command handler that looks for a segment named NAME, - // and sets SEGMENT to describe it if found. - SegmentFinder(const string &name, Segment *segment) - : name_(name), segment_(segment), found_() { } - - // Return true if the traversal found the segment, false otherwise. - bool found() const { return found_; } - - bool SegmentCommand(const Segment &segment) { - if (segment.name == name_) { - *segment_ = segment; - found_ = true; - return false; - } - return true; - } - - private: - // The name of the segment our creator is looking for. - const string &name_; - - // Where we should store the segment if found. (WEAK) - Segment *segment_; - - // True if we found the segment. - bool found_; -}; - -bool Reader::FindSegment(const string &name, Segment *segment) const { - SegmentFinder finder(name, segment); - WalkLoadCommands(&finder); - return finder.found(); -} - -bool Reader::WalkSegmentSections(const Segment &segment, - SectionHandler *handler) const { - size_t word_size = segment.bits_64 ? 8 : 4; - ByteCursor cursor(&segment.section_list, big_endian_); - - for (size_t i = 0; i < segment.nsects; i++) { - Section section; - section.bits_64 = segment.bits_64; - uint64_t size; - uint32_t offset, dummy32; - cursor - .CString(§ion.section_name, 16) - .CString(§ion.segment_name, 16) - .Read(word_size, false, §ion.address) - .Read(word_size, false, &size) - >> offset - >> section.align - >> dummy32 - >> dummy32 - >> section.flags - >> dummy32 - >> dummy32; - if (section.bits_64) - cursor >> dummy32; - if (!cursor) { - reporter_->SectionsMissing(segment.name); - return false; - } - const uint32_t section_type = section.flags & SECTION_TYPE; - if (section_type == S_ZEROFILL || section_type == S_THREAD_LOCAL_ZEROFILL || - section_type == S_GB_ZEROFILL) { - // Zero-fill sections have a size, but no contents. - section.contents.start = section.contents.end = NULL; - } else if (segment.contents.start == NULL && - segment.contents.end == NULL) { - // Mach-O files in .dSYM bundles have the contents of the loaded - // segments removed, and their file offsets and file sizes zeroed - // out. However, the sections within those segments still have - // non-zero sizes. There's no reason to call MisplacedSectionData in - // this case; the caller may just need the section's load - // address. But do set the contents' limits to NULL, for safety. - section.contents.start = section.contents.end = NULL; - } else { - if (offset < size_t(segment.contents.start - buffer_.start) || - offset > size_t(segment.contents.end - buffer_.start) || - size > size_t(segment.contents.end - buffer_.start - offset)) { - reporter_->MisplacedSectionData(section.section_name, - section.segment_name); - return false; - } - section.contents.start = buffer_.start + offset; - section.contents.end = section.contents.start + size; - } - if (!handler->HandleSection(section)) - return false; - } - return true; -} - -// A SectionHandler that builds a SectionMap for the sections within a -// given segment. -class Reader::SectionMapper: public SectionHandler { - public: - // Create a SectionHandler that populates MAP with an entry for - // each section it is given. - SectionMapper(SectionMap *map) : map_(map) { } - bool HandleSection(const Section §ion) { - (*map_)[section.section_name] = section; - return true; - } - private: - // The map under construction. (WEAK) - SectionMap *map_; -}; - -bool Reader::MapSegmentSections(const Segment &segment, - SectionMap *section_map) const { - section_map->clear(); - SectionMapper mapper(section_map); - return WalkSegmentSections(segment, &mapper); -} - -} // namespace mach_o -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.h b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.h deleted file mode 100644 index 30db742db..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader.h +++ /dev/null @@ -1,460 +0,0 @@ -// -*- mode: C++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// macho_reader.h: A class for parsing Mach-O files. - -#ifndef BREAKPAD_COMMON_MAC_MACHO_READER_H_ -#define BREAKPAD_COMMON_MAC_MACHO_READER_H_ - -#include <mach-o/loader.h> -#include <mach-o/fat.h> -#include <stdint.h> -#include <stdlib.h> -#include <unistd.h> - -#include <map> -#include <string> -#include <vector> - -#include "common/byte_cursor.h" -#include "common/mac/super_fat_arch.h" - -namespace google_breakpad { -namespace mach_o { - -using std::map; -using std::string; -using std::vector; - -// The Mac headers don't specify particular types for these groups of -// constants, but defining them here provides some documentation -// value. We also give them the same width as the fields in which -// they appear, which makes them a bit easier to use with ByteCursors. -typedef uint32_t Magic; -typedef uint32_t FileType; -typedef uint32_t FileFlags; -typedef uint32_t LoadCommandType; -typedef uint32_t SegmentFlags; -typedef uint32_t SectionFlags; - -// A parser for fat binary files, used to store universal binaries. -// When applied to a (non-fat) Mach-O file, this behaves as if the -// file were a fat file containing a single object file. -class FatReader { - public: - - // A class for reporting errors found while parsing fat binary files. The - // default definitions of these methods print messages to stderr. - class Reporter { - public: - // Create a reporter that attributes problems to |filename|. - explicit Reporter(const string &filename) : filename_(filename) { } - - virtual ~Reporter() { } - - // The data does not begin with a fat binary or Mach-O magic number. - // This is a fatal error. - virtual void BadHeader(); - - // The Mach-O fat binary file ends abruptly, without enough space - // to contain an object file it claims is present. - virtual void MisplacedObjectFile(); - - // The file ends abruptly: either it is not large enough to hold a - // complete header, or the header implies that contents are present - // beyond the actual end of the file. - virtual void TooShort(); - - private: - // The filename to which the reader should attribute problems. - string filename_; - }; - - // Create a fat binary file reader that uses |reporter| to report problems. - explicit FatReader(Reporter *reporter) : reporter_(reporter) { } - - // Read the |size| bytes at |buffer| as a fat binary file. On success, - // return true; on failure, report the problem to reporter_ and return - // false. - // - // If the data is a plain Mach-O file, rather than a fat binary file, - // then the reader behaves as if it had found a fat binary file whose - // single object file is the Mach-O file. - bool Read(const uint8_t *buffer, size_t size); - - // Return an array of 'SuperFatArch' structures describing the - // object files present in this fat binary file. Set |size| to the - // number of elements in the array. - // - // Assuming Read returned true, the entries are validated: it is safe to - // assume that the offsets and sizes in each SuperFatArch refer to subranges - // of the bytes passed to Read. - // - // If there are no object files in this fat binary, then this - // function can return NULL. - // - // The array is owned by this FatReader instance; it will be freed when - // this FatReader is destroyed. - // - // This function returns a C-style array instead of a vector to make it - // possible to use the result with OS X functions like NXFindBestFatArch, - // so that the symbol dumper will behave consistently with other OS X - // utilities that work with fat binaries. - const SuperFatArch* object_files(size_t *count) const { - *count = object_files_.size(); - if (object_files_.size() > 0) - return &object_files_[0]; - return NULL; - } - - private: - // We use this to report problems parsing the file's contents. (WEAK) - Reporter *reporter_; - - // The contents of the fat binary or Mach-O file we're parsing. We do not - // own the storage it refers to. - ByteBuffer buffer_; - - // The magic number of this binary, in host byte order. - Magic magic_; - - // The list of object files in this binary. - // object_files_.size() == fat_header.nfat_arch - vector<SuperFatArch> object_files_; -}; - -// A segment in a Mach-O file. All these fields have been byte-swapped as -// appropriate for use by the executing architecture. -struct Segment { - // The ByteBuffers below point into the bytes passed to the Reader that - // created this Segment. - - ByteBuffer section_list; // This segment's section list. - ByteBuffer contents; // This segment's contents. - - // This segment's name. - string name; - - // The address at which this segment should be loaded in memory. If - // bits_64 is false, only the bottom 32 bits of this value are valid. - uint64_t vmaddr; - - // The size of this segment when loaded into memory. This may be larger - // than contents.Size(), in which case the extra area will be - // initialized with zeros. If bits_64 is false, only the bottom 32 bits - // of this value are valid. - uint64_t vmsize; - - // The maximum and initial VM protection of this segment's contents. - uint32_t maxprot; - uint32_t initprot; - - // The number of sections in section_list. - uint32_t nsects; - - // Flags describing this segment, from SegmentFlags. - uint32_t flags; - - // True if this is a 64-bit section; false if it is a 32-bit section. - bool bits_64; -}; - -// A section in a Mach-O file. All these fields have been byte-swapped as -// appropriate for use by the executing architecture. -struct Section { - // This section's contents. This points into the bytes passed to the - // Reader that created this Section. - ByteBuffer contents; - - // This section's name. - string section_name; // section[_64].sectname - // The name of the segment this section belongs to. - string segment_name; // section[_64].segname - - // The address at which this section's contents should be loaded in - // memory. If bits_64 is false, only the bottom 32 bits of this value - // are valid. - uint64_t address; - - // The contents of this section should be loaded into memory at an - // address which is a multiple of (two raised to this power). - uint32_t align; - - // Flags from SectionFlags describing the section's contents. - uint32_t flags; - - // We don't support reading relocations yet. - - // True if this is a 64-bit section; false if it is a 32-bit section. - bool bits_64; -}; - -// A map from section names to Sections. -typedef map<string, Section> SectionMap; - -// A reader for a Mach-O file. -// -// This does not handle fat binaries; see FatReader above. FatReader -// provides a friendly interface for parsing data that could be either a -// fat binary or a Mach-O file. -class Reader { - public: - - // A class for reporting errors found while parsing Mach-O files. The - // default definitions of these member functions print messages to - // stderr. - class Reporter { - public: - // Create a reporter that attributes problems to |filename|. - explicit Reporter(const string &filename) : filename_(filename) { } - virtual ~Reporter() { } - - // Reporter functions for fatal errors return void; the reader will - // definitely return an error to its caller after calling them - - // The data does not begin with a Mach-O magic number, or the magic - // number does not match the expected value for the cpu architecture. - // This is a fatal error. - virtual void BadHeader(); - - // The data contained in a Mach-O fat binary (|cpu_type|, |cpu_subtype|) - // does not match the expected CPU architecture - // (|expected_cpu_type|, |expected_cpu_subtype|). - virtual void CPUTypeMismatch(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - cpu_type_t expected_cpu_type, - cpu_subtype_t expected_cpu_subtype); - - // The file ends abruptly: either it is not large enough to hold a - // complete header, or the header implies that contents are present - // beyond the actual end of the file. - virtual void HeaderTruncated(); - - // The file's load command region, as given in the Mach-O header, is - // too large for the file. - virtual void LoadCommandRegionTruncated(); - - // The file's Mach-O header claims the file contains |claimed| load - // commands, but the I'th load command, of type |type|, extends beyond - // the end of the load command region, as given by the Mach-O header. - // If |type| is zero, the command's type was unreadable. - virtual void LoadCommandsOverrun(size_t claimed, size_t i, - LoadCommandType type); - - // The contents of the |i|'th load command, of type |type|, extend beyond - // the size given in the load command's header. - virtual void LoadCommandTooShort(size_t i, LoadCommandType type); - - // The LC_SEGMENT or LC_SEGMENT_64 load command for the segment named - // |name| is too short to hold the sections that its header says it does. - // (This more specific than LoadCommandTooShort.) - virtual void SectionsMissing(const string &name); - - // The segment named |name| claims that its contents lie beyond the end - // of the file. - virtual void MisplacedSegmentData(const string &name); - - // The section named |section| in the segment named |segment| claims that - // its contents do not lie entirely within the segment. - virtual void MisplacedSectionData(const string §ion, - const string &segment); - - // The LC_SYMTAB command claims that symbol table contents are located - // beyond the end of the file. - virtual void MisplacedSymbolTable(); - - // An attempt was made to read a Mach-O file of the unsupported - // CPU architecture |cpu_type|. - virtual void UnsupportedCPUType(cpu_type_t cpu_type); - - private: - string filename_; - }; - - // A handler for sections parsed from a segment. The WalkSegmentSections - // member function accepts an instance of this class, and applies it to - // each section defined in a given segment. - class SectionHandler { - public: - virtual ~SectionHandler() { } - - // Called to report that the segment's section list contains |section|. - // This should return true if the iteration should continue, or false - // if it should stop. - virtual bool HandleSection(const Section §ion) = 0; - }; - - // A handler for the load commands in a Mach-O file. - class LoadCommandHandler { - public: - LoadCommandHandler() { } - virtual ~LoadCommandHandler() { } - - // When called from WalkLoadCommands, the following handler functions - // should return true if they wish to continue iterating over the load - // command list, or false if they wish to stop iterating. - // - // When called from LoadCommandIterator::Handle or Reader::Handle, - // these functions' return values are simply passed through to Handle's - // caller. - // - // The definitions provided by this base class simply return true; the - // default is to silently ignore sections whose member functions the - // subclass doesn't override. - - // COMMAND is load command we don't recognize. We provide only the - // command type and a ByteBuffer enclosing the command's data (If we - // cannot parse the command type or its size, we call - // reporter_->IncompleteLoadCommand instead.) - virtual bool UnknownCommand(LoadCommandType type, - const ByteBuffer &contents) { - return true; - } - - // The load command is LC_SEGMENT or LC_SEGMENT_64, defining a segment - // with the properties given in |segment|. - virtual bool SegmentCommand(const Segment &segment) { - return true; - } - - // The load command is LC_SYMTAB. |entries| holds the array of nlist - // entries, and |names| holds the strings the entries refer to. - virtual bool SymtabCommand(const ByteBuffer &entries, - const ByteBuffer &names) { - return true; - } - - // Add handler functions for more load commands here as needed. - }; - - // Create a Mach-O file reader that reports problems to |reporter|. - explicit Reader(Reporter *reporter) - : reporter_(reporter) { } - - // Read the given data as a Mach-O file. The reader retains pointers - // into the data passed, so the data should live as long as the reader - // does. On success, return true; on failure, return false. - // - // At most one of these functions should be invoked once on each Reader - // instance. - bool Read(const uint8_t *buffer, - size_t size, - cpu_type_t expected_cpu_type, - cpu_subtype_t expected_cpu_subtype); - bool Read(const ByteBuffer &buffer, - cpu_type_t expected_cpu_type, - cpu_subtype_t expected_cpu_subtype) { - return Read(buffer.start, - buffer.Size(), - expected_cpu_type, - expected_cpu_subtype); - } - - // Return this file's characteristics, as found in the Mach-O header. - cpu_type_t cpu_type() const { return cpu_type_; } - cpu_subtype_t cpu_subtype() const { return cpu_subtype_; } - FileType file_type() const { return file_type_; } - FileFlags flags() const { return flags_; } - - // Return true if this is a 64-bit Mach-O file, false if it is a 32-bit - // Mach-O file. - bool bits_64() const { return bits_64_; } - - // Return true if this is a big-endian Mach-O file, false if it is - // little-endian. - bool big_endian() const { return big_endian_; } - - // Apply |handler| to each load command in this Mach-O file, stopping when - // a handler function returns false. If we encounter a malformed load - // command, report it via reporter_ and return false. Return true if all - // load commands were parseable and all handlers returned true. - bool WalkLoadCommands(LoadCommandHandler *handler) const; - - // Set |segment| to describe the segment named |name|, if present. If - // found, |segment|'s byte buffers refer to a subregion of the bytes - // passed to Read. If we find the section, return true; otherwise, - // return false. - bool FindSegment(const string &name, Segment *segment) const; - - // Apply |handler| to each section defined in |segment|. If |handler| returns - // false, stop iterating and return false. If all calls to |handler| return - // true and we reach the end of the section list, return true. - bool WalkSegmentSections(const Segment &segment, SectionHandler *handler) - const; - - // Clear |section_map| and then populate it with a map of the sections - // in |segment|, from section names to Section structures. - // Each Section's contents refer to bytes in |segment|'s contents. - // On success, return true; if a problem occurs, report it and return false. - bool MapSegmentSections(const Segment &segment, SectionMap *section_map) - const; - - private: - // Used internally. - class SegmentFinder; - class SectionMapper; - - // We use this to report problems parsing the file's contents. (WEAK) - Reporter *reporter_; - - // The contents of the Mach-O file we're parsing. We do not own the - // storage it refers to. - ByteBuffer buffer_; - - // True if this file is big-endian. - bool big_endian_; - - // True if this file is a 64-bit Mach-O file. - bool bits_64_; - - // This file's cpu type and subtype. - cpu_type_t cpu_type_; // mach_header[_64].cputype - cpu_subtype_t cpu_subtype_; // mach_header[_64].cpusubtype - - // This file's type. - FileType file_type_; // mach_header[_64].filetype - - // The region of buffer_ occupied by load commands. - ByteBuffer load_commands_; - - // The number of load commands in load_commands_. - uint32_t load_command_count_; // mach_header[_64].ncmds - - // This file's header flags. - FileFlags flags_; -}; - -} // namespace mach_o -} // namespace google_breakpad - -#endif // BREAKPAD_COMMON_MAC_MACHO_READER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader_unittest.cc deleted file mode 100644 index 8ceab14bf..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_reader_unittest.cc +++ /dev/null @@ -1,1902 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// macho_reader_unittest.cc: Unit tests for google_breakpad::Mach_O::FatReader -// and google_breakpad::Mach_O::Reader. - -#include <map> -#include <string> -#include <vector> - -#include "breakpad_googletest_includes.h" -#include "common/mac/macho_reader.h" -#include "common/test_assembler.h" - -namespace mach_o = google_breakpad::mach_o; -namespace test_assembler = google_breakpad::test_assembler; - -using mach_o::FatReader; -using mach_o::FileFlags; -using mach_o::FileType; -using mach_o::LoadCommandType; -using mach_o::Reader; -using mach_o::Section; -using mach_o::SectionMap; -using mach_o::Segment; -using test_assembler::Endianness; -using test_assembler::Label; -using test_assembler::kBigEndian; -using test_assembler::kLittleEndian; -using test_assembler::kUnsetEndian; -using google_breakpad::ByteBuffer; -using std::map; -using std::string; -using std::vector; -using testing::AllOf; -using testing::DoAll; -using testing::Field; -using testing::InSequence; -using testing::Matcher; -using testing::Return; -using testing::SaveArg; -using testing::Test; -using testing::_; - - -// Mock classes for the reader's various reporters and handlers. - -class MockFatReaderReporter: public FatReader::Reporter { - public: - MockFatReaderReporter(const string &filename) - : FatReader::Reporter(filename) { } - MOCK_METHOD0(BadHeader, void()); - MOCK_METHOD0(MisplacedObjectFile, void()); - MOCK_METHOD0(TooShort, void()); -}; - -class MockReaderReporter: public Reader::Reporter { - public: - MockReaderReporter(const string &filename) : Reader::Reporter(filename) { } - MOCK_METHOD0(BadHeader, void()); - MOCK_METHOD4(CPUTypeMismatch, void(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - cpu_type_t expected_cpu_type, - cpu_subtype_t expected_cpu_subtype)); - MOCK_METHOD0(HeaderTruncated, void()); - MOCK_METHOD0(LoadCommandRegionTruncated, void()); - MOCK_METHOD3(LoadCommandsOverrun, void(size_t claimed, size_t i, - LoadCommandType type)); - MOCK_METHOD2(LoadCommandTooShort, void(size_t i, LoadCommandType type)); - MOCK_METHOD1(SectionsMissing, void(const string &name)); - MOCK_METHOD1(MisplacedSegmentData, void(const string &name)); - MOCK_METHOD2(MisplacedSectionData, void(const string §ion, - const string &segment)); - MOCK_METHOD0(MisplacedSymbolTable, void()); - MOCK_METHOD1(UnsupportedCPUType, void(cpu_type_t cpu_type)); -}; - -class MockLoadCommandHandler: public Reader::LoadCommandHandler { - public: - MOCK_METHOD2(UnknownCommand, bool(LoadCommandType, const ByteBuffer &)); - MOCK_METHOD1(SegmentCommand, bool(const Segment &)); - MOCK_METHOD2(SymtabCommand, bool(const ByteBuffer &, const ByteBuffer &)); -}; - -class MockSectionHandler: public Reader::SectionHandler { - public: - MOCK_METHOD1(HandleSection, bool(const Section §ion)); -}; - - -// Tests for mach_o::FatReader. - -// Since the effect of these functions is to write to stderr, the -// results of these tests must be inspected by hand. -TEST(FatReaderReporter, BadHeader) { - FatReader::Reporter reporter("filename"); - reporter.BadHeader(); -} - -TEST(FatReaderReporter, MisplacedObjectFile) { - FatReader::Reporter reporter("filename"); - reporter.MisplacedObjectFile(); -} - -TEST(FatReaderReporter, TooShort) { - FatReader::Reporter reporter("filename"); - reporter.TooShort(); -} - -TEST(MachOReaderReporter, BadHeader) { - Reader::Reporter reporter("filename"); - reporter.BadHeader(); -} - -TEST(MachOReaderReporter, CPUTypeMismatch) { - Reader::Reporter reporter("filename"); - reporter.CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, - CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL); -} - -TEST(MachOReaderReporter, HeaderTruncated) { - Reader::Reporter reporter("filename"); - reporter.HeaderTruncated(); -} - -TEST(MachOReaderReporter, LoadCommandRegionTruncated) { - Reader::Reporter reporter("filename"); - reporter.LoadCommandRegionTruncated(); -} - -TEST(MachOReaderReporter, LoadCommandsOverrun) { - Reader::Reporter reporter("filename"); - reporter.LoadCommandsOverrun(10, 9, LC_DYSYMTAB); - reporter.LoadCommandsOverrun(10, 9, 0); -} - -TEST(MachOReaderReporter, LoadCommandTooShort) { - Reader::Reporter reporter("filename"); - reporter.LoadCommandTooShort(11, LC_SYMTAB); -} - -TEST(MachOReaderReporter, SectionsMissing) { - Reader::Reporter reporter("filename"); - reporter.SectionsMissing("segment name"); -} - -TEST(MachOReaderReporter, MisplacedSegmentData) { - Reader::Reporter reporter("filename"); - reporter.MisplacedSegmentData("segment name"); -} - -TEST(MachOReaderReporter, MisplacedSectionData) { - Reader::Reporter reporter("filename"); - reporter.MisplacedSectionData("section name", "segment name"); -} - -TEST(MachOReaderReporter, MisplacedSymbolTable) { - Reader::Reporter reporter("filename"); - reporter.MisplacedSymbolTable(); -} - -TEST(MachOReaderReporter, UnsupportedCPUType) { - Reader::Reporter reporter("filename"); - reporter.UnsupportedCPUType(CPU_TYPE_HPPA); -} - -struct FatReaderFixture { - FatReaderFixture() - : fat(kBigEndian), - reporter("reporter filename"), - reader(&reporter), object_files() { - EXPECT_CALL(reporter, BadHeader()).Times(0); - EXPECT_CALL(reporter, TooShort()).Times(0); - - // here, start, and Mark are file offsets in 'fat'. - fat.start() = 0; - } - // Append a 'fat_arch' entry to 'fat', with the given field values. - void AppendFatArch(cpu_type_t type, cpu_subtype_t subtype, - Label offset, Label size, uint32_t align) { - fat - .B32(type) - .B32(subtype) - .B32(offset) - .B32(size) - .B32(align); - } - // Append |n| dummy 'fat_arch' entries to 'fat'. The cpu type and - // subtype have unrealistic values. - void AppendDummyArchEntries(int n) { - for (int i = 0; i < n; i++) - AppendFatArch(0xb68ad617, 0x715a0840, 0, 0, 1); - } - void ReadFat(bool expect_parse_success = true) { - ASSERT_TRUE(fat.GetContents(&contents)); - fat_bytes = reinterpret_cast<const uint8_t *>(contents.data()); - if (expect_parse_success) { - EXPECT_TRUE(reader.Read(fat_bytes, contents.size())); - size_t fat_files_count; - const SuperFatArch* fat_files = reader.object_files(&fat_files_count); - object_files.resize(fat_files_count); - for (size_t i = 0; i < fat_files_count; ++i) { - EXPECT_TRUE(fat_files[i].ConvertToFatArch(&object_files[i])); - } - } - else - EXPECT_FALSE(reader.Read(fat_bytes, contents.size())); - } - test_assembler::Section fat; - MockFatReaderReporter reporter; - FatReader reader; - string contents; - const uint8_t *fat_bytes; - vector<struct fat_arch> object_files; -}; - -class FatReaderTest: public FatReaderFixture, public Test { }; - -TEST_F(FatReaderTest, BadMagic) { - EXPECT_CALL(reporter, BadHeader()).Times(1); - fat - .B32(0xcafed00d) // magic number (incorrect) - .B32(10); // number of architectures - AppendDummyArchEntries(10); - ReadFat(false); -} - -TEST_F(FatReaderTest, HeaderTooShort) { - EXPECT_CALL(reporter, TooShort()).Times(1); - fat - .B32(0xcafebabe); // magic number - ReadFat(false); -} - -TEST_F(FatReaderTest, ObjectListTooShort) { - EXPECT_CALL(reporter, TooShort()).Times(1); - fat - .B32(0xcafebabe) // magic number - .B32(10); // number of architectures - AppendDummyArchEntries(9); // nine dummy architecture entries... - fat // and a tenth, missing a byte at the end - .B32(0x3d46c8fc) // cpu type - .B32(0x8a7bfb01) // cpu subtype - .B32(0) // offset - .B32(0) // size - .Append(3, '*'); // one byte short of a four-byte alignment - ReadFat(false); -} - -TEST_F(FatReaderTest, DataTooShort) { - EXPECT_CALL(reporter, MisplacedObjectFile()).Times(1); - Label arch_data; - fat - .B32(0xcafebabe) // magic number - .B32(1); // number of architectures - AppendFatArch(0xb4d4a366, 0x4ba4f525, arch_data, 40, 0); - fat - .Mark(&arch_data) // file data begins here - .Append(30, '*'); // only 30 bytes, not 40 as header claims - ReadFat(false); -} - -TEST_F(FatReaderTest, NoObjectFiles) { - fat - .B32(0xcafebabe) // magic number - .B32(0); // number of architectures - ReadFat(); - EXPECT_EQ(0U, object_files.size()); -} - -TEST_F(FatReaderTest, OneObjectFile) { - Label obj1_offset; - fat - .B32(0xcafebabe) // magic number - .B32(1); // number of architectures - // First object file list entry - AppendFatArch(0x5e3a6e91, 0x52ccd852, obj1_offset, 0x42, 0x355b15b2); - // First object file data - fat - .Mark(&obj1_offset) - .Append(0x42, '*'); // dummy contents - ReadFat(); - ASSERT_EQ(1U, object_files.size()); - EXPECT_EQ(0x5e3a6e91, object_files[0].cputype); - EXPECT_EQ(0x52ccd852, object_files[0].cpusubtype); - EXPECT_EQ(obj1_offset.Value(), object_files[0].offset); - EXPECT_EQ(0x42U, object_files[0].size); - EXPECT_EQ(0x355b15b2U, object_files[0].align); -} - -TEST_F(FatReaderTest, ThreeObjectFiles) { - Label obj1, obj2, obj3; - fat - .B32(0xcafebabe) // magic number - .B32(3); // number of architectures - // Three object file list entries. - AppendFatArch(0x0cb92c30, 0x6a159a71, obj1, 0xfb4, 0x2615dbe8); - AppendFatArch(0x0f3f1cbb, 0x6c55e90f, obj2, 0xc31, 0x83af6ffd); - AppendFatArch(0x3717276d, 0x10ecdc84, obj3, 0x4b3, 0x035267d7); - fat - // First object file data - .Mark(&obj1) - .Append(0xfb4, '*') // dummy contents - // Second object file data - .Mark(&obj2) - .Append(0xc31, '%') // dummy contents - // Third object file data - .Mark(&obj3) - .Append(0x4b3, '^'); // dummy contents - - ReadFat(); - - ASSERT_EQ(3U, object_files.size()); - - // First object file. - EXPECT_EQ(0x0cb92c30, object_files[0].cputype); - EXPECT_EQ(0x6a159a71, object_files[0].cpusubtype); - EXPECT_EQ(obj1.Value(), object_files[0].offset); - EXPECT_EQ(0xfb4U, object_files[0].size); - EXPECT_EQ(0x2615dbe8U, object_files[0].align); - - // Second object file. - EXPECT_EQ(0x0f3f1cbb, object_files[1].cputype); - EXPECT_EQ(0x6c55e90f, object_files[1].cpusubtype); - EXPECT_EQ(obj2.Value(), object_files[1].offset); - EXPECT_EQ(0xc31U, object_files[1].size); - EXPECT_EQ(0x83af6ffdU, object_files[1].align); - - // Third object file. - EXPECT_EQ(0x3717276d, object_files[2].cputype); - EXPECT_EQ(0x10ecdc84, object_files[2].cpusubtype); - EXPECT_EQ(obj3.Value(), object_files[2].offset); - EXPECT_EQ(0x4b3U, object_files[2].size); - EXPECT_EQ(0x035267d7U, object_files[2].align); -} - -TEST_F(FatReaderTest, BigEndianMachO32) { - fat.set_endianness(kBigEndian); - fat - .D32(0xfeedface) // Mach-O file magic number - .D32(0x1a9d0518) // cpu type - .D32(0x1b779357) // cpu subtype - .D32(0x009df67e) // file type - .D32(0) // no load commands - .D32(0) // the load commands occupy no bytes - .D32(0x21987a99); // flags - - ReadFat(); - - // FatReader should treat a Mach-O file as if it were a fat binary file - // containing one object file --- the whole thing. - ASSERT_EQ(1U, object_files.size()); - EXPECT_EQ(0x1a9d0518, object_files[0].cputype); - EXPECT_EQ(0x1b779357, object_files[0].cpusubtype); - EXPECT_EQ(0U, object_files[0].offset); - EXPECT_EQ(contents.size(), object_files[0].size); -} - -TEST_F(FatReaderTest, BigEndianMachO64) { - fat.set_endianness(kBigEndian); - fat - .D32(0xfeedfacf) // Mach-O 64-bit file magic number - .D32(0x5aff8487) // cpu type - .D32(0x4c6a57f7) // cpu subtype - .D32(0x4392d2c8) // file type - .D32(0) // no load commands - .D32(0) // the load commands occupy no bytes - .D32(0x1b033eea); // flags - - ReadFat(); - - // FatReader should treat a Mach-O file as if it were a fat binary file - // containing one object file --- the whole thing. - ASSERT_EQ(1U, object_files.size()); - EXPECT_EQ(0x5aff8487, object_files[0].cputype); - EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype); - EXPECT_EQ(0U, object_files[0].offset); - EXPECT_EQ(contents.size(), object_files[0].size); -} - -TEST_F(FatReaderTest, LittleEndianMachO32) { - fat.set_endianness(kLittleEndian); - fat - .D32(0xfeedface) // Mach-O file magic number - .D32(0x1a9d0518) // cpu type - .D32(0x1b779357) // cpu subtype - .D32(0x009df67e) // file type - .D32(0) // no load commands - .D32(0) // the load commands occupy no bytes - .D32(0x21987a99); // flags - - ReadFat(); - - // FatReader should treat a Mach-O file as if it were a fat binary file - // containing one object file --- the whole thing. - ASSERT_EQ(1U, object_files.size()); - EXPECT_EQ(0x1a9d0518, object_files[0].cputype); - EXPECT_EQ(0x1b779357, object_files[0].cpusubtype); - EXPECT_EQ(0U, object_files[0].offset); - EXPECT_EQ(contents.size(), object_files[0].size); -} - -TEST_F(FatReaderTest, LittleEndianMachO64) { - fat.set_endianness(kLittleEndian); - fat - .D32(0xfeedfacf) // Mach-O 64-bit file magic number - .D32(0x5aff8487) // cpu type - .D32(0x4c6a57f7) // cpu subtype - .D32(0x4392d2c8) // file type - .D32(0) // no load commands - .D32(0) // the load commands occupy no bytes - .D32(0x1b033eea); // flags - - ReadFat(); - - // FatReader should treat a Mach-O file as if it were a fat binary file - // containing one object file --- the whole thing. - ASSERT_EQ(1U, object_files.size()); - EXPECT_EQ(0x5aff8487, object_files[0].cputype); - EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype); - EXPECT_EQ(0U, object_files[0].offset); - EXPECT_EQ(contents.size(), object_files[0].size); -} - -TEST_F(FatReaderTest, IncompleteMach) { - fat.set_endianness(kLittleEndian); - fat - .D32(0xfeedfacf) // Mach-O 64-bit file magic number - .D32(0x5aff8487); // cpu type - // Truncated! - - EXPECT_CALL(reporter, TooShort()).WillOnce(Return()); - - ReadFat(false); -} - - -// General mach_o::Reader tests. - -// Dynamically scoped configuration data. -class WithConfiguration { - public: - // Establish the given parameters as the default for SizedSections - // created within the dynamic scope of this instance. - WithConfiguration(Endianness endianness, size_t word_size) - : endianness_(endianness), word_size_(word_size), saved_(current_) { - current_ = this; - } - ~WithConfiguration() { current_ = saved_; } - static Endianness endianness() { - assert(current_); - return current_->endianness_; - } - static size_t word_size() { - assert(current_); - return current_->word_size_; - } - - private: - // The innermost WithConfiguration in whose dynamic scope we are - // currently executing. - static WithConfiguration *current_; - - // The innermost WithConfiguration whose dynamic scope encloses this - // WithConfiguration. - Endianness endianness_; - size_t word_size_; - WithConfiguration *saved_; -}; - -WithConfiguration *WithConfiguration::current_ = NULL; - -// A test_assembler::Section with a size that we can cite. The start(), -// Here() and Mark() member functions of a SizedSection always represent -// offsets within the overall file. -class SizedSection: public test_assembler::Section { - public: - // Construct a section of the given endianness and word size. - explicit SizedSection(Endianness endianness, size_t word_size) - : test_assembler::Section(endianness), word_size_(word_size) { - assert(word_size_ == 32 || word_size_ == 64); - } - SizedSection() - : test_assembler::Section(WithConfiguration::endianness()), - word_size_(WithConfiguration::word_size()) { - assert(word_size_ == 32 || word_size_ == 64); - } - - // Access/set this section's word size. - size_t word_size() const { return word_size_; } - void set_word_size(size_t word_size) { - assert(word_size_ == 32 || word_size_ == 64); - word_size_ = word_size; - } - - // Return a label representing the size this section will have when it - // is Placed in some containing section. - Label final_size() const { return final_size_; } - - // Append SECTION to the end of this section, and call its Finish member. - // Return a reference to this section. - SizedSection &Place(SizedSection *section) { - assert(section->endianness() == endianness()); - section->Finish(); - section->start() = Here(); - test_assembler::Section::Append(*section); - return *this; - } - - protected: - // Mark this section's contents as complete. For plain SizedSections, we - // set SECTION's start to its position in this section, and its final_size - // label to its current size. Derived classes can extend this as needed - // for their additional semantics. - virtual void Finish() { - final_size_ = Size(); - } - - // The word size for this data: either 32 or 64. - size_t word_size_; - - private: - // This section's final size, set when we are placed in some other - // SizedSection. - Label final_size_; -}; - -// A SizedSection that is loaded into memory at a particular address. -class LoadedSection: public SizedSection { - public: - explicit LoadedSection(Label address = Label()) : address_(address) { } - - // Return a label representing this section's address. - Label address() const { return address_; } - - // Placing a loaded section within a loaded section sets the relationship - // between their addresses. - LoadedSection &Place(LoadedSection *section) { - section->address() = address() + Size(); - SizedSection::Place(section); - return *this; - } - - protected: - // The address at which this section's contents will be loaded. - Label address_; -}; - -// A SizedSection representing a segment load command. -class SegmentLoadCommand: public SizedSection { - public: - SegmentLoadCommand() : section_count_(0) { } - - // Append a segment load command header with the given characteristics. - // The load command will refer to CONTENTS, which must be Placed in the - // file separately, at the desired position. Return a reference to this - // section. - SegmentLoadCommand &Header(const string &name, const LoadedSection &contents, - uint32_t maxprot, uint32_t initprot, - uint32_t flags) { - assert(contents.word_size() == word_size()); - D32(word_size() == 32 ? LC_SEGMENT : LC_SEGMENT_64); - D32(final_size()); - AppendCString(name, 16); - Append(endianness(), word_size() / 8, contents.address()); - Append(endianness(), word_size() / 8, vmsize_); - Append(endianness(), word_size() / 8, contents.start()); - Append(endianness(), word_size() / 8, contents.final_size()); - D32(maxprot); - D32(initprot); - D32(final_section_count_); - D32(flags); - - content_final_size_ = contents.final_size(); - - return *this; - } - - // Return a label representing the size of this segment when loaded into - // memory. If this label is still undefined by the time we place this - // segment, it defaults to the final size of the segment's in-file - // contents. Return a reference to this load command. - Label &vmsize() { return vmsize_; } - - // Add a section entry with the given characteristics to this segment - // load command. Return a reference to this. The section entry will refer - // to CONTENTS, which must be Placed in the segment's contents - // separately, at the desired position. - SegmentLoadCommand &AppendSectionEntry(const string §ion_name, - const string &segment_name, - uint32_t alignment, uint32_t flags, - const LoadedSection &contents) { - AppendCString(section_name, 16); - AppendCString(segment_name, 16); - Append(endianness(), word_size() / 8, contents.address()); - Append(endianness(), word_size() / 8, contents.final_size()); - D32(contents.start()); - D32(alignment); - D32(0); // relocations start - D32(0); // relocations size - D32(flags); - D32(0x93656b95); // reserved1 - D32(0xc35a2473); // reserved2 - if (word_size() == 64) - D32(0x70284b95); // reserved3 - - section_count_++; - - return *this; - } - - protected: - void Finish() { - final_section_count_ = section_count_; - if (!vmsize_.IsKnownConstant()) - vmsize_ = content_final_size_; - SizedSection::Finish(); - } - - private: - // The number of sections that have been added to this segment so far. - size_t section_count_; - - // A label representing the final number of sections this segment will hold. - Label final_section_count_; - - // The size of the contents for this segment present in the file. - Label content_final_size_; - - // A label representing the size of this segment when loaded; this can be - // larger than the size of its file contents, the difference being - // zero-filled. If not set explicitly by calling set_vmsize, this is set - // equal to the size of the contents. - Label vmsize_; -}; - -// A SizedSection holding a list of Mach-O load commands. -class LoadCommands: public SizedSection { - public: - LoadCommands() : command_count_(0) { } - - // Return a label representing the final load command count. - Label final_command_count() const { return final_command_count_; } - - // Increment the command count; return a reference to this section. - LoadCommands &CountCommand() { - command_count_++; - return *this; - } - - // Place COMMAND, containing a load command, at the end of this section. - // Return a reference to this section. - LoadCommands &Place(SizedSection *section) { - SizedSection::Place(section); - CountCommand(); - return *this; - } - - protected: - // Mark this load command list as complete. - void Finish() { - SizedSection::Finish(); - final_command_count_ = command_count_; - } - - private: - // The number of load commands we have added to this file so far. - size_t command_count_; - - // A label representing the final command count. - Label final_command_count_; -}; - -// A SizedSection holding the contents of a Mach-O file. Within a -// MachOFile, the start, Here, and Mark members refer to file offsets. -class MachOFile: public SizedSection { - public: - MachOFile() { - start() = 0; - } - - // Create a Mach-O file header using the given characteristics and load - // command list. This Places COMMANDS immediately after the header. - // Return a reference to this section. - MachOFile &Header(LoadCommands *commands, - cpu_type_t cpu_type = CPU_TYPE_X86, - cpu_subtype_t cpu_subtype = CPU_SUBTYPE_I386_ALL, - FileType file_type = MH_EXECUTE, - uint32_t file_flags = (MH_TWOLEVEL | - MH_DYLDLINK | - MH_NOUNDEFS)) { - D32(word_size() == 32 ? 0xfeedface : 0xfeedfacf); // magic number - D32(cpu_type); // cpu type - D32(cpu_subtype); // cpu subtype - D32(file_type); // file type - D32(commands->final_command_count()); // number of load commands - D32(commands->final_size()); // their size in bytes - D32(file_flags); // flags - if (word_size() == 64) - D32(0x55638b90); // reserved - Place(commands); - return *this; - } -}; - - -struct ReaderFixture { - ReaderFixture() - : reporter("reporter filename"), - reader(&reporter) { - EXPECT_CALL(reporter, BadHeader()).Times(0); - EXPECT_CALL(reporter, CPUTypeMismatch(_, _, _, _)).Times(0); - EXPECT_CALL(reporter, HeaderTruncated()).Times(0); - EXPECT_CALL(reporter, LoadCommandRegionTruncated()).Times(0); - EXPECT_CALL(reporter, LoadCommandsOverrun(_, _, _)).Times(0); - EXPECT_CALL(reporter, LoadCommandTooShort(_, _)).Times(0); - EXPECT_CALL(reporter, SectionsMissing(_)).Times(0); - EXPECT_CALL(reporter, MisplacedSegmentData(_)).Times(0); - EXPECT_CALL(reporter, MisplacedSectionData(_, _)).Times(0); - EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(0); - EXPECT_CALL(reporter, UnsupportedCPUType(_)).Times(0); - - EXPECT_CALL(load_command_handler, UnknownCommand(_, _)).Times(0); - EXPECT_CALL(load_command_handler, SegmentCommand(_)).Times(0); - } - - void ReadFile(MachOFile *file, - bool expect_parse_success, - cpu_type_t expected_cpu_type, - cpu_subtype_t expected_cpu_subtype) { - ASSERT_TRUE(file->GetContents(&file_contents)); - file_bytes = reinterpret_cast<const uint8_t *>(file_contents.data()); - if (expect_parse_success) { - EXPECT_TRUE(reader.Read(file_bytes, - file_contents.size(), - expected_cpu_type, - expected_cpu_subtype)); - } else { - EXPECT_FALSE(reader.Read(file_bytes, - file_contents.size(), - expected_cpu_type, - expected_cpu_subtype)); - } - } - - string file_contents; - const uint8_t *file_bytes; - MockReaderReporter reporter; - Reader reader; - MockLoadCommandHandler load_command_handler; - MockSectionHandler section_handler; -}; - -class ReaderTest: public ReaderFixture, public Test { }; - -TEST_F(ReaderTest, BadMagic) { - WithConfiguration config(kLittleEndian, 32); - const cpu_type_t kCPUType = 0x46b760df; - const cpu_subtype_t kCPUSubType = 0x76a0e7f7; - MachOFile file; - file - .D32(0x67bdebe1) // Not a proper magic number. - .D32(kCPUType) // cpu type - .D32(kCPUSubType) // cpu subtype - .D32(0x149fc717) // file type - .D32(0) // no load commands - .D32(0) // they occupy no bytes - .D32(0x80e71d64) // flags - .D32(0); // reserved - EXPECT_CALL(reporter, BadHeader()).WillOnce(Return()); - ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType); -} - -TEST_F(ReaderTest, MismatchedMagic) { - WithConfiguration config(kLittleEndian, 32); - const cpu_type_t kCPUType = CPU_TYPE_I386; - const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL; - MachOFile file; - file - .D32(MH_CIGAM) // Right magic, but winds up wrong - // due to bitswapping - .D32(kCPUType) // cpu type - .D32(kCPUSubType) // cpu subtype - .D32(0x149fc717) // file type - .D32(0) // no load commands - .D32(0) // they occupy no bytes - .D32(0x80e71d64) // flags - .D32(0); // reserved - EXPECT_CALL(reporter, BadHeader()).WillOnce(Return()); - ReadFile(&file, false, kCPUType, kCPUSubType); -} - -TEST_F(ReaderTest, ShortMagic) { - WithConfiguration config(kBigEndian, 32); - MachOFile file; - file - .D16(0xfeed); // magic number - // truncated! - EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return()); - ReadFile(&file, false, CPU_TYPE_ANY, 0); -} - -TEST_F(ReaderTest, ShortHeader) { - WithConfiguration config(kBigEndian, 32); - const cpu_type_t kCPUType = CPU_TYPE_ANY; - const cpu_subtype_t kCPUSubType = 0x76a0e7f7; - MachOFile file; - file - .D32(0xfeedface) // magic number - .D32(kCPUType) // cpu type - .D32(kCPUSubType) // cpu subtype - .D32(0x149fc717) // file type - .D32(0) // no load commands - .D32(0); // they occupy no bytes - EXPECT_CALL(reporter, HeaderTruncated()).WillOnce(Return()); - ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType); -} - -TEST_F(ReaderTest, MismatchedCPU) { - WithConfiguration config(kBigEndian, 32); - const cpu_type_t kCPUType = CPU_TYPE_I386; - const cpu_subtype_t kCPUSubType = CPU_SUBTYPE_X86_ALL; - MachOFile file; - file - .D32(MH_MAGIC) // Right magic for PPC (once bitswapped) - .D32(kCPUType) // cpu type - .D32(kCPUSubType) // cpu subtype - .D32(0x149fc717) // file type - .D32(0) // no load commands - .D32(0) // they occupy no bytes - .D32(0x80e71d64) // flags - .D32(0); // reserved - EXPECT_CALL(reporter, - CPUTypeMismatch(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, - CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL)) - .WillOnce(Return()); - ReadFile(&file, false, CPU_TYPE_POWERPC, CPU_SUBTYPE_POWERPC_ALL); -} - -TEST_F(ReaderTest, LittleEndian32Bit) { - WithConfiguration config(kLittleEndian, 32); - const cpu_type_t kCPUType = 0x46b760df; - const cpu_subtype_t kCPUSubType = 0x76a0e7f7; - MachOFile file; - file - .D32(0xfeedface) // magic number - .D32(kCPUType) // cpu type - .D32(kCPUSubType) // cpu subtype - .D32(0x149fc717) // file type - .D32(0) // no load commands - .D32(0) // they occupy no bytes - .D32(0x80e71d64) // flags - .D32(0); // reserved - ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType); - EXPECT_FALSE(reader.bits_64()); - EXPECT_FALSE(reader.big_endian()); - EXPECT_EQ(kCPUType, reader.cpu_type()); - EXPECT_EQ(kCPUSubType, reader.cpu_subtype()); - EXPECT_EQ(FileType(0x149fc717), reader.file_type()); - EXPECT_EQ(FileFlags(0x80e71d64), reader.flags()); -} - -TEST_F(ReaderTest, LittleEndian64Bit) { - WithConfiguration config(kLittleEndian, 64); - const cpu_type_t kCPUType = 0x46b760df; - const cpu_subtype_t kCPUSubType = 0x76a0e7f7; - MachOFile file; - file - .D32(0xfeedfacf) // magic number - .D32(kCPUType) // cpu type - .D32(kCPUSubType) // cpu subtype - .D32(0x149fc717) // file type - .D32(0) // no load commands - .D32(0) // they occupy no bytes - .D32(0x80e71d64) // flags - .D32(0); // reserved - ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType); - EXPECT_TRUE(reader.bits_64()); - EXPECT_FALSE(reader.big_endian()); - EXPECT_EQ(kCPUType, reader.cpu_type()); - EXPECT_EQ(kCPUSubType, reader.cpu_subtype()); - EXPECT_EQ(FileType(0x149fc717), reader.file_type()); - EXPECT_EQ(FileFlags(0x80e71d64), reader.flags()); -} - -TEST_F(ReaderTest, BigEndian32Bit) { - WithConfiguration config(kBigEndian, 32); - const cpu_type_t kCPUType = 0x46b760df; - const cpu_subtype_t kCPUSubType = 0x76a0e7f7; - MachOFile file; - file - .D32(0xfeedface) // magic number - .D32(kCPUType) // cpu type - .D32(kCPUSubType) // cpu subtype - .D32(0x149fc717) // file type - .D32(0) // no load commands - .D32(0) // they occupy no bytes - .D32(0x80e71d64) // flags - .D32(0); // reserved - ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType); - EXPECT_FALSE(reader.bits_64()); - EXPECT_TRUE(reader.big_endian()); - EXPECT_EQ(kCPUType, reader.cpu_type()); - EXPECT_EQ(kCPUSubType, reader.cpu_subtype()); - EXPECT_EQ(FileType(0x149fc717), reader.file_type()); - EXPECT_EQ(FileFlags(0x80e71d64), reader.flags()); -} - -TEST_F(ReaderTest, BigEndian64Bit) { - WithConfiguration config(kBigEndian, 64); - const cpu_type_t kCPUType = 0x46b760df; - const cpu_subtype_t kCPUSubType = 0x76a0e7f7; - MachOFile file; - file - .D32(0xfeedfacf) // magic number - .D32(kCPUType) // cpu type - .D32(kCPUSubType) // cpu subtype - .D32(0x149fc717) // file type - .D32(0) // no load commands - .D32(0) // they occupy no bytes - .D32(0x80e71d64) // flags - .D32(0); // reserved - ReadFile(&file, true, CPU_TYPE_ANY, kCPUSubType); - EXPECT_TRUE(reader.bits_64()); - EXPECT_TRUE(reader.big_endian()); - EXPECT_EQ(kCPUType, reader.cpu_type()); - EXPECT_EQ(kCPUSubType, reader.cpu_subtype()); - EXPECT_EQ(FileType(0x149fc717), reader.file_type()); - EXPECT_EQ(FileFlags(0x80e71d64), reader.flags()); -} - - -// Load command tests. - -class LoadCommand: public ReaderFixture, public Test { }; - -TEST_F(LoadCommand, RegionTruncated) { - WithConfiguration config(kBigEndian, 64); - const cpu_type_t kCPUType = 0x46b760df; - const cpu_subtype_t kCPUSubType = 0x76a0e7f7; - MachOFile file; - file - .D32(0xfeedfacf) // magic number - .D32(kCPUType) // cpu type - .D32(kCPUSubType) // cpu subtype - .D32(0x149fc717) // file type - .D32(1) // one load command - .D32(40) // occupying 40 bytes - .D32(0x80e71d64) // flags - .D32(0) // reserved - .Append(20, 0); // load command region, not as long as - // Mach-O header promised - - EXPECT_CALL(reporter, LoadCommandRegionTruncated()).WillOnce(Return()); - - ReadFile(&file, false, CPU_TYPE_ANY, kCPUSubType); -} - -TEST_F(LoadCommand, None) { - WithConfiguration config(kLittleEndian, 32); - LoadCommands load_commands; - MachOFile file; - file.Header(&load_commands); - - ReadFile(&file, true, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL); - - EXPECT_FALSE(reader.bits_64()); - EXPECT_FALSE(reader.big_endian()); - EXPECT_EQ(CPU_TYPE_X86, reader.cpu_type()); - EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype()); - EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type()); - EXPECT_EQ(FileFlags(MH_TWOLEVEL | - MH_DYLDLINK | - MH_NOUNDEFS), - FileFlags(reader.flags())); - - EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); -} - -TEST_F(LoadCommand, Unknown) { - WithConfiguration config(kBigEndian, 32); - LoadCommands load_commands; - load_commands - .CountCommand() - .D32(0x33293d4a) // unknown load command - .D32(40) // total size in bytes - .Append(32, '*'); // dummy data - MachOFile file; - file.Header(&load_commands); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - EXPECT_FALSE(reader.bits_64()); - EXPECT_TRUE(reader.big_endian()); - EXPECT_EQ(CPU_TYPE_X86, reader.cpu_type()); - EXPECT_EQ(CPU_SUBTYPE_I386_ALL, reader.cpu_subtype()); - EXPECT_EQ(static_cast<uint32_t>(MH_EXECUTE), reader.file_type()); - EXPECT_EQ(FileFlags(MH_TWOLEVEL | - MH_DYLDLINK | - MH_NOUNDEFS), - reader.flags()); - - ByteBuffer expected; - expected.start = file_bytes + load_commands.start().Value(); - expected.end = expected.start + load_commands.final_size().Value(); - EXPECT_CALL(load_command_handler, UnknownCommand(0x33293d4a, - expected)) - .WillOnce(Return(true)); - - EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); -} - -TEST_F(LoadCommand, TypeIncomplete) { - WithConfiguration config(kLittleEndian, 32); - LoadCommands load_commands; - load_commands - .CountCommand() - .Append(3, 0); // load command type, incomplete - - MachOFile file; - file.Header(&load_commands); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, 0)) - .WillOnce(Return()); - EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); -} - -TEST_F(LoadCommand, LengthIncomplete) { - WithConfiguration config(kBigEndian, 64); - LoadCommands load_commands; - load_commands - .CountCommand() - .D32(LC_SEGMENT); // load command - // no length - MachOFile file; - file.Header(&load_commands); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT)) - .WillOnce(Return()); - EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); -} - -TEST_F(LoadCommand, ContentIncomplete) { - WithConfiguration config(kLittleEndian, 64); - LoadCommands load_commands; - load_commands - .CountCommand() - .D32(LC_SEGMENT) // load command - .D32(40) // total size in bytes - .Append(28, '*'); // not enough dummy data - MachOFile file; - file.Header(&load_commands); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - EXPECT_CALL(reporter, LoadCommandsOverrun(1, 0, LC_SEGMENT)) - .WillOnce(Return()); - EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); -} - -TEST_F(LoadCommand, SegmentBE32) { - WithConfiguration config(kBigEndian, 32); - LoadedSection segment; - segment.address() = 0x1891139c; - segment.Append(42, '*'); // segment contents - SegmentLoadCommand segment_command; - segment_command - .Header("froon", segment, 0x94d6dd22, 0x8bdbc319, 0x990a16dd); - segment_command.vmsize() = 0xcb76584fU; - LoadCommands load_commands; - load_commands.Place(&segment_command); - MachOFile file; - file - .Header(&load_commands) - .Place(&segment); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - Segment actual_segment; - EXPECT_CALL(load_command_handler, SegmentCommand(_)) - .WillOnce(DoAll(SaveArg<0>(&actual_segment), - Return(true))); - EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); - - EXPECT_EQ(false, actual_segment.bits_64); - EXPECT_EQ("froon", actual_segment.name); - EXPECT_EQ(0x1891139cU, actual_segment.vmaddr); - EXPECT_EQ(0xcb76584fU, actual_segment.vmsize); - EXPECT_EQ(0x94d6dd22U, actual_segment.maxprot); - EXPECT_EQ(0x8bdbc319U, actual_segment.initprot); - EXPECT_EQ(0x990a16ddU, actual_segment.flags); - EXPECT_EQ(0U, actual_segment.nsects); - EXPECT_EQ(0U, actual_segment.section_list.Size()); - EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size()); -} - -TEST_F(LoadCommand, SegmentLE32) { - WithConfiguration config(kLittleEndian, 32); - LoadedSection segment; - segment.address() = 0x4b877866; - segment.Append(42, '*'); // segment contents - SegmentLoadCommand segment_command; - segment_command - .Header("sixteenprecisely", segment, - 0x350759ed, 0x6cf5a62e, 0x990a16dd); - segment_command.vmsize() = 0xcb76584fU; - LoadCommands load_commands; - load_commands.Place(&segment_command); - MachOFile file; - file - .Header(&load_commands) - .Place(&segment); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - Segment actual_segment; - EXPECT_CALL(load_command_handler, SegmentCommand(_)) - .WillOnce(DoAll(SaveArg<0>(&actual_segment), - Return(true))); - EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); - - EXPECT_EQ(false, actual_segment.bits_64); - EXPECT_EQ("sixteenprecisely", actual_segment.name); - EXPECT_EQ(0x4b877866U, actual_segment.vmaddr); - EXPECT_EQ(0xcb76584fU, actual_segment.vmsize); - EXPECT_EQ(0x350759edU, actual_segment.maxprot); - EXPECT_EQ(0x6cf5a62eU, actual_segment.initprot); - EXPECT_EQ(0x990a16ddU, actual_segment.flags); - EXPECT_EQ(0U, actual_segment.nsects); - EXPECT_EQ(0U, actual_segment.section_list.Size()); - EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size()); -} - -TEST_F(LoadCommand, SegmentBE64) { - WithConfiguration config(kBigEndian, 64); - LoadedSection segment; - segment.address() = 0x79f484f77009e511ULL; - segment.Append(42, '*'); // segment contents - SegmentLoadCommand segment_command; - segment_command - .Header("froon", segment, 0x42b45da5, 0x8bdbc319, 0xb2335220); - segment_command.vmsize() = 0x8d92397ce6248abaULL; - LoadCommands load_commands; - load_commands.Place(&segment_command); - MachOFile file; - file - .Header(&load_commands) - .Place(&segment); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - Segment actual_segment; - EXPECT_CALL(load_command_handler, SegmentCommand(_)) - .WillOnce(DoAll(SaveArg<0>(&actual_segment), - Return(true))); - EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); - - EXPECT_EQ(true, actual_segment.bits_64); - EXPECT_EQ("froon", actual_segment.name); - EXPECT_EQ(0x79f484f77009e511ULL, actual_segment.vmaddr); - EXPECT_EQ(0x8d92397ce6248abaULL, actual_segment.vmsize); - EXPECT_EQ(0x42b45da5U, actual_segment.maxprot); - EXPECT_EQ(0x8bdbc319U, actual_segment.initprot); - EXPECT_EQ(0xb2335220U, actual_segment.flags); - EXPECT_EQ(0U, actual_segment.nsects); - EXPECT_EQ(0U, actual_segment.section_list.Size()); - EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size()); -} - -TEST_F(LoadCommand, SegmentLE64) { - WithConfiguration config(kLittleEndian, 64); - LoadedSection segment; - segment.address() = 0x50c0501dc5922d35ULL; - segment.Append(42, '*'); // segment contents - SegmentLoadCommand segment_command; - segment_command - .Header("sixteenprecisely", segment, - 0x917c339d, 0xdbc446fa, 0xb650b563); - segment_command.vmsize() = 0x84ae73e7c75469bfULL; - LoadCommands load_commands; - load_commands.Place(&segment_command); - MachOFile file; - file - .Header(&load_commands) - .Place(&segment); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - Segment actual_segment; - EXPECT_CALL(load_command_handler, SegmentCommand(_)) - .WillOnce(DoAll(SaveArg<0>(&actual_segment), - Return(true))); - EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); - - EXPECT_EQ(true, actual_segment.bits_64); - EXPECT_EQ("sixteenprecisely", actual_segment.name); - EXPECT_EQ(0x50c0501dc5922d35ULL, actual_segment.vmaddr); - EXPECT_EQ(0x84ae73e7c75469bfULL, actual_segment.vmsize); - EXPECT_EQ(0x917c339dU, actual_segment.maxprot); - EXPECT_EQ(0xdbc446faU, actual_segment.initprot); - EXPECT_EQ(0xb650b563U, actual_segment.flags); - EXPECT_EQ(0U, actual_segment.nsects); - EXPECT_EQ(0U, actual_segment.section_list.Size()); - EXPECT_EQ(segment.final_size().Value(), actual_segment.contents.Size()); -} - -TEST_F(LoadCommand, SegmentCommandTruncated) { - WithConfiguration config(kBigEndian, 32); - LoadedSection segment_contents; - segment_contents.Append(20, '*'); // lah di dah - SizedSection command; - command - .D32(LC_SEGMENT) // command type - .D32(command.final_size()) // command size - .AppendCString("too-short", 16) // segment name - .D32(0x9c759211) // vmaddr - .D32(segment_contents.final_size()) // vmsize - .D32(segment_contents.start()) // file offset - .D32(segment_contents.final_size()) // file size - .D32(0x56f28446) // max protection - .D32(0xe7910dcb) // initial protection - .D32(0) // no sections - .Append(3, 0); // flags (one byte short!) - LoadCommands load_commands; - load_commands.Place(&command); - MachOFile file; - file - .Header(&load_commands) - .Place(&segment_contents); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - EXPECT_CALL(reporter, LoadCommandTooShort(0, LC_SEGMENT)) - .WillOnce(Return()); - - EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); -} - -TEST_F(LoadCommand, SegmentBadContentOffset) { - WithConfiguration config(kLittleEndian, 32); - // Instead of letting a Place call set the segment's file offset and size, - // set them ourselves, to check that the parser catches invalid offsets - // instead of handing us bogus pointers. - LoadedSection segment; - segment.address() = 0x4db5489c; - segment.start() = 0x7e189e76; // beyond end of file - segment.final_size() = 0x98b9c3ab; - SegmentLoadCommand segment_command; - segment_command - .Header("notmerelyfifteen", segment, 0xcbab25ee, 0x359a20db, 0x68a3933f); - LoadCommands load_commands; - load_commands.Place(&segment_command); - MachOFile file; - file.Header(&load_commands); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - EXPECT_CALL(reporter, MisplacedSegmentData("notmerelyfifteen")) - .WillOnce(Return()); - - EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); -} - -TEST_F(LoadCommand, ThreeLoadCommands) { - WithConfiguration config(kBigEndian, 32); - LoadedSection seg1, seg2, seg3; - SegmentLoadCommand cmd1, cmd2, cmd3; - - seg1.Append(128, '@'); - seg1.address() = 0xa7f61ef6; - cmd1.Header("head", seg1, 0x88bf1cc7, 0x889a26a4, 0xe9b80d87); - // Include some dummy data at the end of the load command. Since we - // didn't claim to have any sections, the reader should ignore this. But - // making sure the commands have different lengths ensures that we're - // using the right command's length to advance the LoadCommandIterator. - cmd1.Append(128, '!'); - - seg2.Append(42, '*'); - seg2.address() = 0xc70fc909; - cmd2.Header("thorax", seg2, 0xde7327f4, 0xfdaf771d, 0x65e74b30); - // More dummy data at the end of the load command. - cmd2.Append(32, '^'); - - seg3.Append(42, '%'); - seg3.address() = 0x46b3ab05; - cmd3.Header("abdomen", seg3, 0x7098b70d, 0x8d8d7728, 0x5131419b); - // More dummy data at the end of the load command. - cmd3.Append(64, '&'); - - LoadCommands load_commands; - load_commands.Place(&cmd1).Place(&cmd2).Place(&cmd3); - - MachOFile file; - file.Header(&load_commands).Place(&seg1).Place(&seg2).Place(&seg3); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - { - InSequence s; - EXPECT_CALL(load_command_handler, - SegmentCommand(Field(&Segment::name, "head"))) - .WillOnce(Return(true)); - EXPECT_CALL(load_command_handler, - SegmentCommand(Field(&Segment::name, "thorax"))) - .WillOnce(Return(true)); - EXPECT_CALL(load_command_handler, - SegmentCommand(Field(&Segment::name, "abdomen"))) - .WillOnce(Return(true)); - } - - EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); -} - -static inline Matcher<const Section &> MatchSection( - Matcher<bool> bits_64, - Matcher<const string &> section_name, - Matcher<const string &> segment_name, - Matcher<uint64_t> address, - Matcher<uint32_t> alignment, - Matcher<uint32_t> flags, - Matcher<const ByteBuffer &> contents) { - return AllOf(AllOf(Field(&Section::bits_64, bits_64), - Field(&Section::section_name, section_name), - Field(&Section::segment_name, segment_name), - Field(&Section::address, address)), - AllOf(Field(&Section::align, alignment), - Field(&Section::flags, flags), - Field(&Section::contents, contents))); -} - -static inline Matcher<const Section &> MatchSection( - Matcher<bool> bits_64, - Matcher<const string &> section_name, - Matcher<const string &> segment_name, - Matcher<uint64_t> address) { - return AllOf(Field(&Section::bits_64, bits_64), - Field(&Section::section_name, section_name), - Field(&Section::segment_name, segment_name), - Field(&Section::address, address)); -} - -TEST_F(LoadCommand, OneSegmentTwoSections) { - WithConfiguration config(kBigEndian, 64); - - // Create some sections with some data. - LoadedSection section1, section2; - section1.Append("buddha's hand"); - section2.Append("kumquat"); - - // Create a segment to hold them. - LoadedSection segment; - segment.address() = 0xe1d0eeec; - segment.Place(§ion2).Place(§ion1); - - SegmentLoadCommand segment_command; - segment_command - .Header("head", segment, 0x92c9568c, 0xa89f2627, 0x4dc7a1e2) - .AppendSectionEntry("mandarin", "kishu", 12, 0x8cd4604bU, section1) - .AppendSectionEntry("bergamot", "cara cara", 12, 0x98746efaU, section2); - - LoadCommands commands; - commands.Place(&segment_command); - - MachOFile file; - file.Header(&commands).Place(&segment); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - Segment actual_segment; - EXPECT_CALL(load_command_handler, SegmentCommand(_)) - .WillOnce(DoAll(SaveArg<0>(&actual_segment), - Return(true))); - EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); - - { - InSequence s; - ByteBuffer contents1; - contents1.start = file_bytes + section1.start().Value(); - contents1.end = contents1.start + section1.final_size().Value(); - EXPECT_EQ("buddha's hand", - string(reinterpret_cast<const char *>(contents1.start), - contents1.Size())); - EXPECT_CALL(section_handler, - HandleSection(MatchSection(true, "mandarin", "kishu", - section1.address().Value(), 12, - 0x8cd4604bU, contents1))) - .WillOnce(Return(true)); - - ByteBuffer contents2; - contents2.start = file_bytes + section2.start().Value(); - contents2.end = contents2.start + section2.final_size().Value(); - EXPECT_EQ("kumquat", - string(reinterpret_cast<const char *>(contents2.start), - contents2.Size())); - EXPECT_CALL(section_handler, - HandleSection(MatchSection(true, "bergamot", "cara cara", - section2.address().Value(), 12, - 0x98746efaU, contents2))) - .WillOnce(Return(true)); - } - - EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, §ion_handler)); -} - -TEST_F(LoadCommand, MisplacedSectionBefore) { - WithConfiguration config(kLittleEndian, 64); - - // The segment. - LoadedSection segment; - segment.address() = 0x696d83cc; - segment.Append(10, '0'); - - // The contents of the following sections don't matter, because - // we're not really going to Place them in segment; we're just going - // to set all their labels by hand to get the (impossible) - // configurations we want. - - // A section whose starting offset is before that of its section. - LoadedSection before; - before.Append(10, '1'); - before.start() = segment.start() - 1; - before.address() = segment.address() - 1; - before.final_size() = before.Size(); - - SegmentLoadCommand command; - command - .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057) - .AppendSectionEntry("before", "segment", 0, 0x686c6921, before); - - LoadCommands commands; - commands.Place(&command); - - MachOFile file; - file.Header(&commands).Place(&segment); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - Segment actual_segment; - EXPECT_TRUE(reader.FindSegment("segment", &actual_segment)); - - EXPECT_CALL(reporter, MisplacedSectionData("before", "segment")) - .WillOnce(Return()); - EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, §ion_handler)); -} - -TEST_F(LoadCommand, MisplacedSectionAfter) { - WithConfiguration config(kLittleEndian, 64); - - // The segment. - LoadedSection segment; - segment.address() = 0x696d83cc; - segment.Append(10, '0'); - - // The contents of the following sections don't matter, because - // we're not really going to Place them in segment; we're just going - // to set all their labels by hand to get the (impossible) - // configurations we want. - - // A section whose starting offset is after the end of its section. - LoadedSection after; - after.Append(10, '2'); - after.start() = segment.start() + 11; - after.address() = segment.address() + 11; - after.final_size() = after.Size(); - - SegmentLoadCommand command; - command - .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057) - .AppendSectionEntry("after", "segment", 0, 0x2ee50124, after); - - LoadCommands commands; - commands.Place(&command); - - MachOFile file; - file.Header(&commands).Place(&segment); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - Segment actual_segment; - EXPECT_TRUE(reader.FindSegment("segment", &actual_segment)); - - EXPECT_CALL(reporter, MisplacedSectionData("after", "segment")) - .WillOnce(Return()); - EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, §ion_handler)); -} - -TEST_F(LoadCommand, MisplacedSectionTooBig) { - WithConfiguration config(kLittleEndian, 64); - - // The segment. - LoadedSection segment; - segment.address() = 0x696d83cc; - segment.Append(10, '0'); - - // The contents of the following sections don't matter, because - // we're not really going to Place them in segment; we're just going - // to set all their labels by hand to get the (impossible) - // configurations we want. - - // A section that extends beyond the end of its section. - LoadedSection too_big; - too_big.Append(10, '3'); - too_big.start() = segment.start() + 1; - too_big.address() = segment.address() + 1; - too_big.final_size() = too_big.Size(); - - SegmentLoadCommand command; - command - .Header("segment", segment, 0x173baa29, 0x8407275d, 0xed8f7057) - .AppendSectionEntry("too big", "segment", 0, 0x8b53ae5c, too_big); - - LoadCommands commands; - commands.Place(&command); - - MachOFile file; - file.Header(&commands).Place(&segment); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - Segment actual_segment; - EXPECT_TRUE(reader.FindSegment("segment", &actual_segment)); - - EXPECT_CALL(reporter, MisplacedSectionData("too big", "segment")) - .WillOnce(Return()); - EXPECT_FALSE(reader.WalkSegmentSections(actual_segment, §ion_handler)); -} - - -// The segments in a .dSYM bundle's Mach-O file have their file offset -// and size set to zero, but the sections don't. The reader shouldn't -// report an error in this case. -TEST_F(LoadCommand, ZappedSegment) { - WithConfiguration config(kBigEndian, 32); - - // The segment. - LoadedSection segment; - segment.address() = 0x696d83cc; - segment.start() = 0; - segment.final_size() = 0; - - // The section. - LoadedSection section; - section.address() = segment.address(); - section.start() = 0; - section.final_size() = 1000; // extends beyond its segment - - SegmentLoadCommand command; - command - .Header("zapped", segment, 0x0861a5cb, 0x68ccff67, 0x0b66255c) - .AppendSectionEntry("twitching", "zapped", 0, 0x93b3bd42, section); - - LoadCommands commands; - commands.Place(&command); - - MachOFile file; - file.Header(&commands); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - Segment actual_segment; - EXPECT_TRUE(reader.FindSegment("zapped", &actual_segment)); - - ByteBuffer zapped_extent(NULL, 0); - EXPECT_CALL(section_handler, - HandleSection(MatchSection(false, "twitching", "zapped", - 0x696d83cc, 0, 0x93b3bd42, - zapped_extent))) - .WillOnce(Return(true)); - - EXPECT_TRUE(reader.WalkSegmentSections(actual_segment, §ion_handler)); -} - -TEST_F(LoadCommand, MapSegmentSections) { - WithConfiguration config(kLittleEndian, 32); - - // Create some sections with some data. - LoadedSection section1, section2, section3, section4; - section1.Append("buddha's hand"); - section2.start() = 0; // Section 2 is an S_ZEROFILL section. - section2.final_size() = 0; - section3.Append("shasta gold"); - section4.Append("satsuma"); - - // Create two segments to hold them. - LoadedSection segment1, segment2; - segment1.address() = 0x13e6c8a9; - segment1.Place(§ion3).Place(§ion1); - segment2.set_word_size(64); - segment2.address() = 0x04d462e2; - segment2.Place(§ion4); - section2.address() = segment2.address() + segment2.Size(); - - SegmentLoadCommand segment_command1, segment_command2; - segment_command1 - .Header("head", segment1, 0x67d955a6, 0x7a61c13e, 0xe3e50c64) - .AppendSectionEntry("mandarin", "head", 12, 0x5bb565d7, section1) - .AppendSectionEntry("bergamot", "head", 12, 0x8620de73, section3); - segment_command2.set_word_size(64); - segment_command2 - .Header("thorax", segment2, 0x7aab2419, 0xe908007f, 0x17961d33) - .AppendSectionEntry("sixteenprecisely", "thorax", - 12, S_ZEROFILL, section2) - .AppendSectionEntry("cara cara", "thorax", 12, 0xb6c5dd8a, section4); - - LoadCommands commands; - commands.Place(&segment_command1).Place(&segment_command2); - - MachOFile file; - file.Header(&commands).Place(&segment1).Place(&segment2); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - Segment segment; - SectionMap section_map; - - EXPECT_FALSE(reader.FindSegment("smoot", &segment)); - - ASSERT_TRUE(reader.FindSegment("thorax", &segment)); - ASSERT_TRUE(reader.MapSegmentSections(segment, §ion_map)); - - EXPECT_FALSE(section_map.find("sixteenpreciselyandthensome") - != section_map.end()); - EXPECT_FALSE(section_map.find("mandarin") != section_map.end()); - ASSERT_TRUE(section_map.find("cara cara") != section_map.end()); - EXPECT_THAT(section_map["cara cara"], - MatchSection(true, "cara cara", "thorax", 0x04d462e2)); - ASSERT_TRUE(section_map.find("sixteenprecisely") - != section_map.end()); - ByteBuffer sixteenprecisely_contents(NULL, 0); - EXPECT_THAT(section_map["sixteenprecisely"], - MatchSection(true, "sixteenprecisely", "thorax", - 0x04d462e2 + 7, 12, S_ZEROFILL, - sixteenprecisely_contents)); - - ASSERT_TRUE(reader.FindSegment("head", &segment)); - ASSERT_TRUE(reader.MapSegmentSections(segment, §ion_map)); - - ASSERT_TRUE(section_map.find("mandarin") != section_map.end()); - EXPECT_THAT(section_map["mandarin"], - MatchSection(false, "mandarin", "head", 0x13e6c8a9 + 11)); - ASSERT_TRUE(section_map.find("bergamot") != section_map.end()); - EXPECT_THAT(section_map["bergamot"], - MatchSection(false, "bergamot", "head", 0x13e6c8a9)); -} - -TEST_F(LoadCommand, FindSegment) { - WithConfiguration config(kBigEndian, 32); - - LoadedSection segment1, segment2, segment3; - segment1.address() = 0xb8ae5752; - segment1.Append("Some contents!"); - segment2.address() = 0xd6b0ce83; - segment2.Append("Different stuff."); - segment3.address() = 0x7374fd2a; - segment3.Append("Further materials."); - - SegmentLoadCommand cmd1, cmd2, cmd3; - cmd1.Header("first", segment1, 0xfadb6932, 0x175bf529, 0x0de790ad); - cmd2.Header("second", segment2, 0xeef716e0, 0xe103a9d7, 0x7d38a8ef); - cmd3.Header("third", segment3, 0xe172b39e, 0x86012f07, 0x080ac94d); - - LoadCommands commands; - commands.Place(&cmd1).Place(&cmd2).Place(&cmd3); - - MachOFile file; - file.Header(&commands).Place(&segment1).Place(&segment2).Place(&segment3); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - Segment actual_segment; - - EXPECT_FALSE(reader.FindSegment("murphy", &actual_segment)); - - EXPECT_TRUE(reader.FindSegment("second", &actual_segment)); - EXPECT_EQ(0xd6b0ce83, actual_segment.vmaddr); -} - - -// Symtab tests. - -// A StringAssembler is a class for generating .stabstr sections to present -// as input to the STABS parser. -class StringAssembler: public SizedSection { - public: - // Add the string S to this StringAssembler, and return the string's - // offset within this compilation unit's strings. - size_t Add(const string &s) { - size_t offset = Size(); - AppendCString(s); - return offset; - } -}; - -// A SymbolAssembler is a class for generating .stab sections to present as -// test input for the STABS parser. -class SymbolAssembler: public SizedSection { - public: - // Create a SymbolAssembler that uses StringAssembler for its strings. - explicit SymbolAssembler(StringAssembler *string_assembler) - : string_assembler_(string_assembler), - entry_count_(0) { } - - // Append a STAB entry to the end of this section with the given - // characteristics. NAME is the offset of this entry's name string within - // its compilation unit's portion of the .stabstr section; this can be a - // value generated by a StringAssembler. Return a reference to this - // SymbolAssembler. - SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor, - Label value, Label name) { - D32(name); - D8(type); - D8(other); - D16(descriptor); - Append(endianness(), word_size_ / 8, value); - entry_count_++; - return *this; - } - - // As above, but automatically add NAME to our StringAssembler. - SymbolAssembler &Symbol(uint8_t type, uint8_t other, Label descriptor, - Label value, const string &name) { - return Symbol(type, other, descriptor, value, string_assembler_->Add(name)); - } - - private: - // The strings for our STABS entries. - StringAssembler *string_assembler_; - - // The number of entries in this compilation unit so far. - size_t entry_count_; -}; - -class Symtab: public ReaderFixture, public Test { }; - -TEST_F(Symtab, Symtab32) { - WithConfiguration config(kLittleEndian, 32); - - StringAssembler strings; - SymbolAssembler symbols(&strings); - symbols - .Symbol(0x52, 0x7c, 0x3470, 0x9bb02e7c, "hrududu") - .Symbol(0x50, 0x90, 0x7520, 0x1122525d, "Frith"); - - SizedSection symtab_command; - symtab_command - .D32(LC_SYMTAB) // command - .D32(symtab_command.final_size()) // size - .D32(symbols.start()) // file offset of symbols - .D32(2) // symbol count - .D32(strings.start()) // file offset of strings - .D32(strings.final_size()); // strings size - - LoadCommands load_commands; - load_commands.Place(&symtab_command); - - MachOFile file; - file.Header(&load_commands).Place(&symbols).Place(&strings); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - ByteBuffer symbols_found, strings_found; - EXPECT_CALL(load_command_handler, SymtabCommand(_, _)) - .WillOnce(DoAll(SaveArg<0>(&symbols_found), - SaveArg<1>(&strings_found), - Return(true))); - EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); - - EXPECT_EQ(24U, symbols_found.Size()); - EXPECT_EQ(14U, strings_found.Size()); -} - -TEST_F(Symtab, Symtab64) { - WithConfiguration config(kBigEndian, 64); - - StringAssembler strings; - SymbolAssembler symbols(&strings); - symbols - .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo") - .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar"); - - SizedSection symtab_command; - symtab_command - .D32(LC_SYMTAB) // command - .D32(symtab_command.final_size()) // size - .D32(symbols.start()) // file offset of symbols - .D32(2) // symbol count - .D32(strings.start()) // file offset of strings - .D32(strings.final_size()); // strings size - - LoadCommands load_commands; - load_commands.Place(&symtab_command); - - MachOFile file; - file.Header(&load_commands).Place(&symbols).Place(&strings); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - ByteBuffer symbols_found, strings_found; - EXPECT_CALL(load_command_handler, SymtabCommand(_, _)) - .WillOnce(DoAll(SaveArg<0>(&symbols_found), - SaveArg<1>(&strings_found), - Return(true))); - EXPECT_TRUE(reader.WalkLoadCommands(&load_command_handler)); - - EXPECT_EQ(32U, symbols_found.Size()); - EXPECT_EQ(8U, strings_found.Size()); -} - -TEST_F(Symtab, SymtabMisplacedSymbols) { - WithConfiguration config(kBigEndian, 32); - - StringAssembler strings; - SymbolAssembler symbols(&strings); - symbols - .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo") - .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar"); - - SizedSection symtab_command; - symtab_command - .D32(LC_SYMTAB) // command - .D32(symtab_command.final_size()) // size - .D32(symbols.start()) // file offset of symbols - .D32(3) // symbol count (too many) - .D32(strings.start()) // file offset of strings - .D32(strings.final_size()); // strings size - - LoadCommands load_commands; - load_commands.Place(&symtab_command); - - MachOFile file; - // Put symbols at end, so the excessive length will be noticed. - file.Header(&load_commands).Place(&strings).Place(&symbols); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1); - EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); -} - -TEST_F(Symtab, SymtabMisplacedStrings) { - WithConfiguration config(kLittleEndian, 32); - - StringAssembler strings; - SymbolAssembler symbols(&strings); - symbols - .Symbol(0xa7, 0xaf, 0x03af, 0x42f3072c74335181ULL, "foo") - .Symbol(0xb0, 0x9a, 0x2aa7, 0x2e2d349b3d5744a0ULL, "bar"); - - SizedSection symtab_command; - symtab_command - .D32(LC_SYMTAB) // command - .D32(symtab_command.final_size()) // size - .D32(symbols.start()) // file offset of symbols - .D32(2) // symbol count - .D32(strings.start()) // file offset of strings - .D32(strings.final_size() + 1); // strings size (too long) - - LoadCommands load_commands; - load_commands.Place(&symtab_command); - - MachOFile file; - // Put strings at end, so the excessive length will be noticed. - file.Header(&load_commands).Place(&symbols).Place(&strings); - - ReadFile(&file, true, CPU_TYPE_ANY, 0); - - EXPECT_CALL(reporter, MisplacedSymbolTable()).Times(1); - EXPECT_FALSE(reader.WalkLoadCommands(&load_command_handler)); -} - diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.cc deleted file mode 100644 index f56fe768c..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.cc +++ /dev/null @@ -1,155 +0,0 @@ -// 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. - -// macho_utilties.cc: Utilities for dealing with mach-o files -// -// Author: Dave Camp - -#include "common/mac/byteswap.h" -#include "common/mac/macho_utilities.h" - -#include <mach-o/fat.h> -#include <mach-o/loader.h> - -void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc) { - uc->cmd = ByteSwap(uc->cmd); - uc->cmdsize = ByteSwap(uc->cmdsize); -} - -void breakpad_swap_load_command(struct load_command *lc) { - lc->cmd = ByteSwap(lc->cmd); - lc->cmdsize = ByteSwap(lc->cmdsize); -} - -void breakpad_swap_dylib_command(struct dylib_command *dc) { - dc->cmd = ByteSwap(dc->cmd); - dc->cmdsize = ByteSwap(dc->cmdsize); - - dc->dylib.name.offset = ByteSwap(dc->dylib.name.offset); - dc->dylib.timestamp = ByteSwap(dc->dylib.timestamp); - dc->dylib.current_version = ByteSwap(dc->dylib.current_version); - dc->dylib.compatibility_version = ByteSwap(dc->dylib.compatibility_version); -} - -void breakpad_swap_segment_command(struct segment_command *sc) { - sc->cmd = ByteSwap(sc->cmd); - sc->cmdsize = ByteSwap(sc->cmdsize); - - sc->vmaddr = ByteSwap(sc->vmaddr); - sc->vmsize = ByteSwap(sc->vmsize); - sc->fileoff = ByteSwap(sc->fileoff); - sc->filesize = ByteSwap(sc->filesize); - sc->maxprot = ByteSwap(sc->maxprot); - sc->initprot = ByteSwap(sc->initprot); - sc->nsects = ByteSwap(sc->nsects); - sc->flags = ByteSwap(sc->flags); -} - -void breakpad_swap_segment_command_64(struct segment_command_64 *sg) { - sg->cmd = ByteSwap(sg->cmd); - sg->cmdsize = ByteSwap(sg->cmdsize); - - sg->vmaddr = ByteSwap(sg->vmaddr); - sg->vmsize = ByteSwap(sg->vmsize); - sg->fileoff = ByteSwap(sg->fileoff); - sg->filesize = ByteSwap(sg->filesize); - - sg->maxprot = ByteSwap(sg->maxprot); - sg->initprot = ByteSwap(sg->initprot); - sg->nsects = ByteSwap(sg->nsects); - sg->flags = ByteSwap(sg->flags); -} - -void breakpad_swap_fat_header(struct fat_header *fh) { - fh->magic = ByteSwap(fh->magic); - fh->nfat_arch = ByteSwap(fh->nfat_arch); -} - -void breakpad_swap_fat_arch(struct fat_arch *fa, uint32_t narchs) { - for (uint32_t i = 0; i < narchs; ++i) { - fa[i].cputype = ByteSwap(fa[i].cputype); - fa[i].cpusubtype = ByteSwap(fa[i].cpusubtype); - fa[i].offset = ByteSwap(fa[i].offset); - fa[i].size = ByteSwap(fa[i].size); - fa[i].align = ByteSwap(fa[i].align); - } -} - -void breakpad_swap_mach_header(struct mach_header *mh) { - mh->magic = ByteSwap(mh->magic); - mh->cputype = ByteSwap(mh->cputype); - mh->cpusubtype = ByteSwap(mh->cpusubtype); - mh->filetype = ByteSwap(mh->filetype); - mh->ncmds = ByteSwap(mh->ncmds); - mh->sizeofcmds = ByteSwap(mh->sizeofcmds); - mh->flags = ByteSwap(mh->flags); -} - -void breakpad_swap_mach_header_64(struct mach_header_64 *mh) { - mh->magic = ByteSwap(mh->magic); - mh->cputype = ByteSwap(mh->cputype); - mh->cpusubtype = ByteSwap(mh->cpusubtype); - mh->filetype = ByteSwap(mh->filetype); - mh->ncmds = ByteSwap(mh->ncmds); - mh->sizeofcmds = ByteSwap(mh->sizeofcmds); - mh->flags = ByteSwap(mh->flags); - mh->reserved = ByteSwap(mh->reserved); -} - -void breakpad_swap_section(struct section *s, - uint32_t nsects) { - for (uint32_t i = 0; i < nsects; i++) { - s[i].addr = ByteSwap(s[i].addr); - s[i].size = ByteSwap(s[i].size); - - s[i].offset = ByteSwap(s[i].offset); - s[i].align = ByteSwap(s[i].align); - s[i].reloff = ByteSwap(s[i].reloff); - s[i].nreloc = ByteSwap(s[i].nreloc); - s[i].flags = ByteSwap(s[i].flags); - s[i].reserved1 = ByteSwap(s[i].reserved1); - s[i].reserved2 = ByteSwap(s[i].reserved2); - } -} - -void breakpad_swap_section_64(struct section_64 *s, - uint32_t nsects) { - for (uint32_t i = 0; i < nsects; i++) { - s[i].addr = ByteSwap(s[i].addr); - s[i].size = ByteSwap(s[i].size); - - s[i].offset = ByteSwap(s[i].offset); - s[i].align = ByteSwap(s[i].align); - s[i].reloff = ByteSwap(s[i].reloff); - s[i].nreloc = ByteSwap(s[i].nreloc); - s[i].flags = ByteSwap(s[i].flags); - s[i].reserved1 = ByteSwap(s[i].reserved1); - s[i].reserved2 = ByteSwap(s[i].reserved2); - } -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.h b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.h deleted file mode 100644 index 00563a77c..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_utilities.h +++ /dev/null @@ -1,95 +0,0 @@ -// 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. - -// macho_utilities.h: Utilities for dealing with mach-o files -// -// Author: Dave Camp - -#ifndef COMMON_MAC_MACHO_UTILITIES_H__ -#define COMMON_MAC_MACHO_UTILITIES_H__ - -#include <mach-o/loader.h> -#include <mach/thread_status.h> - -/* Some #defines and structs that aren't defined in older SDKs */ -#ifndef CPU_ARCH_ABI64 -# define CPU_ARCH_ABI64 0x01000000 -#endif - -#ifndef CPU_TYPE_X86 -# define CPU_TYPE_X86 CPU_TYPE_I386 -#endif - -#ifndef CPU_TYPE_POWERPC64 -# define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64) -#endif - -#ifndef LC_UUID -# define LC_UUID 0x1b /* the uuid */ -#endif - -// The uuid_command struct/swap routines were added during the 10.4 series. -// Their presence isn't guaranteed. -struct breakpad_uuid_command { - uint32_t cmd; /* LC_UUID */ - uint32_t cmdsize; /* sizeof(struct uuid_command) */ - uint8_t uuid[16]; /* the 128-bit uuid */ -}; - -void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc); - -void breakpad_swap_load_command(struct load_command *lc); - -void breakpad_swap_dylib_command(struct dylib_command *dc); - -// Older SDKs defines thread_state_data_t as an int[] instead -// of the natural_t[] it should be. -typedef natural_t breakpad_thread_state_data_t[THREAD_STATE_MAX]; - -void breakpad_swap_segment_command(struct segment_command *sc); - -// The 64-bit swap routines were added during the 10.4 series, their -// presence isn't guaranteed. -void breakpad_swap_segment_command_64(struct segment_command_64 *sg); - -void breakpad_swap_fat_header(struct fat_header *fh); - -void breakpad_swap_fat_arch(struct fat_arch *fa, uint32_t narchs); - -void breakpad_swap_mach_header(struct mach_header *mh); - -void breakpad_swap_mach_header_64(struct mach_header_64 *mh); - -void breakpad_swap_section(struct section *s, - uint32_t nsects); - -void breakpad_swap_section_64(struct section_64 *s, - uint32_t nsects); - -#endif diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.cc deleted file mode 100644 index 1acd86656..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.cc +++ /dev/null @@ -1,268 +0,0 @@ -// 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. - -// macho_walker.cc: Iterate over the load commands in a mach-o file -// -// See macho_walker.h for documentation -// -// Author: Dan Waylonis - -#include <assert.h> -#include <fcntl.h> -#include <mach-o/arch.h> -#include <mach-o/fat.h> -#include <mach-o/loader.h> -#include <string.h> -#include <unistd.h> - -#include "common/mac/byteswap.h" -#include "common/mac/macho_walker.h" -#include "common/mac/macho_utilities.h" - -namespace MacFileUtilities { - -MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback, - void *context) - : file_(-1), - memory_(NULL), - memory_size_(0), - callback_(callback), - callback_context_(context), - current_header_(NULL), - current_header_size_(0), - current_header_offset_(0) { - file_ = open(path, O_RDONLY); -} - -MachoWalker::MachoWalker(void *memory, size_t size, - LoadCommandCallback callback, void *context) - : file_(-1), - memory_(memory), - memory_size_(size), - callback_(callback), - callback_context_(context), - current_header_(NULL), - current_header_size_(0), - current_header_offset_(0) { -} - -MachoWalker::~MachoWalker() { - if (file_ != -1) - close(file_); -} - -bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) { - cpu_type_t valid_cpu_type = cpu_type; - cpu_subtype_t valid_cpu_subtype = cpu_subtype; - // if |cpu_type| is 0, use the native cpu type. - if (cpu_type == 0) { - const NXArchInfo *arch = NXGetLocalArchInfo(); - assert(arch); - valid_cpu_type = arch->cputype; - valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE; - } - off_t offset; - if (FindHeader(valid_cpu_type, valid_cpu_subtype, offset)) { - if (cpu_type & CPU_ARCH_ABI64) - return WalkHeader64AtOffset(offset); - - return WalkHeaderAtOffset(offset); - } - - return false; -} - -bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) { - if (memory_) { - if (offset < 0) - return false; - bool result = true; - if (offset + size > memory_size_) { - if (static_cast<size_t>(offset) >= memory_size_) - return false; - size = memory_size_ - static_cast<size_t>(offset); - result = false; - } - memcpy(buffer, static_cast<char *>(memory_) + offset, size); - return result; - } else { - return pread(file_, buffer, size, offset) == (ssize_t)size; - } -} - -bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) { - if (current_header_) { - memcpy(header, current_header_, sizeof(mach_header_64)); - *offset = current_header_offset_; - return true; - } - - return false; -} - -bool MachoWalker::FindHeader(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - off_t &offset) { - // Read the magic bytes that's common amongst all mach-o files - uint32_t magic; - if (!ReadBytes(&magic, sizeof(magic), 0)) - return false; - - offset = sizeof(magic); - - // Figure out what type of file we've got - bool is_fat = false; - if (magic == FAT_MAGIC || magic == FAT_CIGAM) { - is_fat = true; - } - else if (magic != MH_MAGIC && magic != MH_CIGAM && magic != MH_MAGIC_64 && - magic != MH_CIGAM_64) { - return false; - } - - if (!is_fat) { - // If we don't have a fat header, check if the cpu type matches the single - // header - struct mach_header header; - if (!ReadBytes(&header, sizeof(header), 0)) - return false; - - if (magic == MH_CIGAM || magic == MH_CIGAM_64) - breakpad_swap_mach_header(&header); - - if (cpu_type != header.cputype || - (cpu_subtype != CPU_SUBTYPE_MULTIPLE && - cpu_subtype != header.cpusubtype)) { - return false; - } - - offset = 0; - return true; - } else { - // Read the fat header and find an appropriate architecture - offset = 0; - struct fat_header fat; - if (!ReadBytes(&fat, sizeof(fat), offset)) - return false; - - if (NXHostByteOrder() != NX_BigEndian) - breakpad_swap_fat_header(&fat); - - offset += sizeof(fat); - - // Search each architecture for the desired one - struct fat_arch arch; - for (uint32_t i = 0; i < fat.nfat_arch; ++i) { - if (!ReadBytes(&arch, sizeof(arch), offset)) - return false; - - if (NXHostByteOrder() != NX_BigEndian) - breakpad_swap_fat_arch(&arch, 1); - - if (arch.cputype == cpu_type && - (cpu_subtype == CPU_SUBTYPE_MULTIPLE || - arch.cpusubtype == cpu_subtype)) { - offset = arch.offset; - return true; - } - - offset += sizeof(arch); - } - } - - return false; -} - -bool MachoWalker::WalkHeaderAtOffset(off_t offset) { - struct mach_header header; - if (!ReadBytes(&header, sizeof(header), offset)) - return false; - - bool swap = (header.magic == MH_CIGAM); - if (swap) - breakpad_swap_mach_header(&header); - - // Copy the data into the mach_header_64 structure. Since the 32-bit and - // 64-bit only differ in the last field (reserved), this is safe to do. - struct mach_header_64 header64; - memcpy((void *)&header64, (const void *)&header, sizeof(header)); - header64.reserved = 0; - - current_header_ = &header64; - current_header_size_ = sizeof(header); // 32-bit, not 64-bit - current_header_offset_ = offset; - offset += current_header_size_; - bool result = WalkHeaderCore(offset, header.ncmds, swap); - current_header_ = NULL; - current_header_size_ = 0; - current_header_offset_ = 0; - return result; -} - -bool MachoWalker::WalkHeader64AtOffset(off_t offset) { - struct mach_header_64 header; - if (!ReadBytes(&header, sizeof(header), offset)) - return false; - - bool swap = (header.magic == MH_CIGAM_64); - if (swap) - breakpad_swap_mach_header_64(&header); - - current_header_ = &header; - current_header_size_ = sizeof(header); - current_header_offset_ = offset; - offset += current_header_size_; - bool result = WalkHeaderCore(offset, header.ncmds, swap); - current_header_ = NULL; - current_header_size_ = 0; - current_header_offset_ = 0; - return result; -} - -bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands, - bool swap) { - for (uint32_t i = 0; i < number_of_commands; ++i) { - struct load_command cmd; - if (!ReadBytes(&cmd, sizeof(cmd), offset)) - return false; - - if (swap) - breakpad_swap_load_command(&cmd); - - // Call the user callback - if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_)) - break; - - offset += cmd.cmdsize; - } - - return true; -} - -} // namespace MacFileUtilities diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.h b/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.h deleted file mode 100644 index dd535814a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/macho_walker.h +++ /dev/null @@ -1,119 +0,0 @@ -// 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. - -// macho_walker.h: Iterate over the load commands in a mach-o file -// -// Author: Dan Waylonis - -#ifndef COMMON_MAC_MACHO_WALKER_H__ -#define COMMON_MAC_MACHO_WALKER_H__ - -#include <mach/machine.h> -#include <mach-o/loader.h> -#include <sys/types.h> - -namespace MacFileUtilities { - -class MachoWalker { - public: - // A callback function executed when a new load command is read. If no - // further processing of load commands is desired, return false. Otherwise, - // return true. - // |cmd| is the current command, and |offset| is the location relative to the - // beginning of the file (not header) where the command was read. If |swap| - // is set, then any command data (other than the returned load_command) should - // be swapped when read - typedef bool (*LoadCommandCallback)(MachoWalker *walker, load_command *cmd, - off_t offset, bool swap, void *context); - - MachoWalker(const char *path, LoadCommandCallback callback, void *context); - MachoWalker(void *memory, size_t size, LoadCommandCallback callback, - void *context); - ~MachoWalker(); - - // Begin walking the header for |cpu_type| and |cpu_subtype|. If |cpu_type| - // is 0, then the native cpu type is used. Otherwise, accepted values are - // listed in /usr/include/mach/machine.h (e.g., CPU_TYPE_X86 or - // CPU_TYPE_POWERPC). If |cpu_subtype| is CPU_SUBTYPE_MULTIPLE, the match is - // only done on |cpu_type|. - // Returns false if opening the file failed or if the |cpu_type|/|cpu_subtype| - // is not present in the file. - bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); - - // Read |size| bytes from the opened file at |offset| into |buffer| - bool ReadBytes(void *buffer, size_t size, off_t offset); - - // Return the current header and header offset - bool CurrentHeader(struct mach_header_64 *header, off_t *offset); - - private: - // Locate (if any) the header offset for |cpu_type| and return in |offset|. - // Return true if found, false otherwise. - bool FindHeader(cpu_type_t cpu_type, - cpu_subtype_t cpu_subtype, - off_t &offset); - - // Process an individual header starting at |offset| from the start of the - // file. Return true if successful, false otherwise. - bool WalkHeaderAtOffset(off_t offset); - bool WalkHeader64AtOffset(off_t offset); - - // Bottleneck for walking the load commands - bool WalkHeaderCore(off_t offset, uint32_t number_of_commands, bool swap); - - // File descriptor to the opened file - int file_; - - // Memory location to read from. - void *memory_; - - // Size of the memory segment we can read from. - size_t memory_size_; - - // User specified callback & context - LoadCommandCallback callback_; - void *callback_context_; - - // Current header, size, and offset. The mach_header_64 is used for both - // 32-bit and 64-bit headers because they only differ in their last field - // (reserved). By adding the |current_header_size_| and the - // |current_header_offset_|, you can determine the offset in the file just - // after the header. - struct mach_header_64 *current_header_; - unsigned long current_header_size_; - off_t current_header_offset_; - - private: - MachoWalker(const MachoWalker &); - MachoWalker &operator=(const MachoWalker &); -}; - -} // namespace MacFileUtilities - -#endif // COMMON_MAC_MACHO_WALKER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/moz.build b/toolkit/crashreporter/google-breakpad/src/common/mac/moz.build deleted file mode 100644 index 6d6df28e2..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/moz.build +++ /dev/null @@ -1,52 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -UNIFIED_SOURCES += [ - 'arch_utilities.cc', - 'file_id.cc', - 'macho_id.cc', - 'macho_reader.cc', - 'macho_utilities.cc', - 'macho_walker.cc', -] - -if CONFIG['HOST_OS_ARCH'] != 'Darwin': - HOST_CXXFLAGS += [ - '-I%s/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/' % TOPSRCDIR, - ] - -# This is a little weird, but we're building a host and a target lib here. -# The host lib is used for dump_syms, and the target lib for the -# crash reporter client. Therefore, we don't need all the srcs in both. -if CONFIG['MOZ_CRASHREPORTER']: - HOST_SOURCES += UNIFIED_SOURCES - HOST_SOURCES += [ - 'dump_syms.cc', - ] - HOST_CXXFLAGS += [ - '-O2', - '-g', - '-stdlib=libc++', - ] - HostLibrary('host_breakpad_mac_common_s') - -SOURCES += [ - 'bootstrap_compat.cc', - 'HTTPMultipartUpload.m', - 'MachIPC.mm', - 'string_utilities.cc', -] - -Library('breakpad_mac_common_s') - -# We allow warnings for third-party code that can be updated from upstream. -ALLOW_COMPILER_WARNINGS = True - -FINAL_LIBRARY = 'xul' - -CMFLAGS += ['-std=c99'] - -include('/toolkit/crashreporter/crashreporter.mozbuild') diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/scoped_task_suspend-inl.h b/toolkit/crashreporter/google-breakpad/src/common/mac/scoped_task_suspend-inl.h deleted file mode 100644 index d6d1bef97..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/scoped_task_suspend-inl.h +++ /dev/null @@ -1,56 +0,0 @@ -// 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. - -// Inline implementation of ScopedTaskSuspend, which suspends a Mach -// task for the duration of its scope. - -#ifndef GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_ -#define GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_ - -#include <mach/mach.h> - -namespace google_breakpad { - -class ScopedTaskSuspend { - public: - explicit ScopedTaskSuspend(mach_port_t target) : target_(target) { - task_suspend(target_); - } - - ~ScopedTaskSuspend() { - task_resume(target_); - } - - private: - mach_port_t target_; -}; - -} // namespace google_breakpad - -#endif // GOOGLE_BREAKPAD_COMMON_MAC_SCOPED_TASK_SUSPEND_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.cc b/toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.cc deleted file mode 100644 index 07c0f4268..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.cc +++ /dev/null @@ -1,84 +0,0 @@ -// 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/scoped_ptr.h" -#include "common/mac/string_utilities.h" - -namespace MacStringUtils { - -using google_breakpad::scoped_array; - -std::string ConvertToString(CFStringRef str) { - CFIndex length = CFStringGetLength(str); - std::string result; - - if (!length) - return result; - - CFIndex maxUTF8Length = - CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); - scoped_array<UInt8> buffer(new UInt8[maxUTF8Length + 1]); - CFIndex actualUTF8Length; - CFStringGetBytes(str, CFRangeMake(0, length), kCFStringEncodingUTF8, 0, - false, buffer.get(), maxUTF8Length, &actualUTF8Length); - buffer[actualUTF8Length] = 0; - result.assign((const char *)buffer.get()); - - return result; -} - -unsigned int IntegerValueAtIndex(string &str, unsigned int idx) { - string digits("0123456789"), temp; - size_t start = 0; - size_t end; - size_t found = 0; - unsigned int result = 0; - - for (; found <= idx; ++found) { - end = str.find_first_not_of(digits, start); - - if (end == string::npos) - end = str.size(); - - temp = str.substr(start, end - start); - - if (found == idx) { - result = atoi(temp.c_str()); - } - - start = str.find_first_of(digits, end + 1); - - if (start == string::npos) - break; - } - - return result; -} - -} // namespace MacStringUtils diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.h b/toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.h deleted file mode 100644 index 6d89c834e..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/string_utilities.h +++ /dev/null @@ -1,52 +0,0 @@ -// 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. - -// string_utilities.h: Utilities for strings for Mac platform - -#ifndef COMMON_MAC_STRING_UTILITIES_H__ -#define COMMON_MAC_STRING_UTILITIES_H__ - -#include <CoreFoundation/CoreFoundation.h> - -#include <string> - -namespace MacStringUtils { - -using std::string; - -// Convert a CoreFoundation string into a std::string -string ConvertToString(CFStringRef str); - -// Return the idx'th decimal integer in str, separated by non-decimal-digits -// E.g., str = 10.4.8, idx = 1 -> 4 -unsigned int IntegerValueAtIndex(string &str, unsigned int idx); - -} // namespace MacStringUtils - -#endif // COMMON_MAC_STRING_UTILITIES_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/super_fat_arch.h b/toolkit/crashreporter/google-breakpad/src/common/mac/super_fat_arch.h deleted file mode 100644 index 501c8652a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/super_fat_arch.h +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 2015, 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: Erik Chen <erikchen@chromium.org> - -// super_fat_arch.h: A class to handle 64-bit object files. Has conversions to -// and from struct fat_arch. - -#ifndef BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_ -#define BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_ - -#include <limits> -#include <mach-o/fat.h> -#include <stdint.h> - -// Similar to struct fat_arch, except size-related parameters support -// 64-bits. -class SuperFatArch { - public: - uint32_t cputype; - uint32_t cpusubtype; - uint64_t offset; - uint64_t size; - uint64_t align; - - SuperFatArch() : - cputype(0), - cpusubtype(0), - offset(0), - size(0), - align(0) { - } - - explicit SuperFatArch(const struct fat_arch &arch) : - cputype(arch.cputype), - cpusubtype(arch.cpusubtype), - offset(arch.offset), - size(arch.size), - align(arch.align) { - } - - // Returns false if the conversion cannot be made. - // If the conversion succeeds, the result is placed in |output_arch|. - bool ConvertToFatArch(struct fat_arch* output_arch) const { - if (offset > std::numeric_limits<uint32_t>::max()) - return false; - if (size > std::numeric_limits<uint32_t>::max()) - return false; - if (align > std::numeric_limits<uint32_t>::max()) - return false; - struct fat_arch arch; - arch.cputype = cputype; - arch.cpusubtype = cpusubtype; - arch.offset = offset; - arch.size = size; - arch.align = align; - *output_arch = arch; - return true; - } -}; - -#endif // BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.h b/toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.h deleted file mode 100644 index ce3d9022c..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.h +++ /dev/null @@ -1,1110 +0,0 @@ -// -// GTMSenTestCase.h -// -// Copyright 2007-2008 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy -// of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. -// - -// Portions of this file fall under the following license, marked with -// SENTE_BEGIN - SENTE_END -// -// Copyright (c) 1997-2005, Sen:te (Sente SA). All rights reserved. -// -// Use of this source code is governed by the following license: -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// (1) Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// (2) 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. -// -// 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 Sente SA 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. -// -// Note: this license is equivalent to the FreeBSD license. -// -// This notice may not be removed from this file. - -// Some extra test case macros that would have been convenient for SenTestingKit -// to provide. I didn't stick GTM in front of the Macro names, so that they would -// be easy to remember. - -#import "GTMDefines.h" - -#if (!GTM_IPHONE_SDK) || (GTM_IPHONE_USE_SENTEST) -#import <SenTestingKit/SenTestingKit.h> -#else -#import <Foundation/Foundation.h> -#ifdef __cplusplus -extern "C" { -#endif - -#if defined __clang__ -// gcc and gcc-llvm do not allow you to use STAssert(blah, nil) with nil -// as a description if you have the NS_FORMAT_FUNCTION on. -// clang however will not compile without warnings if you don't have it. -NSString *STComposeString(NSString *, ...) NS_FORMAT_FUNCTION(1, 2); -#else -NSString *STComposeString(NSString *, ...); -#endif // __clang__ - -#ifdef __cplusplus -} -#endif - -#endif // !GTM_IPHONE_SDK || GTM_IPHONE_USE_SENTEST - -// Generates a failure when a1 != noErr -// Args: -// a1: should be either an OSErr or an OSStatus -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertNoErr(a1, description, ...) \ -do { \ - @try { \ - OSStatus a1value = (a1); \ - if (a1value != noErr) { \ - NSString *_expression = [NSString stringWithFormat:@"Expected noErr, got %ld for (%s)", (long)a1value, #a1]; \ - [self failWithException:([NSException failureInCondition:_expression \ - isTrue:NO \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == noErr fails", #a1] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - -// Generates a failure when a1 != a2 -// Args: -// a1: received value. Should be either an OSErr or an OSStatus -// a2: expected value. Should be either an OSErr or an OSStatus -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertErr(a1, a2, description, ...) \ -do { \ - @try { \ - OSStatus a1value = (a1); \ - OSStatus a2value = (a2); \ - if (a1value != a2value) { \ - NSString *_expression = [NSString stringWithFormat:@"Expected %s(%ld) but got %ld for (%s)", #a2, (long)a2value, (long)a1value, #a1]; \ - [self failWithException:([NSException failureInCondition:_expression \ - isTrue:NO \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s) fails", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - - -// Generates a failure when a1 is NULL -// Args: -// a1: should be a pointer (use STAssertNotNil for an object) -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertNotNULL(a1, description, ...) \ -do { \ - @try { \ - __typeof__(a1) a1value = (a1); \ - if (a1value == (__typeof__(a1))NULL) { \ - NSString *_expression = [NSString stringWithFormat:@"((%s) != NULL)", #a1]; \ - [self failWithException:([NSException failureInCondition:_expression \ - isTrue:NO \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != NULL fails", #a1] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - -// Generates a failure when a1 is not NULL -// Args: -// a1: should be a pointer (use STAssertNil for an object) -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertNULL(a1, description, ...) \ -do { \ - @try { \ - __typeof__(a1) a1value = (a1); \ - if (a1value != (__typeof__(a1))NULL) { \ - NSString *_expression = [NSString stringWithFormat:@"((%s) == NULL)", #a1]; \ - [self failWithException:([NSException failureInCondition:_expression \ - isTrue:NO \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == NULL fails", #a1] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - -// Generates a failure when a1 is equal to a2. This test is for C scalars, -// structs and unions. -// Args: -// a1: argument 1 -// a2: argument 2 -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertNotEquals(a1, a2, description, ...) \ -do { \ - @try { \ - if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \ - [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \ - } else { \ - __typeof__(a1) a1value = (a1); \ - __typeof__(a2) a2value = (a2); \ - NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \ - NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \ - if ([a1encoded isEqualToValue:a2encoded]) { \ - NSString *_expression = [NSString stringWithFormat:@"((%s) != (%s))", #a1, #a2]; \ - [self failWithException:([NSException failureInCondition:_expression \ - isTrue:NO \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ - }\ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - -// Generates a failure when a1 is equal to a2. This test is for objects. -// Args: -// a1: argument 1. object. -// a2: argument 2. object. -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertNotEqualObjects(a1, a2, description, ...) \ -do { \ - @try {\ - id a1value = (a1); \ - id a2value = (a2); \ - if ( (strcmp(@encode(__typeof__(a1value)), @encode(id)) == 0) && \ - (strcmp(@encode(__typeof__(a2value)), @encode(id)) == 0) && \ - (![(id)a1value isEqual:(id)a2value]) ) continue; \ - [self failWithException:([NSException failureInEqualityBetweenObject:a1value \ - andObject:a2value \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ - }\ - @catch (id anException) {\ - [self failWithException:([NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ - }\ -} while(0) - -// Generates a failure when a1 is not 'op' to a2. This test is for C scalars. -// Args: -// a1: argument 1 -// a2: argument 2 -// op: operation -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertOperation(a1, a2, op, description, ...) \ -do { \ - @try { \ - if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \ - [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \ - } else { \ - __typeof__(a1) a1value = (a1); \ - __typeof__(a2) a2value = (a2); \ - if (!(a1value op a2value)) { \ - double a1DoubleValue = a1value; \ - double a2DoubleValue = a2value; \ - NSString *_expression = [NSString stringWithFormat:@"(%s (%lg) %s %s (%lg))", #a1, a1DoubleValue, #op, #a2, a2DoubleValue]; \ - [self failWithException:([NSException failureInCondition:_expression \ - isTrue:NO \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)])]; \ - } \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException \ - failureInRaise:[NSString stringWithFormat:@"(%s) %s (%s)", #a1, #op, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - -// Generates a failure when a1 is not > a2. This test is for C scalars. -// Args: -// a1: argument 1 -// a2: argument 2 -// op: operation -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertGreaterThan(a1, a2, description, ...) \ - STAssertOperation(a1, a2, >, description, ##__VA_ARGS__) - -// Generates a failure when a1 is not >= a2. This test is for C scalars. -// Args: -// a1: argument 1 -// a2: argument 2 -// op: operation -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertGreaterThanOrEqual(a1, a2, description, ...) \ - STAssertOperation(a1, a2, >=, description, ##__VA_ARGS__) - -// Generates a failure when a1 is not < a2. This test is for C scalars. -// Args: -// a1: argument 1 -// a2: argument 2 -// op: operation -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertLessThan(a1, a2, description, ...) \ - STAssertOperation(a1, a2, <, description, ##__VA_ARGS__) - -// Generates a failure when a1 is not <= a2. This test is for C scalars. -// Args: -// a1: argument 1 -// a2: argument 2 -// op: operation -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertLessThanOrEqual(a1, a2, description, ...) \ - STAssertOperation(a1, a2, <=, description, ##__VA_ARGS__) - -// Generates a failure when string a1 is not equal to string a2. This call -// differs from STAssertEqualObjects in that strings that are different in -// composition (precomposed vs decomposed) will compare equal if their final -// representation is equal. -// ex O + umlaut decomposed is the same as O + umlaut composed. -// Args: -// a1: string 1 -// a2: string 2 -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertEqualStrings(a1, a2, description, ...) \ -do { \ - @try { \ - id a1value = (a1); \ - id a2value = (a2); \ - if (a1value == a2value) continue; \ - if ([a1value isKindOfClass:[NSString class]] && \ - [a2value isKindOfClass:[NSString class]] && \ - [a1value compare:a2value options:0] == NSOrderedSame) continue; \ - [self failWithException:[NSException failureInEqualityBetweenObject:a1value \ - andObject:a2value \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - -// Generates a failure when string a1 is equal to string a2. This call -// differs from STAssertEqualObjects in that strings that are different in -// composition (precomposed vs decomposed) will compare equal if their final -// representation is equal. -// ex O + umlaut decomposed is the same as O + umlaut composed. -// Args: -// a1: string 1 -// a2: string 2 -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertNotEqualStrings(a1, a2, description, ...) \ -do { \ - @try { \ - id a1value = (a1); \ - id a2value = (a2); \ - if ([a1value isKindOfClass:[NSString class]] && \ - [a2value isKindOfClass:[NSString class]] && \ - [a1value compare:a2value options:0] != NSOrderedSame) continue; \ - [self failWithException:[NSException failureInEqualityBetweenObject:a1value \ - andObject:a2value \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - -// Generates a failure when c-string a1 is not equal to c-string a2. -// Args: -// a1: string 1 -// a2: string 2 -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertEqualCStrings(a1, a2, description, ...) \ -do { \ - @try { \ - const char* a1value = (a1); \ - const char* a2value = (a2); \ - if (a1value == a2value) continue; \ - if (strcmp(a1value, a2value) == 0) continue; \ - [self failWithException:[NSException failureInEqualityBetweenObject:[NSString stringWithUTF8String:a1value] \ - andObject:[NSString stringWithUTF8String:a2value] \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - -// Generates a failure when c-string a1 is equal to c-string a2. -// Args: -// a1: string 1 -// a2: string 2 -// description: A format string as in the printf() function. Can be nil or -// an empty string but must be present. -// ...: A variable number of arguments to the format string. Can be absent. -#define STAssertNotEqualCStrings(a1, a2, description, ...) \ -do { \ - @try { \ - const char* a1value = (a1); \ - const char* a2value = (a2); \ - if (strcmp(a1value, a2value) != 0) continue; \ - [self failWithException:[NSException failureInEqualityBetweenObject:[NSString stringWithUTF8String:a1value] \ - andObject:[NSString stringWithUTF8String:a2value] \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != (%s)", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - -/*" Generates a failure when a1 is not equal to a2 within + or - accuracy is false. - This test is for GLKit types (GLKVector, GLKMatrix) where small differences - could make these items not exactly equal. Do not use this version directly. - Use the explicit STAssertEqualGLKVectors and STAssertEqualGLKMatrices defined - below. - _{a1 The GLKType on the left.} - _{a2 The GLKType on the right.} - _{accuracy The maximum difference between a1 and a2 for these values to be - considered equal.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ - -#define STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ...) \ -do { \ - @try { \ - if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \ - [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \ - } else { \ - __typeof__(a1) a1GLKValue = (a1); \ - __typeof__(a2) a2GLKValue = (a2); \ - __typeof__(accuracy) accuracyvalue = (accuracy); \ - float *a1FloatValue = ((float*)&a1GLKValue); \ - float *a2FloatValue = ((float*)&a2GLKValue); \ - for (size_t i = 0; i < sizeof(__typeof__(a1)) / sizeof(float); ++i) { \ - float a1value = a1FloatValue[i]; \ - float a2value = a2FloatValue[i]; \ - if (STAbsoluteDifference(a1value, a2value) > accuracyvalue) { \ - NSMutableArray *strings = [NSMutableArray arrayWithCapacity:sizeof(a1) / sizeof(float)]; \ - NSString *string; \ - for (size_t j = 0; j < sizeof(__typeof__(a1)) / sizeof(float); ++j) { \ - string = [NSString stringWithFormat:@"(%0.3f == %0.3f)", a1FloatValue[j], a2FloatValue[j]]; \ - [strings addObject:string]; \ - } \ - string = [strings componentsJoinedByString:@", "]; \ - NSString *desc = STComposeString(description, ##__VA_ARGS__); \ - desc = [NSString stringWithFormat:@"%@ With Accuracy %0.3f: %@", string, (float)accuracyvalue, desc]; \ - [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", desc]]; \ - break; \ - } \ - } \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - -#define STAssertEqualGLKVectors(a1, a2, accuracy, description, ...) \ - STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ##__VA_ARGS__) - -#define STAssertEqualGLKMatrices(a1, a2, accuracy, description, ...) \ - STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ##__VA_ARGS__) - -#define STAssertEqualGLKQuaternions(a1, a2, accuracy, description, ...) \ - STInternalAssertEqualGLKVectorsOrMatrices(a1, a2, accuracy, description, ##__VA_ARGS__) - -#if GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST -// When not using the Xcode provided version, define everything ourselves. - -// SENTE_BEGIN -/*" Generates a failure when !{ [a1 isEqualTo:a2] } is false - (or one is nil and the other is not). - _{a1 The object on the left.} - _{a2 The object on the right.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ -#define STAssertEqualObjects(a1, a2, description, ...) \ -do { \ - @try { \ - id a1value = (a1); \ - id a2value = (a2); \ - if (a1value == a2value) continue; \ - if ((strcmp(@encode(__typeof__(a1value)), @encode(id)) == 0) && \ - (strcmp(@encode(__typeof__(a2value)), @encode(id)) == 0) && \ - [(id)a1value isEqual:(id)a2value]) continue; \ - [self failWithException:[NSException failureInEqualityBetweenObject:a1value \ - andObject:a2value \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - - -/*" Generates a failure when a1 is not equal to a2. This test is for - C scalars, structs and unions. - _{a1 The argument on the left.} - _{a2 The argument on the right.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ -#define STAssertEquals(a1, a2, description, ...) \ -do { \ - @try { \ - if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \ - [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \ - } else { \ - __typeof__(a1) a1value = (a1); \ - __typeof__(a2) a2value = (a2); \ - NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \ - NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \ - if (![a1encoded isEqualToValue:a2encoded]) { \ - [self failWithException:[NSException failureInEqualityBetweenValue:a1encoded \ - andValue:a2encoded \ - withAccuracy:nil \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - -#define STAbsoluteDifference(left,right) (MAX(left,right)-MIN(left,right)) - - -/*" Generates a failure when a1 is not equal to a2 within + or - accuracy is false. - This test is for scalars such as floats and doubles where small differences - could make these items not exactly equal, but also works for all scalars. - _{a1 The scalar on the left.} - _{a2 The scalar on the right.} - _{accuracy The maximum difference between a1 and a2 for these values to be - considered equal.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ - -#define STAssertEqualsWithAccuracy(a1, a2, accuracy, description, ...) \ -do { \ - @try { \ - if (strcmp(@encode(__typeof__(a1)), @encode(__typeof__(a2)))) { \ - [self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"Type mismatch -- %@", STComposeString(description, ##__VA_ARGS__)]]; \ - } else { \ - __typeof__(a1) a1value = (a1); \ - __typeof__(a2) a2value = (a2); \ - __typeof__(accuracy) accuracyvalue = (accuracy); \ - if (STAbsoluteDifference(a1value, a2value) > accuracyvalue) { \ - NSValue *a1encoded = [NSValue value:&a1value withObjCType:@encode(__typeof__(a1))]; \ - NSValue *a2encoded = [NSValue value:&a2value withObjCType:@encode(__typeof__(a2))]; \ - NSValue *accuracyencoded = [NSValue value:&accuracyvalue withObjCType:@encode(__typeof__(accuracy))]; \ - [self failWithException:[NSException failureInEqualityBetweenValue:a1encoded \ - andValue:a2encoded \ - withAccuracy:accuracyencoded \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == (%s)", #a1, #a2] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - - - -/*" Generates a failure unconditionally. - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ -#define STFail(description, ...) \ -[self failWithException:[NSException failureInFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]] - - - -/*" Generates a failure when a1 is not nil. - _{a1 An object.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ -#define STAssertNil(a1, description, ...) \ -do { \ - @try { \ - id a1value = (a1); \ - if (a1value != nil) { \ - NSString *_a1 = [NSString stringWithUTF8String:#a1]; \ - NSString *_expression = [NSString stringWithFormat:@"((%@) == nil)", _a1]; \ - [self failWithException:[NSException failureInCondition:_expression \ - isTrue:NO \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) == nil fails", #a1] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - - -/*" Generates a failure when a1 is nil. - _{a1 An object.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ -#define STAssertNotNil(a1, description, ...) \ -do { \ - @try { \ - id a1value = (a1); \ - if (a1value == nil) { \ - NSString *_a1 = [NSString stringWithUTF8String:#a1]; \ - NSString *_expression = [NSString stringWithFormat:@"((%@) != nil)", _a1]; \ - [self failWithException:[NSException failureInCondition:_expression \ - isTrue:NO \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) != nil fails", #a1] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while(0) - - -/*" Generates a failure when expression evaluates to false. - _{expr The expression that is tested.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ -#define STAssertTrue(expr, description, ...) \ -do { \ - BOOL _evaluatedExpression = (expr); \ - if (!_evaluatedExpression) { \ - NSString *_expression = [NSString stringWithUTF8String:#expr]; \ - [self failWithException:[NSException failureInCondition:_expression \ - isTrue:NO \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while (0) - - -/*" Generates a failure when expression evaluates to false and in addition will - generate error messages if an exception is encountered. - _{expr The expression that is tested.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ -#define STAssertTrueNoThrow(expr, description, ...) \ -do { \ - @try { \ - BOOL _evaluatedExpression = (expr); \ - if (!_evaluatedExpression) { \ - NSString *_expression = [NSString stringWithUTF8String:#expr]; \ - [self failWithException:[NSException failureInCondition:_expression \ - isTrue:NO \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"(%s) ", #expr] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while (0) - - -/*" Generates a failure when the expression evaluates to true. - _{expr The expression that is tested.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ -#define STAssertFalse(expr, description, ...) \ -do { \ - BOOL _evaluatedExpression = (expr); \ - if (_evaluatedExpression) { \ - NSString *_expression = [NSString stringWithUTF8String:#expr]; \ - [self failWithException:[NSException failureInCondition:_expression \ - isTrue:YES \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while (0) - - -/*" Generates a failure when the expression evaluates to true and in addition - will generate error messages if an exception is encountered. - _{expr The expression that is tested.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ -#define STAssertFalseNoThrow(expr, description, ...) \ -do { \ - @try { \ - BOOL _evaluatedExpression = (expr); \ - if (_evaluatedExpression) { \ - NSString *_expression = [NSString stringWithUTF8String:#expr]; \ - [self failWithException:[NSException failureInCondition:_expression \ - isTrue:YES \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithFormat:@"!(%s) ", #expr] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while (0) - - -/*" Generates a failure when expression does not throw an exception. - _{expression The expression that is evaluated.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent. -"*/ -#define STAssertThrows(expr, description, ...) \ -do { \ - @try { \ - (expr); \ - } \ - @catch (id anException) { \ - continue; \ - } \ - [self failWithException:[NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ - exception:nil \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ -} while (0) - - -/*" Generates a failure when expression does not throw an exception of a - specific class. - _{expression The expression that is evaluated.} - _{specificException The specified class of the exception.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ -#define STAssertThrowsSpecific(expr, specificException, description, ...) \ -do { \ - @try { \ - (expr); \ - } \ - @catch (specificException *anException) { \ - continue; \ - } \ - @catch (id anException) { \ - NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description); \ - [self failWithException:[NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \ - continue; \ - } \ - NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description); \ - [self failWithException:[NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ - exception:nil \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \ -} while (0) - - -/*" Generates a failure when expression does not throw an exception of a - specific class with a specific name. Useful for those frameworks like - AppKit or Foundation that throw generic NSException w/specific names - (NSInvalidArgumentException, etc). - _{expression The expression that is evaluated.} - _{specificException The specified class of the exception.} - _{aName The name of the specified exception.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} - -"*/ -#define STAssertThrowsSpecificNamed(expr, specificException, aName, description, ...) \ -do { \ - @try { \ - (expr); \ - } \ - @catch (specificException *anException) { \ - if ([aName isEqualToString:[anException name]]) continue; \ - NSString *_descrip = STComposeString(@"(Expected exception: %@ (name: %@)) %@", NSStringFromClass([specificException class]), aName, description); \ - [self failWithException: \ - [NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \ - continue; \ - } \ - @catch (id anException) { \ - NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description); \ - [self failWithException: \ - [NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \ - continue; \ - } \ - NSString *_descrip = STComposeString(@"(Expected exception: %@) %@", NSStringFromClass([specificException class]), description); \ - [self failWithException: \ - [NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ - exception:nil \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \ -} while (0) - - -/*" Generates a failure when expression does throw an exception. - _{expression The expression that is evaluated.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ -#define STAssertNoThrow(expr, description, ...) \ -do { \ - @try { \ - (expr); \ - } \ - @catch (id anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ -} while (0) - - -/*" Generates a failure when expression does throw an exception of the specitied - class. Any other exception is okay (i.e. does not generate a failure). - _{expression The expression that is evaluated.} - _{specificException The specified class of the exception.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} -"*/ -#define STAssertNoThrowSpecific(expr, specificException, description, ...) \ -do { \ - @try { \ - (expr); \ - } \ - @catch (specificException *anException) { \ - [self failWithException:[NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(description, ##__VA_ARGS__)]]; \ - } \ - @catch (id anythingElse) { \ - ; \ - } \ -} while (0) - - -/*" Generates a failure when expression does throw an exception of a - specific class with a specific name. Useful for those frameworks like - AppKit or Foundation that throw generic NSException w/specific names - (NSInvalidArgumentException, etc). - _{expression The expression that is evaluated.} - _{specificException The specified class of the exception.} - _{aName The name of the specified exception.} - _{description A format string as in the printf() function. Can be nil or - an empty string but must be present.} - _{... A variable number of arguments to the format string. Can be absent.} - -"*/ -#define STAssertNoThrowSpecificNamed(expr, specificException, aName, description, ...) \ -do { \ - @try { \ - (expr); \ - } \ - @catch (specificException *anException) { \ - if ([aName isEqualToString:[anException name]]) { \ - NSString *_descrip = STComposeString(@"(Expected exception: %@ (name: %@)) %@", NSStringFromClass([specificException class]), aName, description); \ - [self failWithException: \ - [NSException failureInRaise:[NSString stringWithUTF8String:#expr] \ - exception:anException \ - inFile:[NSString stringWithUTF8String:__FILE__] \ - atLine:__LINE__ \ - withDescription:@"%@", STComposeString(_descrip, ##__VA_ARGS__)]]; \ - } \ - continue; \ - } \ - @catch (id anythingElse) { \ - ; \ - } \ -} while (0) - - - -@interface NSException (GTMSenTestAdditions) -+ (NSException *)failureInFile:(NSString *)filename - atLine:(int)lineNumber - withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(3, 4); -+ (NSException *)failureInCondition:(NSString *)condition - isTrue:(BOOL)isTrue - inFile:(NSString *)filename - atLine:(int)lineNumber - withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(5, 6); -+ (NSException *)failureInEqualityBetweenObject:(id)left - andObject:(id)right - inFile:(NSString *)filename - atLine:(int)lineNumber - withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(5, 6); -+ (NSException *)failureInEqualityBetweenValue:(NSValue *)left - andValue:(NSValue *)right - withAccuracy:(NSValue *)accuracy - inFile:(NSString *)filename - atLine:(int) ineNumber - withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(6, 7); -+ (NSException *)failureInRaise:(NSString *)expression - inFile:(NSString *)filename - atLine:(int)lineNumber - withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(4, 5); -+ (NSException *)failureInRaise:(NSString *)expression - exception:(NSException *)exception - inFile:(NSString *)filename - atLine:(int)lineNumber - withDescription:(NSString *)formatString, ... NS_FORMAT_FUNCTION(5, 6); -@end - -// SENTE_END - -@protocol SenTestCase -+ (id)testCaseWithInvocation:(NSInvocation *)anInvocation; -- (id)initWithInvocation:(NSInvocation *)anInvocation; -- (void)setUp; -- (void)invokeTest; -- (void)tearDown; -- (void)performTest; -- (void)failWithException:(NSException*)exception; -- (NSInvocation *)invocation; -- (SEL)selector; -+ (NSArray *)testInvocations; -@end - -@interface SenTestCase : NSObject<SenTestCase> { - @private - NSInvocation *invocation_; -} -@end - -GTM_EXTERN NSString *const SenTestFailureException; - -GTM_EXTERN NSString *const SenTestFilenameKey; -GTM_EXTERN NSString *const SenTestLineNumberKey; - -#endif // GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST - -// All unittest cases in GTM should inherit from GTMTestCase. It makes sure -// to set up our logging system correctly to verify logging calls. -// See GTMUnitTestDevLog.h for details -@interface GTMTestCase : SenTestCase - -// Returns YES if this is an abstract testCase class as opposed to a concrete -// testCase class that you want tests run against. SenTestCase is not designed -// out of the box to handle an abstract class hierarchy descending from it with -// some concrete subclasses. In some cases we want all the "concrete" -// subclasses of an abstract subclass of SenTestCase to run a test, but we don't -// want that test to be run against an instance of an abstract subclass itself. -// By returning "YES" here, the tests defined by this class won't be run against -// an instance of this class. As an example class hierarchy: -// -// FooExtensionTestCase -// GTMTestCase <- ExtensionAbstractTestCase < -// BarExtensionTestCase -// -// So FooExtensionTestCase and BarExtensionTestCase inherit from -// ExtensionAbstractTestCase (and probably FooExtension and BarExtension inherit -// from a class named Extension). We want the tests in ExtensionAbstractTestCase -// to be run as part of FooExtensionTestCase and BarExtensionTestCase, but we -// don't want them run against ExtensionAbstractTestCase. The default -// implementation checks to see if the name of the class contains the word -// "AbstractTest" (case sensitive). -+ (BOOL)isAbstractTestCase; - -@end diff --git a/toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.m b/toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.m deleted file mode 100644 index 162f01e97..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/mac/testing/GTMSenTestCase.m +++ /dev/null @@ -1,428 +0,0 @@ -// -// GTMSenTestCase.m -// -// Copyright 2007-2008 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); you may not -// use this file except in compliance with the License. You may obtain a copy -// of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations under -// the License. -// - -#import "GTMSenTestCase.h" - -#import <unistd.h> -#if GTM_IPHONE_SIMULATOR -#import <objc/message.h> -#endif - -#import "GTMObjC2Runtime.h" -#import "GTMUnitTestDevLog.h" - -#if GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST -#import <stdarg.h> - -@interface NSException (GTMSenTestPrivateAdditions) -+ (NSException *)failureInFile:(NSString *)filename - atLine:(int)lineNumber - reason:(NSString *)reason; -@end - -@implementation NSException (GTMSenTestPrivateAdditions) -+ (NSException *)failureInFile:(NSString *)filename - atLine:(int)lineNumber - reason:(NSString *)reason { - NSDictionary *userInfo = - [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithInteger:lineNumber], SenTestLineNumberKey, - filename, SenTestFilenameKey, - nil]; - - return [self exceptionWithName:SenTestFailureException - reason:reason - userInfo:userInfo]; -} -@end - -@implementation NSException (GTMSenTestAdditions) - -+ (NSException *)failureInFile:(NSString *)filename - atLine:(int)lineNumber - withDescription:(NSString *)formatString, ... { - - NSString *testDescription = @""; - if (formatString) { - va_list vl; - va_start(vl, formatString); - testDescription = - [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - } - - NSString *reason = testDescription; - - return [self failureInFile:filename atLine:lineNumber reason:reason]; -} - -+ (NSException *)failureInCondition:(NSString *)condition - isTrue:(BOOL)isTrue - inFile:(NSString *)filename - atLine:(int)lineNumber - withDescription:(NSString *)formatString, ... { - - NSString *testDescription = @""; - if (formatString) { - va_list vl; - va_start(vl, formatString); - testDescription = - [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - } - - NSString *reason = [NSString stringWithFormat:@"'%@' should be %s. %@", - condition, isTrue ? "false" : "true", testDescription]; - - return [self failureInFile:filename atLine:lineNumber reason:reason]; -} - -+ (NSException *)failureInEqualityBetweenObject:(id)left - andObject:(id)right - inFile:(NSString *)filename - atLine:(int)lineNumber - withDescription:(NSString *)formatString, ... { - - NSString *testDescription = @""; - if (formatString) { - va_list vl; - va_start(vl, formatString); - testDescription = - [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - } - - NSString *reason = - [NSString stringWithFormat:@"'%@' should be equal to '%@'. %@", - [left description], [right description], testDescription]; - - return [self failureInFile:filename atLine:lineNumber reason:reason]; -} - -+ (NSException *)failureInEqualityBetweenValue:(NSValue *)left - andValue:(NSValue *)right - withAccuracy:(NSValue *)accuracy - inFile:(NSString *)filename - atLine:(int)lineNumber - withDescription:(NSString *)formatString, ... { - - NSString *testDescription = @""; - if (formatString) { - va_list vl; - va_start(vl, formatString); - testDescription = - [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - } - - NSString *reason; - if (accuracy) { - reason = - [NSString stringWithFormat:@"'%@' should be equal to '%@'. %@", - left, right, testDescription]; - } else { - reason = - [NSString stringWithFormat:@"'%@' should be equal to '%@' +/-'%@'. %@", - left, right, accuracy, testDescription]; - } - - return [self failureInFile:filename atLine:lineNumber reason:reason]; -} - -+ (NSException *)failureInRaise:(NSString *)expression - inFile:(NSString *)filename - atLine:(int)lineNumber - withDescription:(NSString *)formatString, ... { - - NSString *testDescription = @""; - if (formatString) { - va_list vl; - va_start(vl, formatString); - testDescription = - [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - } - - NSString *reason = [NSString stringWithFormat:@"'%@' should raise. %@", - expression, testDescription]; - - return [self failureInFile:filename atLine:lineNumber reason:reason]; -} - -+ (NSException *)failureInRaise:(NSString *)expression - exception:(NSException *)exception - inFile:(NSString *)filename - atLine:(int)lineNumber - withDescription:(NSString *)formatString, ... { - - NSString *testDescription = @""; - if (formatString) { - va_list vl; - va_start(vl, formatString); - testDescription = - [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - } - - NSString *reason; - if ([[exception name] isEqualToString:SenTestFailureException]) { - // it's our exception, assume it has the right description on it. - reason = [exception reason]; - } else { - // not one of our exception, use the exceptions reason and our description - reason = [NSString stringWithFormat:@"'%@' raised '%@'. %@", - expression, [exception reason], testDescription]; - } - - return [self failureInFile:filename atLine:lineNumber reason:reason]; -} - -@end - -NSString *STComposeString(NSString *formatString, ...) { - NSString *reason = @""; - if (formatString) { - va_list vl; - va_start(vl, formatString); - reason = - [[[NSString alloc] initWithFormat:formatString arguments:vl] autorelease]; - va_end(vl); - } - return reason; -} - -NSString *const SenTestFailureException = @"SenTestFailureException"; -NSString *const SenTestFilenameKey = @"SenTestFilenameKey"; -NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey"; - -@interface SenTestCase (SenTestCasePrivate) -// our method of logging errors -+ (void)printException:(NSException *)exception fromTestName:(NSString *)name; -@end - -@implementation SenTestCase -+ (id)testCaseWithInvocation:(NSInvocation *)anInvocation { - return [[[self alloc] initWithInvocation:anInvocation] autorelease]; -} - -- (id)initWithInvocation:(NSInvocation *)anInvocation { - if ((self = [super init])) { - invocation_ = [anInvocation retain]; - } - return self; -} - -- (void)dealloc { - [invocation_ release]; - [super dealloc]; -} - -- (void)failWithException:(NSException*)exception { - [exception raise]; -} - -- (void)setUp { -} - -- (void)performTest { - @try { - [self invokeTest]; - } @catch (NSException *exception) { - [[self class] printException:exception - fromTestName:NSStringFromSelector([self selector])]; - [exception raise]; - } -} - -- (NSInvocation *)invocation { - return invocation_; -} - -- (SEL)selector { - return [invocation_ selector]; -} - -+ (void)printException:(NSException *)exception fromTestName:(NSString *)name { - NSDictionary *userInfo = [exception userInfo]; - NSString *filename = [userInfo objectForKey:SenTestFilenameKey]; - NSNumber *lineNumber = [userInfo objectForKey:SenTestLineNumberKey]; - NSString *className = NSStringFromClass([self class]); - if ([filename length] == 0) { - filename = @"Unknown.m"; - } - fprintf(stderr, "%s:%ld: error: -[%s %s] : %s\n", - [filename UTF8String], - (long)[lineNumber integerValue], - [className UTF8String], - [name UTF8String], - [[exception reason] UTF8String]); - fflush(stderr); -} - -- (void)invokeTest { - NSException *e = nil; - @try { - // Wrap things in autorelease pools because they may - // have an STMacro in their dealloc which may get called - // when the pool is cleaned up - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - // We don't log exceptions here, instead we let the person that called - // this log the exception. This ensures they are only logged once but the - // outer layers get the exceptions to report counts, etc. - @try { - [self setUp]; - @try { - NSInvocation *invocation = [self invocation]; -#if GTM_IPHONE_SIMULATOR - // We don't call [invocation invokeWithTarget:self]; because of - // Radar 8081169: NSInvalidArgumentException can't be caught - // It turns out that on iOS4 (and 3.2) exceptions thrown inside an - // [invocation invoke] on the simulator cannot be caught. - // http://openradar.appspot.com/8081169 - objc_msgSend(self, [invocation selector]); -#else - [invocation invokeWithTarget:self]; -#endif - } @catch (NSException *exception) { - e = [exception retain]; - } - [self tearDown]; - } @catch (NSException *exception) { - e = [exception retain]; - } - [pool release]; - } @catch (NSException *exception) { - e = [exception retain]; - } - if (e) { - [e autorelease]; - [e raise]; - } -} - -- (void)tearDown { -} - -- (NSString *)description { - // This matches the description OCUnit would return to you - return [NSString stringWithFormat:@"-[%@ %@]", [self class], - NSStringFromSelector([self selector])]; -} - -// Used for sorting methods below -static int MethodSort(id a, id b, void *context) { - NSInvocation *invocationA = a; - NSInvocation *invocationB = b; - const char *nameA = sel_getName([invocationA selector]); - const char *nameB = sel_getName([invocationB selector]); - return strcmp(nameA, nameB); -} - - -+ (NSArray *)testInvocations { - NSMutableArray *invocations = nil; - // Need to walk all the way up the parent classes collecting methods (in case - // a test is a subclass of another test). - Class senTestCaseClass = [SenTestCase class]; - for (Class currentClass = self; - currentClass && (currentClass != senTestCaseClass); - currentClass = class_getSuperclass(currentClass)) { - unsigned int methodCount; - Method *methods = class_copyMethodList(currentClass, &methodCount); - if (methods) { - // This handles disposing of methods for us even if an exception should fly. - [NSData dataWithBytesNoCopy:methods - length:sizeof(Method) * methodCount]; - if (!invocations) { - invocations = [NSMutableArray arrayWithCapacity:methodCount]; - } - for (size_t i = 0; i < methodCount; ++i) { - Method currMethod = methods[i]; - SEL sel = method_getName(currMethod); - char *returnType = NULL; - const char *name = sel_getName(sel); - // If it starts with test, takes 2 args (target and sel) and returns - // void run it. - if (strstr(name, "test") == name) { - returnType = method_copyReturnType(currMethod); - if (returnType) { - // This handles disposing of returnType for us even if an - // exception should fly. Length +1 for the terminator, not that - // the length really matters here, as we never reference inside - // the data block. - [NSData dataWithBytesNoCopy:returnType - length:strlen(returnType) + 1]; - } - } - // TODO: If a test class is a subclass of another, and they reuse the - // same selector name (ie-subclass overrides it), this current loop - // and test here will cause cause it to get invoked twice. To fix this - // the selector would have to be checked against all the ones already - // added, so it only gets done once. - if (returnType // True if name starts with "test" - && strcmp(returnType, @encode(void)) == 0 - && method_getNumberOfArguments(currMethod) == 2) { - NSMethodSignature *sig = [self instanceMethodSignatureForSelector:sel]; - NSInvocation *invocation - = [NSInvocation invocationWithMethodSignature:sig]; - [invocation setSelector:sel]; - [invocations addObject:invocation]; - } - } - } - } - // Match SenTestKit and run everything in alphbetical order. - [invocations sortUsingFunction:MethodSort context:nil]; - return invocations; -} - -@end - -#endif // GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST - -@implementation GTMTestCase : SenTestCase -- (void)invokeTest { - NSAutoreleasePool *localPool = [[NSAutoreleasePool alloc] init]; - Class devLogClass = NSClassFromString(@"GTMUnitTestDevLog"); - if (devLogClass) { - [devLogClass performSelector:@selector(enableTracking)]; - [devLogClass performSelector:@selector(verifyNoMoreLogsExpected)]; - - } - [super invokeTest]; - if (devLogClass) { - [devLogClass performSelector:@selector(verifyNoMoreLogsExpected)]; - [devLogClass performSelector:@selector(disableTracking)]; - } - [localPool drain]; -} - -+ (BOOL)isAbstractTestCase { - NSString *name = NSStringFromClass(self); - return [name rangeOfString:@"AbstractTest"].location != NSNotFound; -} - -+ (NSArray *)testInvocations { - NSArray *invocations = nil; - if (![self isAbstractTestCase]) { - invocations = [super testInvocations]; - } - return invocations; -} - -@end diff --git a/toolkit/crashreporter/google-breakpad/src/common/md5.cc b/toolkit/crashreporter/google-breakpad/src/common/md5.cc deleted file mode 100644 index a0d9a1bdd..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/md5.cc +++ /dev/null @@ -1,251 +0,0 @@ -/* - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - */ - -#include <string.h> - -#include "common/md5.h" - -namespace google_breakpad { - -#ifndef WORDS_BIGENDIAN -#define byteReverse(buf, len) /* Nothing */ -#else -/* - * Note: this code is harmless on little-endian machines. - */ -static void byteReverse(unsigned char *buf, unsigned longs) -{ - u32 t; - do { - t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 | - ((unsigned) buf[1] << 8 | buf[0]); - *(u32 *) buf = t; - buf += 4; - } while (--longs); -} -#endif - -static void MD5Transform(u32 buf[4], u32 const in[16]); - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void MD5Init(struct MD5Context *ctx) -{ - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len) -{ - u32 t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((u32) len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if (t) { - unsigned char *p = (unsigned char *) ctx->in + t; - - t = 64 - t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (u32 *) ctx->in); - buf += t; - len -= t; - } - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (u32 *) ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void MD5Final(unsigned char digest[16], struct MD5Context *ctx) -{ - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (u32 *) ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count - 8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((u32 *) ctx->in)[14] = ctx->bits[0]; - ((u32 *) ctx->in)[15] = ctx->bits[1]; - - MD5Transform(ctx->buf, (u32 *) ctx->in); - byteReverse((unsigned char *) ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ -} - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -static void MD5Transform(u32 buf[4], u32 const in[16]) -{ - u32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -} // namespace google_breakpad - diff --git a/toolkit/crashreporter/google-breakpad/src/common/md5.h b/toolkit/crashreporter/google-breakpad/src/common/md5.h deleted file mode 100644 index 2ab0ab95a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/md5.h +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2007 Google Inc. All Rights Reserved. -// Author: liuli@google.com (Liu Li) -#ifndef COMMON_MD5_H__ -#define COMMON_MD5_H__ - -#include <stdint.h> - -namespace google_breakpad { - -typedef uint32_t u32; -typedef uint8_t u8; - -struct MD5Context { - u32 buf[4]; - u32 bits[2]; - u8 in[64]; -}; - -void MD5Init(struct MD5Context *ctx); - -void MD5Update(struct MD5Context *ctx, unsigned char const *buf, size_t len); - -void MD5Final(unsigned char digest[16], struct MD5Context *ctx); - -} // namespace google_breakpad - -#endif // COMMON_MD5_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/memory.h b/toolkit/crashreporter/google-breakpad/src/common/memory.h deleted file mode 100644 index 9158b50c8..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/memory.h +++ /dev/null @@ -1,249 +0,0 @@ -// 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. - -#ifndef GOOGLE_BREAKPAD_COMMON_MEMORY_H_ -#define GOOGLE_BREAKPAD_COMMON_MEMORY_H_ - -#include <stdint.h> -#include <stdlib.h> -#include <unistd.h> -#include <sys/mman.h> - -#include <memory> -#include <vector> - -#if defined(MEMORY_SANITIZER) -#include <sanitizer/msan_interface.h> -#endif - -#ifdef __APPLE__ -#define sys_mmap mmap -#define sys_munmap munmap -#define MAP_ANONYMOUS MAP_ANON -#else -#include "third_party/lss/linux_syscall_support.h" -#endif - -namespace google_breakpad { - -// This is very simple allocator which fetches pages from the kernel directly. -// Thus, it can be used even when the heap may be corrupted. -// -// There is no free operation. The pages are only freed when the object is -// destroyed. -class PageAllocator { - public: - PageAllocator() - : page_size_(getpagesize()), - last_(NULL), - current_page_(NULL), - page_offset_(0), - pages_allocated_(0) { - } - - ~PageAllocator() { - FreeAll(); - } - - void *Alloc(size_t bytes) { - if (!bytes) - return NULL; - - if (current_page_ && page_size_ - page_offset_ >= bytes) { - uint8_t *const ret = current_page_ + page_offset_; - page_offset_ += bytes; - if (page_offset_ == page_size_) { - page_offset_ = 0; - current_page_ = NULL; - } - - return ret; - } - - const size_t pages = - (bytes + sizeof(PageHeader) + page_size_ - 1) / page_size_; - uint8_t *const ret = GetNPages(pages); - if (!ret) - return NULL; - - page_offset_ = - (page_size_ - (page_size_ * pages - (bytes + sizeof(PageHeader)))) % - page_size_; - current_page_ = page_offset_ ? ret + page_size_ * (pages - 1) : NULL; - - return ret + sizeof(PageHeader); - } - - // Checks whether the page allocator owns the passed-in pointer. - // This method exists for testing pursposes only. - bool OwnsPointer(const void* p) { - for (PageHeader* header = last_; header; header = header->next) { - const char* current = reinterpret_cast<char*>(header); - if ((p >= current) && (p < current + header->num_pages * page_size_)) - return true; - } - - return false; - } - - unsigned long pages_allocated() { return pages_allocated_; } - - private: - uint8_t *GetNPages(size_t num_pages) { - void *a = sys_mmap(NULL, page_size_ * num_pages, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (a == MAP_FAILED) - return NULL; - -#if defined(MEMORY_SANITIZER) - // We need to indicate to MSan that memory allocated through sys_mmap is - // initialized, since linux_syscall_support.h doesn't have MSan hooks. - __msan_unpoison(a, page_size_ * num_pages); -#endif - - struct PageHeader *header = reinterpret_cast<PageHeader*>(a); - header->next = last_; - header->num_pages = num_pages; - last_ = header; - - pages_allocated_ += num_pages; - - return reinterpret_cast<uint8_t*>(a); - } - - void FreeAll() { - PageHeader *next; - - for (PageHeader *cur = last_; cur; cur = next) { - next = cur->next; - sys_munmap(cur, cur->num_pages * page_size_); - } - } - - struct PageHeader { - PageHeader *next; // pointer to the start of the next set of pages. - size_t num_pages; // the number of pages in this set. - }; - - const size_t page_size_; - PageHeader *last_; - uint8_t *current_page_; - size_t page_offset_; - unsigned long pages_allocated_; -}; - -// Wrapper to use with STL containers -template <typename T> -struct PageStdAllocator : public std::allocator<T> { - typedef typename std::allocator<T>::pointer pointer; - typedef typename std::allocator<T>::size_type size_type; - - explicit PageStdAllocator(PageAllocator& allocator) : allocator_(allocator), - stackdata_(NULL), - stackdata_size_(0) - {} - - template <class Other> PageStdAllocator(const PageStdAllocator<Other>& other) - : allocator_(other.allocator_), - stackdata_(nullptr), - stackdata_size_(0) - {} - - explicit PageStdAllocator(PageAllocator& allocator, - pointer stackdata, - size_type stackdata_size) : allocator_(allocator), - stackdata_(stackdata), - stackdata_size_(stackdata_size) - {} - - inline pointer allocate(size_type n, const void* = 0) { - const size_type size = sizeof(T) * n; - if (size <= stackdata_size_) { - return stackdata_; - } - return static_cast<pointer>(allocator_.Alloc(size)); - } - - inline void deallocate(pointer, size_type) { - // The PageAllocator doesn't free. - } - - template <typename U> struct rebind { - typedef PageStdAllocator<U> other; - }; - - private: - // Silly workaround for the gcc from Android's ndk (gcc 4.6), which will - // otherwise complain that `other.allocator_` is private in the constructor - // code. - template<typename Other> friend struct PageStdAllocator; - - PageAllocator& allocator_; - pointer stackdata_; - size_type stackdata_size_; -}; - -// A wasteful vector is a std::vector, except that it allocates memory from a -// PageAllocator. It's wasteful because, when resizing, it always allocates a -// whole new array since the PageAllocator doesn't support realloc. -template<class T> -class wasteful_vector : public std::vector<T, PageStdAllocator<T> > { - public: - wasteful_vector(PageAllocator* allocator, unsigned size_hint = 16) - : std::vector<T, PageStdAllocator<T> >(PageStdAllocator<T>(*allocator)) { - std::vector<T, PageStdAllocator<T> >::reserve(size_hint); - } - protected: - wasteful_vector(PageStdAllocator<T> allocator) - : std::vector<T, PageStdAllocator<T> >(allocator) {} -}; - -// auto_wasteful_vector allocates space on the stack for N entries to avoid -// using the PageAllocator for small data, while still allowing for larger data. -template<class T, unsigned int N> -class auto_wasteful_vector : public wasteful_vector<T> { - T stackdata_[N]; - public: - auto_wasteful_vector(PageAllocator* allocator) - : wasteful_vector<T>( - PageStdAllocator<T>(*allocator, - &stackdata_[0], - sizeof(stackdata_))) { - std::vector<T, PageStdAllocator<T> >::reserve(N); - } -}; - -} // namespace google_breakpad - -inline void* operator new(size_t nbytes, - google_breakpad::PageAllocator& allocator) { - return allocator.Alloc(nbytes); -} - -#endif // GOOGLE_BREAKPAD_COMMON_MEMORY_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/memory_range.h b/toolkit/crashreporter/google-breakpad/src/common/memory_range.h deleted file mode 100644 index 41dd2da62..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/memory_range.h +++ /dev/null @@ -1,145 +0,0 @@ -// 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_range.h: Define the google_breakpad::MemoryRange class, which -// is a lightweight wrapper with a pointer and a length to encapsulate -// a contiguous range of memory. - -#ifndef COMMON_MEMORY_RANGE_H_ -#define COMMON_MEMORY_RANGE_H_ - -#include <stddef.h> - -#include "google_breakpad/common/breakpad_types.h" - -namespace google_breakpad { - -// A lightweight wrapper with a pointer and a length to encapsulate a -// contiguous range of memory. It provides helper methods for checked -// access of a subrange of the memory. Its implemementation does not -// allocate memory or call into libc functions, and is thus safer to use -// in a crashed environment. -class MemoryRange { - public: - MemoryRange() : data_(NULL), length_(0) {} - - MemoryRange(const void* data, size_t length) { - Set(data, length); - } - - // Returns true if this memory range contains no data. - bool IsEmpty() const { - // Set() guarantees that |length_| is zero if |data_| is NULL. - return length_ == 0; - } - - // Resets to an empty range. - void Reset() { - data_ = NULL; - length_ = 0; - } - - // Sets this memory range to point to |data| and its length to |length|. - void Set(const void* data, size_t length) { - data_ = reinterpret_cast<const uint8_t*>(data); - // Always set |length_| to zero if |data_| is NULL. - length_ = data ? length : 0; - } - - // Returns true if this range covers a subrange of |sub_length| bytes - // at |sub_offset| bytes of this memory range, or false otherwise. - bool Covers(size_t sub_offset, size_t sub_length) const { - // The following checks verify that: - // 1. sub_offset is within [ 0 .. length_ - 1 ] - // 2. sub_offset + sub_length is within - // [ sub_offset .. length_ ] - return sub_offset < length_ && - sub_offset + sub_length >= sub_offset && - sub_offset + sub_length <= length_; - } - - // Returns a raw data pointer to a subrange of |sub_length| bytes at - // |sub_offset| bytes of this memory range, or NULL if the subrange - // is out of bounds. - const void* GetData(size_t sub_offset, size_t sub_length) const { - return Covers(sub_offset, sub_length) ? (data_ + sub_offset) : NULL; - } - - // Same as the two-argument version of GetData() but uses sizeof(DataType) - // as the subrange length and returns an |DataType| pointer for convenience. - template <typename DataType> - const DataType* GetData(size_t sub_offset) const { - return reinterpret_cast<const DataType*>( - GetData(sub_offset, sizeof(DataType))); - } - - // Returns a raw pointer to the |element_index|-th element of an array - // of elements of length |element_size| starting at |sub_offset| bytes - // of this memory range, or NULL if the element is out of bounds. - const void* GetArrayElement(size_t element_offset, - size_t element_size, - unsigned element_index) const { - size_t sub_offset = element_offset + element_index * element_size; - return GetData(sub_offset, element_size); - } - - // Same as the three-argument version of GetArrayElement() but deduces - // the element size using sizeof(ElementType) and returns an |ElementType| - // pointer for convenience. - template <typename ElementType> - const ElementType* GetArrayElement(size_t element_offset, - unsigned element_index) const { - return reinterpret_cast<const ElementType*>( - GetArrayElement(element_offset, sizeof(ElementType), element_index)); - } - - // Returns a subrange of |sub_length| bytes at |sub_offset| bytes of - // this memory range, or an empty range if the subrange is out of bounds. - MemoryRange Subrange(size_t sub_offset, size_t sub_length) const { - return Covers(sub_offset, sub_length) ? - MemoryRange(data_ + sub_offset, sub_length) : MemoryRange(); - } - - // Returns a pointer to the beginning of this memory range. - const uint8_t* data() const { return data_; } - - // Returns the length, in bytes, of this memory range. - size_t length() const { return length_; } - - private: - // Pointer to the beginning of this memory range. - const uint8_t* data_; - - // Length, in bytes, of this memory range. - size_t length_; -}; - -} // namespace google_breakpad - -#endif // COMMON_MEMORY_RANGE_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/memory_range_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/memory_range_unittest.cc deleted file mode 100644 index f6cf8c8b2..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/memory_range_unittest.cc +++ /dev/null @@ -1,193 +0,0 @@ -// 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_range_unittest.cc: Unit tests for google_breakpad::MemoryRange. - -#include "breakpad_googletest_includes.h" -#include "common/memory_range.h" - -using google_breakpad::MemoryRange; -using testing::Message; - -namespace { - -const uint32_t kBuffer[10] = { 0 }; -const size_t kBufferSize = sizeof(kBuffer); -const uint8_t* kBufferPointer = reinterpret_cast<const uint8_t*>(kBuffer); - -// Test vectors for verifying Covers, GetData, and Subrange. -const struct { - bool valid; - size_t offset; - size_t length; -} kSubranges[] = { - { true, 0, 0 }, - { true, 0, 2 }, - { true, 0, kBufferSize }, - { true, 2, 0 }, - { true, 2, 4 }, - { true, 2, kBufferSize - 2 }, - { true, kBufferSize - 1, 1 }, - { false, kBufferSize, 0 }, - { false, kBufferSize, static_cast<size_t>(-1) }, - { false, kBufferSize + 1, 0 }, - { false, static_cast<size_t>(-1), 2 }, - { false, 1, kBufferSize }, - { false, kBufferSize - 1, 2 }, - { false, 0, static_cast<size_t>(-1) }, - { false, 1, static_cast<size_t>(-1) }, -}; -const size_t kNumSubranges = sizeof(kSubranges) / sizeof(kSubranges[0]); - -// Test vectors for verifying GetArrayElement. -const struct { - size_t offset; - size_t size; - size_t index; - const void* const pointer; -} kElements[] = { - // Valid array elemenets - { 0, 1, 0, kBufferPointer }, - { 0, 1, 1, kBufferPointer + 1 }, - { 0, 1, kBufferSize - 1, kBufferPointer + kBufferSize - 1 }, - { 0, 2, 1, kBufferPointer + 2 }, - { 0, 4, 2, kBufferPointer + 8 }, - { 0, 4, 9, kBufferPointer + 36 }, - { kBufferSize - 1, 1, 0, kBufferPointer + kBufferSize - 1 }, - // Invalid array elemenets - { 0, 1, kBufferSize, NULL }, - { 0, 4, 10, NULL }, - { kBufferSize - 1, 1, 1, NULL }, - { kBufferSize - 1, 2, 0, NULL }, - { kBufferSize, 1, 0, NULL }, -}; -const size_t kNumElements = sizeof(kElements) / sizeof(kElements[0]); - -} // namespace - -TEST(MemoryRangeTest, DefaultConstructor) { - MemoryRange range; - EXPECT_EQ(NULL, range.data()); - EXPECT_EQ(0U, range.length()); -} - -TEST(MemoryRangeTest, ConstructorWithDataAndLength) { - MemoryRange range(kBuffer, kBufferSize); - EXPECT_EQ(kBufferPointer, range.data()); - EXPECT_EQ(kBufferSize, range.length()); -} - -TEST(MemoryRangeTest, Reset) { - MemoryRange range; - range.Reset(); - EXPECT_EQ(NULL, range.data()); - EXPECT_EQ(0U, range.length()); - - range.Set(kBuffer, kBufferSize); - EXPECT_EQ(kBufferPointer, range.data()); - EXPECT_EQ(kBufferSize, range.length()); - - range.Reset(); - EXPECT_EQ(NULL, range.data()); - EXPECT_EQ(0U, range.length()); -} - -TEST(MemoryRangeTest, Set) { - MemoryRange range; - range.Set(kBuffer, kBufferSize); - EXPECT_EQ(kBufferPointer, range.data()); - EXPECT_EQ(kBufferSize, range.length()); - - range.Set(NULL, 0); - EXPECT_EQ(NULL, range.data()); - EXPECT_EQ(0U, range.length()); -} - -TEST(MemoryRangeTest, SubrangeOfEmptyMemoryRange) { - MemoryRange range; - MemoryRange subrange = range.Subrange(0, 10); - EXPECT_EQ(NULL, subrange.data()); - EXPECT_EQ(0U, subrange.length()); -} - -TEST(MemoryRangeTest, SubrangeAndGetData) { - MemoryRange range(kBuffer, kBufferSize); - for (size_t i = 0; i < kNumSubranges; ++i) { - bool valid = kSubranges[i].valid; - size_t sub_offset = kSubranges[i].offset; - size_t sub_length = kSubranges[i].length; - SCOPED_TRACE(Message() << "offset=" << sub_offset - << ", length=" << sub_length); - - MemoryRange subrange = range.Subrange(sub_offset, sub_length); - if (valid) { - EXPECT_TRUE(range.Covers(sub_offset, sub_length)); - EXPECT_EQ(kBufferPointer + sub_offset, - range.GetData(sub_offset, sub_length)); - EXPECT_EQ(kBufferPointer + sub_offset, subrange.data()); - EXPECT_EQ(sub_length, subrange.length()); - } else { - EXPECT_FALSE(range.Covers(sub_offset, sub_length)); - EXPECT_EQ(NULL, range.GetData(sub_offset, sub_length)); - EXPECT_EQ(NULL, subrange.data()); - EXPECT_EQ(0U, subrange.length()); - } - } -} - -TEST(MemoryRangeTest, GetDataWithTemplateType) { - MemoryRange range(kBuffer, kBufferSize); - const char* char_pointer = range.GetData<char>(0); - EXPECT_EQ(reinterpret_cast<const char*>(kBufferPointer), char_pointer); - const int* int_pointer = range.GetData<int>(0); - EXPECT_EQ(reinterpret_cast<const int*>(kBufferPointer), int_pointer); -} - -TEST(MemoryRangeTest, GetArrayElement) { - MemoryRange range(kBuffer, kBufferSize); - for (size_t i = 0; i < kNumElements; ++i) { - size_t element_offset = kElements[i].offset; - size_t element_size = kElements[i].size; - unsigned element_index = kElements[i].index; - const void* const element_pointer = kElements[i].pointer; - SCOPED_TRACE(Message() << "offset=" << element_offset - << ", size=" << element_size - << ", index=" << element_index); - EXPECT_EQ(element_pointer, range.GetArrayElement( - element_offset, element_size, element_index)); - } -} - -TEST(MemoryRangeTest, GetArrayElmentWithTemplateType) { - MemoryRange range(kBuffer, kBufferSize); - const char* char_pointer = range.GetArrayElement<char>(0, 0); - EXPECT_EQ(reinterpret_cast<const char*>(kBufferPointer), char_pointer); - const int* int_pointer = range.GetArrayElement<int>(0, 0); - EXPECT_EQ(reinterpret_cast<const int*>(kBufferPointer), int_pointer); -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/memory_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/memory_unittest.cc deleted file mode 100644 index 8d2494c23..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/memory_unittest.cc +++ /dev/null @@ -1,124 +0,0 @@ -// 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 "breakpad_googletest_includes.h" -#include "common/memory.h" - -using namespace google_breakpad; - -namespace { -typedef testing::Test PageAllocatorTest; -} - -TEST(PageAllocatorTest, Setup) { - PageAllocator allocator; - EXPECT_EQ(0U, allocator.pages_allocated()); -} - -TEST(PageAllocatorTest, SmallObjects) { - PageAllocator allocator; - - EXPECT_EQ(0U, allocator.pages_allocated()); - for (unsigned i = 1; i < 1024; ++i) { - uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i)); - ASSERT_FALSE(p == NULL); - memset(p, 0, i); - } -} - -TEST(PageAllocatorTest, LargeObject) { - PageAllocator allocator; - - EXPECT_EQ(0U, allocator.pages_allocated()); - uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(10000)); - ASSERT_FALSE(p == NULL); - EXPECT_EQ(3U, allocator.pages_allocated()); - for (unsigned i = 1; i < 10; ++i) { - uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i)); - ASSERT_FALSE(p == NULL); - memset(p, 0, i); - } -} - -namespace { -typedef testing::Test WastefulVectorTest; -} - -TEST(WastefulVectorTest, Setup) { - PageAllocator allocator_; - wasteful_vector<int> v(&allocator_); - ASSERT_TRUE(v.empty()); - ASSERT_EQ(v.size(), 0u); -} - -TEST(WastefulVectorTest, Simple) { - PageAllocator allocator_; - EXPECT_EQ(0U, allocator_.pages_allocated()); - wasteful_vector<unsigned> v(&allocator_); - - for (unsigned i = 0; i < 256; ++i) { - v.push_back(i); - ASSERT_EQ(i, v.back()); - ASSERT_EQ(&v.back(), &v[i]); - } - ASSERT_FALSE(v.empty()); - ASSERT_EQ(v.size(), 256u); - EXPECT_EQ(1U, allocator_.pages_allocated()); - for (unsigned i = 0; i < 256; ++i) - ASSERT_EQ(v[i], i); -} - -TEST(WastefulVectorTest, UsesPageAllocator) { - PageAllocator allocator_; - wasteful_vector<unsigned> v(&allocator_); - EXPECT_EQ(1U, allocator_.pages_allocated()); - - v.push_back(1); - ASSERT_TRUE(allocator_.OwnsPointer(&v[0])); -} - -TEST(WastefulVectorTest, AutoWastefulVector) { - PageAllocator allocator_; - EXPECT_EQ(0U, allocator_.pages_allocated()); - - auto_wasteful_vector<unsigned, 4> v(&allocator_); - EXPECT_EQ(0U, allocator_.pages_allocated()); - - v.push_back(1); - EXPECT_EQ(0U, allocator_.pages_allocated()); - EXPECT_FALSE(allocator_.OwnsPointer(&v[0])); - - v.resize(4); - EXPECT_EQ(0U, allocator_.pages_allocated()); - EXPECT_FALSE(allocator_.OwnsPointer(&v[0])); - - v.resize(10); - EXPECT_EQ(1U, allocator_.pages_allocated()); - EXPECT_TRUE(allocator_.OwnsPointer(&v[0])); -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/minidump_type_helper.h b/toolkit/crashreporter/google-breakpad/src/common/minidump_type_helper.h deleted file mode 100644 index 5a7d5a6a8..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/minidump_type_helper.h +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) 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 GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_ -#define GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_ - -#include <stdint.h> - -#include "google_breakpad/common/minidump_format.h" - -namespace google_breakpad { - -template <size_t> -struct MDTypeHelper; - -template <> -struct MDTypeHelper<sizeof(uint32_t)> { - typedef MDRawDebug32 MDRawDebug; - typedef MDRawLinkMap32 MDRawLinkMap; -}; - -template <> -struct MDTypeHelper<sizeof(uint64_t)> { - typedef MDRawDebug64 MDRawDebug; - typedef MDRawLinkMap64 MDRawLinkMap; -}; - -} // namespace google_breakpad - -#endif // GOOGLE_BREAKPAD_COMMON_MINIDUMP_TYPE_HELPER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/module.cc b/toolkit/crashreporter/google-breakpad/src/common/module.cc deleted file mode 100644 index e701f1b59..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/module.cc +++ /dev/null @@ -1,348 +0,0 @@ -// 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: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// module.cc: Implement google_breakpad::Module. See module.h. - -#include "common/module.h" - -#include <assert.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> - -#include <iostream> -#include <utility> - -namespace google_breakpad { - -using std::dec; -using std::endl; -using std::hex; - - -Module::Module(const string &name, const string &os, - const string &architecture, const string &id, - const string &code_id /* = "" */) : - name_(name), - os_(os), - architecture_(architecture), - id_(id), - code_id_(code_id), - load_address_(0) { } - -Module::~Module() { - for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) - delete it->second; - for (FunctionSet::iterator it = functions_.begin(); - it != functions_.end(); ++it) { - delete *it; - } - for (StackFrameEntrySet::iterator it = stack_frame_entries_.begin(); - it != stack_frame_entries_.end(); ++it) { - delete *it; - } - for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it) - delete *it; -} - -void Module::SetLoadAddress(Address address) { - load_address_ = address; -} - -void Module::AddFunction(Function *function) { - // FUNC lines must not hold an empty name, so catch the problem early if - // callers try to add one. - assert(!function->name.empty()); - - // FUNCs are better than PUBLICs as they come with sizes, so remove an extern - // with the same address if present. - Extern ext(function->address); - ExternSet::iterator it_ext = externs_.find(&ext); - if (it_ext == externs_.end() && - architecture_ == "arm" && - (function->address & 0x1) == 0) { - // ARM THUMB functions have bit 0 set. ARM64 does not have THUMB. - Extern arm_thumb_ext(function->address | 0x1); - it_ext = externs_.find(&arm_thumb_ext); - } - if (it_ext != externs_.end()) { - delete *it_ext; - externs_.erase(it_ext); - } -#if _DEBUG - { - // There should be no other PUBLIC symbols that overlap with the function. - Extern debug_ext(function->address); - ExternSet::iterator it_debug = externs_.lower_bound(&ext); - assert(it_debug == externs_.end() || - (*it_debug)->address >= function->address + function->size); - } -#endif - - std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function); - if (!ret.second && (*ret.first != function)) { - // Free the duplicate that was not inserted because this Module - // now owns it. - delete function; - } -} - -void Module::AddFunctions(vector<Function *>::iterator begin, - vector<Function *>::iterator end) { - for (vector<Function *>::iterator it = begin; it != end; ++it) - AddFunction(*it); -} - -void Module::AddStackFrameEntry(StackFrameEntry* stack_frame_entry) { - std::pair<StackFrameEntrySet::iterator,bool> ret = - stack_frame_entries_.insert(stack_frame_entry); - if (!ret.second) { - // Free the duplicate that was not inserted because this Module - // now owns it. - delete stack_frame_entry; - } -} - -void Module::AddExtern(Extern *ext) { - std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext); - if (!ret.second) { - // Free the duplicate that was not inserted because this Module - // now owns it. - delete ext; - } -} - -void Module::GetFunctions(vector<Function *> *vec, - vector<Function *>::iterator i) { - vec->insert(i, functions_.begin(), functions_.end()); -} - -void Module::GetExterns(vector<Extern *> *vec, - vector<Extern *>::iterator i) { - vec->insert(i, externs_.begin(), externs_.end()); -} - -Module::File *Module::FindFile(const string &name) { - // A tricky bit here. The key of each map entry needs to be a - // pointer to the entry's File's name string. This means that we - // can't do the initial lookup with any operation that would create - // an empty entry for us if the name isn't found (like, say, - // operator[] or insert do), because such a created entry's key will - // be a pointer the string passed as our argument. Since the key of - // a map's value type is const, we can't fix it up once we've - // created our file. lower_bound does the lookup without doing an - // insertion, and returns a good hint iterator to pass to insert. - // Our "destiny" is where we belong, whether we're there or not now. - FileByNameMap::iterator destiny = files_.lower_bound(&name); - if (destiny == files_.end() - || *destiny->first != name) { // Repeated string comparison, boo hoo. - File *file = new File(name); - file->source_id = -1; - destiny = files_.insert(destiny, - FileByNameMap::value_type(&file->name, file)); - } - return destiny->second; -} - -Module::File *Module::FindFile(const char *name) { - string name_string = name; - return FindFile(name_string); -} - -Module::File *Module::FindExistingFile(const string &name) { - FileByNameMap::iterator it = files_.find(&name); - return (it == files_.end()) ? NULL : it->second; -} - -void Module::GetFiles(vector<File *> *vec) { - vec->clear(); - for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it) - vec->push_back(it->second); -} - -void Module::GetStackFrameEntries(vector<StackFrameEntry*>* vec) const { - vec->clear(); - vec->insert(vec->begin(), stack_frame_entries_.begin(), - stack_frame_entries_.end()); -} - -Module::StackFrameEntry* Module::FindStackFrameEntryByAddress(Address address) { - StackFrameEntry search; - search.address = address; - StackFrameEntrySet::iterator it = stack_frame_entries_.upper_bound(&search); - - if (it == stack_frame_entries_.begin()) - return NULL; - - it--; - if ((*it)->address <= address && address < (*it)->address + (*it)->size) - return *it; - - return NULL; -} - -void Module::AssignSourceIds() { - // First, give every source file an id of -1. - for (FileByNameMap::iterator file_it = files_.begin(); - file_it != files_.end(); ++file_it) { - file_it->second->source_id = -1; - } - - // Next, mark all files actually cited by our functions' line number - // info, by setting each one's source id to zero. - for (FunctionSet::const_iterator func_it = functions_.begin(); - func_it != functions_.end(); ++func_it) { - Function *func = *func_it; - for (vector<Line>::iterator line_it = func->lines.begin(); - line_it != func->lines.end(); ++line_it) - line_it->file->source_id = 0; - } - - // Finally, assign source ids to those files that have been marked. - // We could have just assigned source id numbers while traversing - // the line numbers, but doing it this way numbers the files in - // lexicographical order by name, which is neat. - int next_source_id = 0; - for (FileByNameMap::iterator file_it = files_.begin(); - file_it != files_.end(); ++file_it) { - if (!file_it->second->source_id) - file_it->second->source_id = next_source_id++; - } -} - -bool Module::ReportError() { - fprintf(stderr, "error writing symbol file: %s\n", - strerror(errno)); - return false; -} - -bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) { - for (RuleMap::const_iterator it = rule_map.begin(); - it != rule_map.end(); ++it) { - if (it != rule_map.begin()) - stream << ' '; - stream << it->first << ": " << it->second; - } - return stream.good(); -} - -bool Module::Write(std::ostream &stream, SymbolData symbol_data) { - stream << "MODULE " << os_ << " " << architecture_ << " " - << id_ << " " << name_ << endl; - if (!stream.good()) - return ReportError(); - - if (!code_id_.empty()) { - stream << "INFO CODE_ID " << code_id_ << endl; - } - - if (symbol_data != ONLY_CFI) { - AssignSourceIds(); - - // Write out files. - for (FileByNameMap::iterator file_it = files_.begin(); - file_it != files_.end(); ++file_it) { - File *file = file_it->second; - if (file->source_id >= 0) { - stream << "FILE " << file->source_id << " " << file->name << endl; - if (!stream.good()) - return ReportError(); - } - } - - // Write out functions and their lines. - for (FunctionSet::const_iterator func_it = functions_.begin(); - func_it != functions_.end(); ++func_it) { - Function *func = *func_it; - stream << "FUNC " << hex - << (func->address - load_address_) << " " - << func->size << " " - << func->parameter_size << " " - << func->name << dec << endl; - if (!stream.good()) - return ReportError(); - - for (vector<Line>::iterator line_it = func->lines.begin(); - line_it != func->lines.end(); ++line_it) { - stream << hex - << (line_it->address - load_address_) << " " - << line_it->size << " " - << dec - << line_it->number << " " - << line_it->file->source_id << endl; - if (!stream.good()) - return ReportError(); - } - } - - // Write out 'PUBLIC' records. - for (ExternSet::const_iterator extern_it = externs_.begin(); - extern_it != externs_.end(); ++extern_it) { - Extern *ext = *extern_it; - stream << "PUBLIC " << hex - << (ext->address - load_address_) << " 0 " - << ext->name << dec << endl; - } - } - - if (symbol_data != NO_CFI) { - // Write out 'STACK CFI INIT' and 'STACK CFI' records. - StackFrameEntrySet::const_iterator frame_it; - for (frame_it = stack_frame_entries_.begin(); - frame_it != stack_frame_entries_.end(); ++frame_it) { - StackFrameEntry *entry = *frame_it; - stream << "STACK CFI INIT " << hex - << (entry->address - load_address_) << " " - << entry->size << " " << dec; - if (!stream.good() - || !WriteRuleMap(entry->initial_rules, stream)) - return ReportError(); - - stream << endl; - - // Write out this entry's delta rules as 'STACK CFI' records. - for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin(); - delta_it != entry->rule_changes.end(); ++delta_it) { - stream << "STACK CFI " << hex - << (delta_it->first - load_address_) << " " << dec; - if (!stream.good() - || !WriteRuleMap(delta_it->second, stream)) - return ReportError(); - - stream << endl; - } - } - } - - return true; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/module.h b/toolkit/crashreporter/google-breakpad/src/common/module.h deleted file mode 100644 index 305f94579..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/module.h +++ /dev/null @@ -1,351 +0,0 @@ -// -*- mode: c++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// module.h: Define google_breakpad::Module. A Module holds debugging -// information, and can write that information out as a Breakpad -// symbol file. - -#ifndef COMMON_LINUX_MODULE_H__ -#define COMMON_LINUX_MODULE_H__ - -#include <iostream> -#include <map> -#include <set> -#include <string> -#include <vector> - -#include "common/symbol_data.h" -#include "common/using_std_string.h" -#include "google_breakpad/common/breakpad_types.h" - -namespace google_breakpad { - -using std::set; -using std::vector; -using std::map; - -// A Module represents the contents of a module, and supports methods -// for adding information produced by parsing STABS or DWARF data -// --- possibly both from the same file --- and then writing out the -// unified contents as a Breakpad-format symbol file. -class Module { - public: - // The type of addresses and sizes in a symbol table. - typedef uint64_t Address; - struct File; - struct Function; - struct Line; - struct Extern; - - // Addresses appearing in File, Function, and Line structures are - // absolute, not relative to the the module's load address. That - // is, if the module were loaded at its nominal load address, the - // addresses would be correct. - - // A source file. - struct File { - explicit File(const string &name_input) : name(name_input), source_id(0) {} - - // The name of the source file. - const string name; - - // The file's source id. The Write member function clears this - // field and assigns source ids a fresh, so any value placed here - // before calling Write will be lost. - int source_id; - }; - - // A function. - struct Function { - Function(const string &name_input, const Address &address_input) : - name(name_input), address(address_input), size(0), parameter_size(0) {} - - // For sorting by address. (Not style-guide compliant, but it's - // stupid not to put this in the struct.) - static bool CompareByAddress(const Function *x, const Function *y) { - return x->address < y->address; - } - - // The function's name. - const string name; - - // The start address and length of the function's code. - const Address address; - Address size; - - // The function's parameter size. - Address parameter_size; - - // Source lines belonging to this function, sorted by increasing - // address. - vector<Line> lines; - }; - - // A source line. - struct Line { - // For sorting by address. (Not style-guide compliant, but it's - // stupid not to put this in the struct.) - static bool CompareByAddress(const Module::Line &x, const Module::Line &y) { - return x.address < y.address; - } - - Address address, size; // The address and size of the line's code. - File *file; // The source file. - int number; // The source line number. - }; - - // An exported symbol. - struct Extern { - explicit Extern(const Address &address_input) : address(address_input) {} - const Address address; - string name; - }; - - // A map from register names to postfix expressions that recover - // their their values. This can represent a complete set of rules to - // follow at some address, or a set of changes to be applied to an - // extant set of rules. - typedef map<string, string> RuleMap; - - // A map from addresses to RuleMaps, representing changes that take - // effect at given addresses. - typedef map<Address, RuleMap> RuleChangeMap; - - // A range of 'STACK CFI' stack walking information. An instance of - // this structure corresponds to a 'STACK CFI INIT' record and the - // subsequent 'STACK CFI' records that fall within its range. - struct StackFrameEntry { - // The starting address and number of bytes of machine code this - // entry covers. - Address address, size; - - // The initial register recovery rules, in force at the starting - // address. - RuleMap initial_rules; - - // A map from addresses to rule changes. To find the rules in - // force at a given address, start with initial_rules, and then - // apply the changes given in this map for all addresses up to and - // including the address you're interested in. - RuleChangeMap rule_changes; - }; - - struct FunctionCompare { - bool operator() (const Function *lhs, - const Function *rhs) const { - if (lhs->address == rhs->address) - return lhs->name < rhs->name; - return lhs->address < rhs->address; - } - }; - - struct ExternCompare { - bool operator() (const Extern *lhs, - const Extern *rhs) const { - return lhs->address < rhs->address; - } - }; - - struct StackFrameEntryCompare { - bool operator() (const StackFrameEntry* lhs, - const StackFrameEntry* rhs) const { - return lhs->address < rhs->address; - } - }; - - // Create a new module with the given name, operating system, - // architecture, and ID string. - Module(const string &name, const string &os, const string &architecture, - const string &id, const string &code_id = ""); - ~Module(); - - // Set the module's load address to LOAD_ADDRESS; addresses given - // for functions and lines will be written to the Breakpad symbol - // file as offsets from this address. Construction initializes this - // module's load address to zero: addresses written to the symbol - // file will be the same as they appear in the Function, Line, and - // StackFrameEntry structures. - // - // Note that this member function has no effect on addresses stored - // in the data added to this module; the Write member function - // simply subtracts off the load address from addresses before it - // prints them. Only the last load address given before calling - // Write is used. - void SetLoadAddress(Address load_address); - - // Add FUNCTION to the module. FUNCTION's name must not be empty. - // This module owns all Function objects added with this function: - // destroying the module destroys them as well. - void AddFunction(Function *function); - - // Add all the functions in [BEGIN,END) to the module. - // This module owns all Function objects added with this function: - // destroying the module destroys them as well. - void AddFunctions(vector<Function *>::iterator begin, - vector<Function *>::iterator end); - - // Add STACK_FRAME_ENTRY to the module. - // This module owns all StackFrameEntry objects added with this - // function: destroying the module destroys them as well. - void AddStackFrameEntry(StackFrameEntry *stack_frame_entry); - - // Add PUBLIC to the module. - // This module owns all Extern objects added with this function: - // destroying the module destroys them as well. - void AddExtern(Extern *ext); - - // If this module has a file named NAME, return a pointer to it. If - // it has none, then create one and return a pointer to the new - // file. This module owns all File objects created using these - // functions; destroying the module destroys them as well. - File *FindFile(const string &name); - File *FindFile(const char *name); - - // If this module has a file named NAME, return a pointer to it. - // Otherwise, return NULL. - File *FindExistingFile(const string &name); - - // Insert pointers to the functions added to this module at I in - // VEC. The pointed-to Functions are still owned by this module. - // (Since this is effectively a copy of the function list, this is - // mostly useful for testing; other uses should probably get a more - // appropriate interface.) - void GetFunctions(vector<Function *> *vec, vector<Function *>::iterator i); - - // Insert pointers to the externs added to this module at I in - // VEC. The pointed-to Externs are still owned by this module. - // (Since this is effectively a copy of the extern list, this is - // mostly useful for testing; other uses should probably get a more - // appropriate interface.) - void GetExterns(vector<Extern *> *vec, vector<Extern *>::iterator i); - - // Clear VEC and fill it with pointers to the Files added to this - // module, sorted by name. The pointed-to Files are still owned by - // this module. (Since this is effectively a copy of the file list, - // this is mostly useful for testing; other uses should probably get - // a more appropriate interface.) - void GetFiles(vector<File *> *vec); - - // Clear VEC and fill it with pointers to the StackFrameEntry - // objects that have been added to this module. (Since this is - // effectively a copy of the stack frame entry list, this is mostly - // useful for testing; other uses should probably get - // a more appropriate interface.) - void GetStackFrameEntries(vector<StackFrameEntry *> *vec) const; - - // If this module has a StackFrameEntry whose address range covers - // ADDRESS, return it. Otherwise return NULL. - StackFrameEntry* FindStackFrameEntryByAddress(Address address); - - // Find those files in this module that are actually referred to by - // functions' line number data, and assign them source id numbers. - // Set the source id numbers for all other files --- unused by the - // source line data --- to -1. We do this before writing out the - // symbol file, at which point we omit any unused files. - void AssignSourceIds(); - - // Call AssignSourceIds, and write this module to STREAM in the - // breakpad symbol format. Return true if all goes well, or false if - // an error occurs. This method writes out: - // - a header based on the values given to the constructor, - // If symbol_data is not ONLY_CFI then: - // - the source files added via FindFile, - // - the functions added via AddFunctions, each with its lines, - // - all public records, - // If symbol_data is not NO_CFI then: - // - all CFI records. - // Addresses in the output are all relative to the load address - // established by SetLoadAddress. - bool Write(std::ostream &stream, SymbolData symbol_data); - - string name() const { return name_; } - string os() const { return os_; } - string architecture() const { return architecture_; } - string identifier() const { return id_; } - string code_identifier() const { return code_id_; } - - private: - // Report an error that has occurred writing the symbol file, using - // errno to find the appropriate cause. Return false. - static bool ReportError(); - - // Write RULE_MAP to STREAM, in the form appropriate for 'STACK CFI' - // records, without a final newline. Return true if all goes well; - // if an error occurs, return false, and leave errno set. - static bool WriteRuleMap(const RuleMap &rule_map, std::ostream &stream); - - // Module header entries. - string name_, os_, architecture_, id_, code_id_; - - // The module's nominal load address. Addresses for functions and - // lines are absolute, assuming the module is loaded at this - // address. - Address load_address_; - - // Relation for maps whose keys are strings shared with some other - // structure. - struct CompareStringPtrs { - bool operator()(const string *x, const string *y) const { return *x < *y; } - }; - - // A map from filenames to File structures. The map's keys are - // pointers to the Files' names. - typedef map<const string *, File *, CompareStringPtrs> FileByNameMap; - - // A set containing Function structures, sorted by address. - typedef set<Function *, FunctionCompare> FunctionSet; - - // A set containing Extern structures, sorted by address. - typedef set<Extern *, ExternCompare> ExternSet; - - // A set containing StackFrameEntry structures, sorted by address. - typedef set<StackFrameEntry*, StackFrameEntryCompare> StackFrameEntrySet; - - // The module owns all the files and functions that have been added - // to it; destroying the module frees the Files and Functions these - // point to. - FileByNameMap files_; // This module's source files. - FunctionSet functions_; // This module's functions. - - // The module owns all the call frame info entries that have been - // added to it. - StackFrameEntrySet stack_frame_entries_; - - // The module owns all the externs that have been added to it; - // destroying the module frees the Externs these point to. - ExternSet externs_; -}; - -} // namespace google_breakpad - -#endif // COMMON_LINUX_MODULE_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/module_unittest.cc deleted file mode 100644 index 3789f9ec5..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/module_unittest.cc +++ /dev/null @@ -1,616 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// module_unittest.cc: Unit tests for google_breakpad::Module. - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <algorithm> -#include <sstream> -#include <string> - -#include "breakpad_googletest_includes.h" -#include "common/module.h" -#include "common/using_std_string.h" - -using google_breakpad::Module; -using std::stringstream; -using std::vector; -using testing::ContainerEq; - -static Module::Function *generate_duplicate_function(const string &name) { - const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cLL; - const Module::Address DUP_SIZE = 0x200b26e605f99071LL; - const Module::Address DUP_PARAMETER_SIZE = 0xf14ac4fed48c4a99LL; - - Module::Function *function = new Module::Function(name, DUP_ADDRESS); - function->size = DUP_SIZE; - function->parameter_size = DUP_PARAMETER_SIZE; - return function; -} - -#define MODULE_NAME "name with spaces" -#define MODULE_OS "os-name" -#define MODULE_ARCH "architecture" -#define MODULE_ID "id-string" -#define MODULE_CODE_ID "code-id-string" - -TEST(Write, Header) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n", - contents.c_str()); -} - -TEST(Write, HeaderCodeId) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID, MODULE_CODE_ID); - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "INFO CODE_ID code-id-string\n", - contents.c_str()); -} - -TEST(Write, OneLineFunc) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - Module::File *file = m.FindFile("file_name.cc"); - Module::Function *function = new Module::Function( - "function_name", 0xe165bf8023b9d9abLL); - function->size = 0x1e4bb0eb1cbf5b09LL; - function->parameter_size = 0x772beee89114358aLL; - Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL, - file, 67519080 }; - function->lines.push_back(line); - m.AddFunction(function); - - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "FILE 0 file_name.cc\n" - "FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a" - " function_name\n" - "e165bf8023b9d9ab 1e4bb0eb1cbf5b09 67519080 0\n", - contents.c_str()); -} - -TEST(Write, RelativeLoadAddress) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // Some source files. We will expect to see them in lexicographic order. - Module::File *file1 = m.FindFile("filename-b.cc"); - Module::File *file2 = m.FindFile("filename-a.cc"); - - // A function. - Module::Function *function = new Module::Function( - "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL); - function->size = 0x2922088f98d3f6fcLL; - function->parameter_size = 0xe5e9aa008bd5f0d0LL; - - // Some source lines. The module should not sort these. - Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, - file1, 41676901 }; - Module::Line line2 = { 0xdaf35bc123885c04LL, 0xcf621b8d324d0ebLL, - file2, 67519080 }; - function->lines.push_back(line2); - function->lines.push_back(line1); - - m.AddFunction(function); - - // Some stack information. - Module::StackFrameEntry *entry = new Module::StackFrameEntry(); - entry->address = 0x30f9e5c83323973dULL; - entry->size = 0x49fc9ca7c7c13dc2ULL; - entry->initial_rules[".cfa"] = "he was a handsome man"; - entry->initial_rules["and"] = "what i want to know is"; - entry->rule_changes[0x30f9e5c83323973eULL]["how"] = - "do you like your blueeyed boy"; - entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; - m.AddStackFrameEntry(entry); - - // Set the load address. Doing this after adding all the data to - // the module must work fine. - m.SetLoadAddress(0x2ab698b0b6407073LL); - - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "FILE 0 filename-a.cc\n" - "FILE 1 filename-b.cc\n" - "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" - " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" - "b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n" - "9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n" - "STACK CFI INIT 6434d177ce326ca 49fc9ca7c7c13dc2" - " .cfa: he was a handsome man" - " and: what i want to know is\n" - "STACK CFI 6434d177ce326cb" - " Mister: Death" - " how: do you like your blueeyed boy\n", - contents.c_str()); -} - -TEST(Write, OmitUnusedFiles) { - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // Create some source files. - Module::File *file1 = m.FindFile("filename1"); - m.FindFile("filename2"); // not used by any line - Module::File *file3 = m.FindFile("filename3"); - - // Create a function. - Module::Function *function = new Module::Function( - "function_name", 0x9b926d464f0b9384LL); - function->size = 0x4f524a4ba795e6a6LL; - function->parameter_size = 0xbbe8133a6641c9b7LL; - - // Source files that refer to some files, but not others. - Module::Line line1 = { 0x595fa44ebacc1086LL, 0x1e1e0191b066c5b3LL, - file1, 137850127 }; - Module::Line line2 = { 0x401ce8c8a12d25e3LL, 0x895751c41b8d2ce2LL, - file3, 28113549 }; - function->lines.push_back(line1); - function->lines.push_back(line2); - m.AddFunction(function); - - m.AssignSourceIds(); - - vector<Module::File *> vec; - m.GetFiles(&vec); - EXPECT_EQ((size_t) 3, vec.size()); - EXPECT_STREQ("filename1", vec[0]->name.c_str()); - EXPECT_NE(-1, vec[0]->source_id); - // Expect filename2 not to be used. - EXPECT_STREQ("filename2", vec[1]->name.c_str()); - EXPECT_EQ(-1, vec[1]->source_id); - EXPECT_STREQ("filename3", vec[2]->name.c_str()); - EXPECT_NE(-1, vec[2]->source_id); - - stringstream s; - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "FILE 0 filename1\n" - "FILE 1 filename3\n" - "FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7" - " function_name\n" - "595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n" - "401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n", - contents.c_str()); -} - -TEST(Write, NoCFI) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // Some source files. We will expect to see them in lexicographic order. - Module::File *file1 = m.FindFile("filename.cc"); - - // A function. - Module::Function *function = new Module::Function( - "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)", 0xbec774ea5dd935f3LL); - function->size = 0x2922088f98d3f6fcLL; - function->parameter_size = 0xe5e9aa008bd5f0d0LL; - - // Some source lines. The module should not sort these. - Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL, - file1, 41676901 }; - function->lines.push_back(line1); - - m.AddFunction(function); - - // Some stack information. - Module::StackFrameEntry *entry = new Module::StackFrameEntry(); - entry->address = 0x30f9e5c83323973dULL; - entry->size = 0x49fc9ca7c7c13dc2ULL; - entry->initial_rules[".cfa"] = "he was a handsome man"; - entry->initial_rules["and"] = "what i want to know is"; - entry->rule_changes[0x30f9e5c83323973eULL]["how"] = - "do you like your blueeyed boy"; - entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death"; - m.AddStackFrameEntry(entry); - - // Set the load address. Doing this after adding all the data to - // the module must work fine. - m.SetLoadAddress(0x2ab698b0b6407073LL); - - m.Write(s, NO_CFI); - string contents = s.str(); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "FILE 0 filename.cc\n" - "FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0" - " A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n" - "9410dc39a798c580 1c2be6d6c5af2611 41676901 0\n", - contents.c_str()); -} - -TEST(Construct, AddFunctions) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // Two functions. - Module::Function *function1 = new Module::Function( - "_without_form", 0xd35024aa7ca7da5cLL); - function1->size = 0x200b26e605f99071LL; - function1->parameter_size = 0xf14ac4fed48c4a99LL; - - Module::Function *function2 = new Module::Function( - "_and_void", 0x2987743d0b35b13fLL); - function2->size = 0xb369db048deb3010LL; - function2->parameter_size = 0x938e556cb5a79988LL; - - // Put them in a vector. - vector<Module::Function *> vec; - vec.push_back(function1); - vec.push_back(function2); - - m.AddFunctions(vec.begin(), vec.end()); - - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988" - " _and_void\n" - "FUNC d35024aa7ca7da5c 200b26e605f99071 f14ac4fed48c4a99" - " _without_form\n", - contents.c_str()); - - // Check that m.GetFunctions returns the functions we expect. - vec.clear(); - m.GetFunctions(&vec, vec.end()); - EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function1)); - EXPECT_TRUE(vec.end() != find(vec.begin(), vec.end(), function2)); - EXPECT_EQ((size_t) 2, vec.size()); -} - -TEST(Construct, AddFrames) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // First STACK CFI entry, with no initial rules or deltas. - Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); - entry1->address = 0xddb5f41285aa7757ULL; - entry1->size = 0x1486493370dc5073ULL; - m.AddStackFrameEntry(entry1); - - // Second STACK CFI entry, with initial rules but no deltas. - Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); - entry2->address = 0x8064f3af5e067e38ULL; - entry2->size = 0x0de2a5ee55509407ULL; - entry2->initial_rules[".cfa"] = "I think that I shall never see"; - entry2->initial_rules["stromboli"] = "a poem lovely as a tree"; - entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest"; - m.AddStackFrameEntry(entry2); - - // Third STACK CFI entry, with initial rules and deltas. - Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); - entry3->address = 0x5e8d0db0a7075c6cULL; - entry3->size = 0x1c7edb12a7aea229ULL; - entry3->initial_rules[".cfa"] = "Whose woods are these"; - entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = - "the village though"; - entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = - "he will not see me stopping here"; - entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = - "his house is in"; - entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = - "I think I know"; - m.AddStackFrameEntry(entry3); - - // Check that Write writes STACK CFI records properly. - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229" - " .cfa: Whose woods are these\n" - "STACK CFI 36682fad3763ffff" - " .cfa: I think I know" - " stromboli: his house is in\n" - "STACK CFI 47ceb0f63c269d7f" - " calzone: the village though" - " cannoli: he will not see me stopping here\n" - "STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407" - " .cfa: I think that I shall never see" - " cannoli: a tree whose hungry mouth is prest" - " stromboli: a poem lovely as a tree\n" - "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n", - contents.c_str()); - - // Check that GetStackFrameEntries works. - vector<Module::StackFrameEntry *> entries; - m.GetStackFrameEntries(&entries); - ASSERT_EQ(3U, entries.size()); - // Check first entry. - EXPECT_EQ(0x5e8d0db0a7075c6cULL, entries[0]->address); - EXPECT_EQ(0x1c7edb12a7aea229ULL, entries[0]->size); - Module::RuleMap entry1_initial; - entry1_initial[".cfa"] = "Whose woods are these"; - EXPECT_THAT(entries[0]->initial_rules, ContainerEq(entry1_initial)); - Module::RuleChangeMap entry1_changes; - entry1_changes[0x36682fad3763ffffULL][".cfa"] = "I think I know"; - entry1_changes[0x36682fad3763ffffULL]["stromboli"] = "his house is in"; - entry1_changes[0x47ceb0f63c269d7fULL]["calzone"] = "the village though"; - entry1_changes[0x47ceb0f63c269d7fULL]["cannoli"] = - "he will not see me stopping here"; - EXPECT_THAT(entries[0]->rule_changes, ContainerEq(entry1_changes)); - // Check second entry. - EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address); - EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size); - ASSERT_EQ(3U, entries[1]->initial_rules.size()); - Module::RuleMap entry2_initial; - entry2_initial[".cfa"] = "I think that I shall never see"; - entry2_initial["stromboli"] = "a poem lovely as a tree"; - entry2_initial["cannoli"] = "a tree whose hungry mouth is prest"; - EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial)); - ASSERT_EQ(0U, entries[1]->rule_changes.size()); - // Check third entry. - EXPECT_EQ(0xddb5f41285aa7757ULL, entries[2]->address); - EXPECT_EQ(0x1486493370dc5073ULL, entries[2]->size); - ASSERT_EQ(0U, entries[2]->initial_rules.size()); - ASSERT_EQ(0U, entries[2]->rule_changes.size()); -} - -TEST(Construct, UniqueFiles) { - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - Module::File *file1 = m.FindFile("foo"); - Module::File *file2 = m.FindFile(string("bar")); - Module::File *file3 = m.FindFile(string("foo")); - Module::File *file4 = m.FindFile("bar"); - EXPECT_NE(file1, file2); - EXPECT_EQ(file1, file3); - EXPECT_EQ(file2, file4); - EXPECT_EQ(file1, m.FindExistingFile("foo")); - EXPECT_TRUE(m.FindExistingFile("baz") == NULL); -} - -TEST(Construct, DuplicateFunctions) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // Two functions. - Module::Function *function1 = generate_duplicate_function("_without_form"); - Module::Function *function2 = generate_duplicate_function("_without_form"); - - m.AddFunction(function1); - m.AddFunction(function2); - - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" - " _without_form\n", - contents.c_str()); -} - -TEST(Construct, FunctionsWithSameAddress) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // Two functions. - Module::Function *function1 = generate_duplicate_function("_without_form"); - Module::Function *function2 = generate_duplicate_function("_and_void"); - - m.AddFunction(function1); - m.AddFunction(function2); - - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" - "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" - " _and_void\n" - "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" - " _without_form\n", - contents.c_str()); -} - -// Externs should be written out as PUBLIC records, sorted by -// address. -TEST(Construct, Externs) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // Two externs. - Module::Extern *extern1 = new Module::Extern(0xffff); - extern1->name = "_abc"; - Module::Extern *extern2 = new Module::Extern(0xaaaa); - extern2->name = "_xyz"; - - m.AddExtern(extern1); - m.AddExtern(extern2); - - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - - EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " - MODULE_ID " " MODULE_NAME "\n" - "PUBLIC aaaa 0 _xyz\n" - "PUBLIC ffff 0 _abc\n", - contents.c_str()); -} - -// Externs with the same address should only keep the first entry -// added. -TEST(Construct, DuplicateExterns) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // Two externs. - Module::Extern *extern1 = new Module::Extern(0xffff); - extern1->name = "_xyz"; - Module::Extern *extern2 = new Module::Extern(0xffff); - extern2->name = "_abc"; - - m.AddExtern(extern1); - m.AddExtern(extern2); - - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - - EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " - MODULE_ID " " MODULE_NAME "\n" - "PUBLIC ffff 0 _xyz\n", - contents.c_str()); -} - -// If there exists an extern and a function at the same address, only write -// out the FUNC entry. -TEST(Construct, FunctionsAndExternsWithSameAddress) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // Two externs. - Module::Extern* extern1 = new Module::Extern(0xabc0); - extern1->name = "abc"; - Module::Extern* extern2 = new Module::Extern(0xfff0); - extern2->name = "xyz"; - - m.AddExtern(extern1); - m.AddExtern(extern2); - - Module::Function* function = new Module::Function("_xyz", 0xfff0); - function->size = 0x10; - function->parameter_size = 0; - m.AddFunction(function); - - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - - EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " - MODULE_ID " " MODULE_NAME "\n" - "FUNC fff0 10 0 _xyz\n" - "PUBLIC abc0 0 abc\n", - contents.c_str()); -} - -// If there exists an extern and a function at the same address, only write -// out the FUNC entry. For ARM THUMB, the extern that comes from the ELF -// symbol section has bit 0 set. -TEST(Construct, FunctionsAndThumbExternsWithSameAddress) { - stringstream s; - Module m(MODULE_NAME, MODULE_OS, "arm", MODULE_ID); - - // Two THUMB externs. - Module::Extern* thumb_extern1 = new Module::Extern(0xabc1); - thumb_extern1->name = "thumb_abc"; - Module::Extern* thumb_extern2 = new Module::Extern(0xfff1); - thumb_extern2->name = "thumb_xyz"; - - Module::Extern* arm_extern1 = new Module::Extern(0xcc00); - arm_extern1->name = "arm_func"; - - m.AddExtern(thumb_extern1); - m.AddExtern(thumb_extern2); - m.AddExtern(arm_extern1); - - // The corresponding function from the DWARF debug data have the actual - // address. - Module::Function* function = new Module::Function("_thumb_xyz", 0xfff0); - function->size = 0x10; - function->parameter_size = 0; - m.AddFunction(function); - - m.Write(s, ALL_SYMBOL_DATA); - string contents = s.str(); - - EXPECT_STREQ("MODULE " MODULE_OS " arm " - MODULE_ID " " MODULE_NAME "\n" - "FUNC fff0 10 0 _thumb_xyz\n" - "PUBLIC abc1 0 thumb_abc\n" - "PUBLIC cc00 0 arm_func\n", - contents.c_str()); -} - -TEST(Lookup, StackFrameEntries) { - Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - - // First STACK CFI entry, with no initial rules or deltas. - Module::StackFrameEntry *entry1 = new Module::StackFrameEntry(); - entry1->address = 0x2000; - entry1->size = 0x900; - m.AddStackFrameEntry(entry1); - - // Second STACK CFI entry, with initial rules but no deltas. - Module::StackFrameEntry *entry2 = new Module::StackFrameEntry(); - entry2->address = 0x3000; - entry2->size = 0x900; - entry2->initial_rules[".cfa"] = "I think that I shall never see"; - entry2->initial_rules["stromboli"] = "a poem lovely as a tree"; - entry2->initial_rules["cannoli"] = "a tree whose hungry mouth is prest"; - m.AddStackFrameEntry(entry2); - - // Third STACK CFI entry, with initial rules and deltas. - Module::StackFrameEntry *entry3 = new Module::StackFrameEntry(); - entry3->address = 0x1000; - entry3->size = 0x900; - entry3->initial_rules[".cfa"] = "Whose woods are these"; - entry3->rule_changes[0x47ceb0f63c269d7fULL]["calzone"] = - "the village though"; - entry3->rule_changes[0x47ceb0f63c269d7fULL]["cannoli"] = - "he will not see me stopping here"; - entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] = - "his house is in"; - entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] = - "I think I know"; - m.AddStackFrameEntry(entry3); - - Module::StackFrameEntry* s = m.FindStackFrameEntryByAddress(0x1000); - EXPECT_EQ(entry3, s); - s = m.FindStackFrameEntryByAddress(0x18FF); - EXPECT_EQ(entry3, s); - - s = m.FindStackFrameEntryByAddress(0x1900); - EXPECT_EQ((Module::StackFrameEntry*)NULL, s); - s = m.FindStackFrameEntryByAddress(0x1A00); - EXPECT_EQ((Module::StackFrameEntry*)NULL, s); - - s = m.FindStackFrameEntryByAddress(0x2000); - EXPECT_EQ(entry1, s); - s = m.FindStackFrameEntryByAddress(0x28FF); - EXPECT_EQ(entry1, s); - - s = m.FindStackFrameEntryByAddress(0x3000); - EXPECT_EQ(entry2, s); - s = m.FindStackFrameEntryByAddress(0x38FF); - EXPECT_EQ(entry2, s); - - s = m.FindStackFrameEntryByAddress(0x3900); - EXPECT_EQ((Module::StackFrameEntry*)NULL, s); - s = m.FindStackFrameEntryByAddress(0x3A00); - EXPECT_EQ((Module::StackFrameEntry*)NULL, s); -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/moz.build b/toolkit/crashreporter/google-breakpad/src/common/moz.build deleted file mode 100644 index 7bb6e9b6d..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/moz.build +++ /dev/null @@ -1,72 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -if CONFIG['OS_ARCH'] in ('Darwin', 'Linux'): - DIRS += ['dwarf'] - -UNIFIED_SOURCES += [ - 'convert_UTF.c', - 'string_conversion.cc', -] - -if CONFIG['OS_ARCH'] != 'WINNT': - UNIFIED_SOURCES += [ - 'md5.cc', - ] - -if CONFIG['OS_ARCH'] == 'Linux': - HOST_DEFINES['HAVE_A_OUT_H'] = True -elif CONFIG['OS_ARCH'] == 'Darwin': - HOST_DEFINES['HAVE_MACH_O_NLIST_H'] = True - HOST_SOURCES += [ - 'stabs_reader.cc', - 'stabs_to_module.cc', - ] - if CONFIG['HOST_OS_ARCH'] != 'Darwin': - HOST_CXXFLAGS += [ - '-I%s/toolkit/crashreporter/google-breakpad/src/third_party/mac_headers/' % TOPSRCDIR, - ] - -if CONFIG['OS_ARCH'] != 'WINNT': - HOST_SOURCES += [ - 'arm_ex_reader.cc', - 'arm_ex_to_module.cc', - 'convert_UTF.c', - 'dwarf_cfi_to_module.cc', - 'dwarf_cu_to_module.cc', - 'dwarf_line_to_module.cc', - 'language.cc', - 'md5.cc', - 'module.cc', - 'string_conversion.cc', - ] - if CONFIG['OS_ARCH'] == 'Darwin': - HOST_CXXFLAGS += [ - '-stdlib=libc++', - ] - HOST_CXXFLAGS += [ - '-O2', - '-g', - ] - HostLibrary('host_breakpad_common_s') - -if CONFIG['OS_TARGET'] == 'Android': - # We don't support unifying assembly files. - SOURCES += [ - 'android/breakpad_getcontext.S', - ] - LOCAL_INCLUDES += [ - '/toolkit/crashreporter/google-breakpad/src/common/android/include', - ] - -Library('breakpad_common_s') - -# We allow warnings for third-party code that can be updated from upstream. -ALLOW_COMPILER_WARNINGS = True - -FINAL_LIBRARY = 'xul' - -include('/toolkit/crashreporter/crashreporter.mozbuild') diff --git a/toolkit/crashreporter/google-breakpad/src/common/scoped_ptr.h b/toolkit/crashreporter/google-breakpad/src/common/scoped_ptr.h deleted file mode 100644 index d137c1868..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/scoped_ptr.h +++ /dev/null @@ -1,404 +0,0 @@ -// Copyright 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. - -// Scopers help you manage ownership of a pointer, helping you easily manage the -// a pointer within a scope, and automatically destroying the pointer at the -// end of a scope. There are two main classes you will use, which correspond -// to the operators new/delete and new[]/delete[]. -// -// Example usage (scoped_ptr): -// { -// scoped_ptr<Foo> foo(new Foo("wee")); -// } // foo goes out of scope, releasing the pointer with it. -// -// { -// scoped_ptr<Foo> foo; // No pointer managed. -// foo.reset(new Foo("wee")); // Now a pointer is managed. -// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed. -// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed. -// foo->Method(); // Foo::Method() called. -// foo.get()->Method(); // Foo::Method() called. -// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer -// // manages a pointer. -// foo.reset(new Foo("wee4")); // foo manages a pointer again. -// foo.reset(); // Foo("wee4") destroyed, foo no longer -// // manages a pointer. -// } // foo wasn't managing a pointer, so nothing was destroyed. -// -// Example usage (scoped_array): -// { -// scoped_array<Foo> foo(new Foo[100]); -// foo.get()->Method(); // Foo::Method on the 0th element. -// foo[10].Method(); // Foo::Method on the 10th element. -// } - -#ifndef COMMON_SCOPED_PTR_H_ -#define COMMON_SCOPED_PTR_H_ - -// This is an implementation designed to match the anticipated future TR2 -// implementation of the scoped_ptr class, and its closely-related brethren, -// scoped_array, scoped_ptr_malloc. - -#include <assert.h> -#include <stddef.h> -#include <stdlib.h> - -namespace google_breakpad { - -// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T> -// automatically deletes the pointer it holds (if any). -// That is, scoped_ptr<T> owns the T object that it points to. -// Like a T*, a scoped_ptr<T> may hold either NULL or a pointer to a T object. -// Also like T*, scoped_ptr<T> is thread-compatible, and once you -// dereference it, you get the threadsafety guarantees of T. -// -// The size of a scoped_ptr is small: -// sizeof(scoped_ptr<C>) == sizeof(C*) -template <class C> -class scoped_ptr { - public: - - // The element type - typedef C element_type; - - // Constructor. Defaults to initializing with NULL. - // There is no way to create an uninitialized scoped_ptr. - // The input parameter must be allocated with new. - explicit scoped_ptr(C* p = NULL) : ptr_(p) { } - - // Destructor. If there is a C object, delete it. - // We don't need to test ptr_ == NULL because C++ does that for us. - ~scoped_ptr() { - enum { type_must_be_complete = sizeof(C) }; - delete ptr_; - } - - // Reset. Deletes the current owned object, if any. - // Then takes ownership of a new object, if given. - // this->reset(this->get()) works. - void reset(C* p = NULL) { - if (p != ptr_) { - enum { type_must_be_complete = sizeof(C) }; - delete ptr_; - ptr_ = p; - } - } - - // Accessors to get the owned object. - // operator* and operator-> will assert() if there is no current object. - C& operator*() const { - assert(ptr_ != NULL); - return *ptr_; - } - C* operator->() const { - assert(ptr_ != NULL); - return ptr_; - } - C* get() const { return ptr_; } - - // Comparison operators. - // These return whether two scoped_ptr refer to the same object, not just to - // two different but equal objects. - bool operator==(C* p) const { return ptr_ == p; } - bool operator!=(C* p) const { return ptr_ != p; } - - // Swap two scoped pointers. - void swap(scoped_ptr& p2) { - C* tmp = ptr_; - ptr_ = p2.ptr_; - p2.ptr_ = tmp; - } - - // Release a pointer. - // The return value is the current pointer held by this object. - // If this object holds a NULL pointer, the return value is NULL. - // After this operation, this object will hold a NULL pointer, - // and will not own the object any more. - C* release() { - C* retVal = ptr_; - ptr_ = NULL; - return retVal; - } - - private: - C* ptr_; - - // Forbid comparison of scoped_ptr types. If C2 != C, it totally doesn't - // make sense, and if C2 == C, it still doesn't make sense because you should - // never have the same object owned by two different scoped_ptrs. - template <class C2> bool operator==(scoped_ptr<C2> const& p2) const; - template <class C2> bool operator!=(scoped_ptr<C2> const& p2) const; - - // Disallow evil constructors - scoped_ptr(const scoped_ptr&); - void operator=(const scoped_ptr&); -}; - -// Free functions -template <class C> -void swap(scoped_ptr<C>& p1, scoped_ptr<C>& p2) { - p1.swap(p2); -} - -template <class C> -bool operator==(C* p1, const scoped_ptr<C>& p2) { - return p1 == p2.get(); -} - -template <class C> -bool operator!=(C* p1, const scoped_ptr<C>& p2) { - return p1 != p2.get(); -} - -// scoped_array<C> is like scoped_ptr<C>, except that the caller must allocate -// with new [] and the destructor deletes objects with delete []. -// -// As with scoped_ptr<C>, a scoped_array<C> either points to an object -// or is NULL. A scoped_array<C> owns the object that it points to. -// scoped_array<T> is thread-compatible, and once you index into it, -// the returned objects have only the threadsafety guarantees of T. -// -// Size: sizeof(scoped_array<C>) == sizeof(C*) -template <class C> -class scoped_array { - public: - - // The element type - typedef C element_type; - - // Constructor. Defaults to intializing with NULL. - // There is no way to create an uninitialized scoped_array. - // The input parameter must be allocated with new []. - explicit scoped_array(C* p = NULL) : array_(p) { } - - // Destructor. If there is a C object, delete it. - // We don't need to test ptr_ == NULL because C++ does that for us. - ~scoped_array() { - enum { type_must_be_complete = sizeof(C) }; - delete[] array_; - } - - // Reset. Deletes the current owned object, if any. - // Then takes ownership of a new object, if given. - // this->reset(this->get()) works. - void reset(C* p = NULL) { - if (p != array_) { - enum { type_must_be_complete = sizeof(C) }; - delete[] array_; - array_ = p; - } - } - - // Get one element of the current object. - // Will assert() if there is no current object, or index i is negative. - C& operator[](ptrdiff_t i) const { - assert(i >= 0); - assert(array_ != NULL); - return array_[i]; - } - - // Get a pointer to the zeroth element of the current object. - // If there is no current object, return NULL. - C* get() const { - return array_; - } - - // Comparison operators. - // These return whether two scoped_array refer to the same object, not just to - // two different but equal objects. - bool operator==(C* p) const { return array_ == p; } - bool operator!=(C* p) const { return array_ != p; } - - // Swap two scoped arrays. - void swap(scoped_array& p2) { - C* tmp = array_; - array_ = p2.array_; - p2.array_ = tmp; - } - - // Release an array. - // The return value is the current pointer held by this object. - // If this object holds a NULL pointer, the return value is NULL. - // After this operation, this object will hold a NULL pointer, - // and will not own the object any more. - C* release() { - C* retVal = array_; - array_ = NULL; - return retVal; - } - - private: - C* array_; - - // Forbid comparison of different scoped_array types. - template <class C2> bool operator==(scoped_array<C2> const& p2) const; - template <class C2> bool operator!=(scoped_array<C2> const& p2) const; - - // Disallow evil constructors - scoped_array(const scoped_array&); - void operator=(const scoped_array&); -}; - -// Free functions -template <class C> -void swap(scoped_array<C>& p1, scoped_array<C>& p2) { - p1.swap(p2); -} - -template <class C> -bool operator==(C* p1, const scoped_array<C>& p2) { - return p1 == p2.get(); -} - -template <class C> -bool operator!=(C* p1, const scoped_array<C>& p2) { - return p1 != p2.get(); -} - -// This class wraps the c library function free() in a class that can be -// passed as a template argument to scoped_ptr_malloc below. -class ScopedPtrMallocFree { - public: - inline void operator()(void* x) const { - free(x); - } -}; - -// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a -// second template argument, the functor used to free the object. - -template<class C, class FreeProc = ScopedPtrMallocFree> -class scoped_ptr_malloc { - public: - - // The element type - typedef C element_type; - - // Constructor. Defaults to initializing with NULL. - // There is no way to create an uninitialized scoped_ptr. - // The input parameter must be allocated with an allocator that matches the - // Free functor. For the default Free functor, this is malloc, calloc, or - // realloc. - explicit scoped_ptr_malloc(C* p = NULL): ptr_(p) {} - - // Destructor. If there is a C object, call the Free functor. - ~scoped_ptr_malloc() { - reset(); - } - - // Reset. Calls the Free functor on the current owned object, if any. - // Then takes ownership of a new object, if given. - // this->reset(this->get()) works. - void reset(C* p = NULL) { - if (ptr_ != p) { - FreeProc free_proc; - free_proc(ptr_); - ptr_ = p; - } - } - - // Get the current object. - // operator* and operator-> will cause an assert() failure if there is - // no current object. - C& operator*() const { - assert(ptr_ != NULL); - return *ptr_; - } - - C* operator->() const { - assert(ptr_ != NULL); - return ptr_; - } - - C* get() const { - return ptr_; - } - - // Comparison operators. - // These return whether a scoped_ptr_malloc and a plain pointer refer - // to the same object, not just to two different but equal objects. - // For compatibility with the boost-derived implementation, these - // take non-const arguments. - bool operator==(C* p) const { - return ptr_ == p; - } - - bool operator!=(C* p) const { - return ptr_ != p; - } - - // Swap two scoped pointers. - void swap(scoped_ptr_malloc & b) { - C* tmp = b.ptr_; - b.ptr_ = ptr_; - ptr_ = tmp; - } - - // Release a pointer. - // The return value is the current pointer held by this object. - // If this object holds a NULL pointer, the return value is NULL. - // After this operation, this object will hold a NULL pointer, - // and will not own the object any more. - C* release() { - C* tmp = ptr_; - ptr_ = NULL; - return tmp; - } - - private: - C* ptr_; - - // no reason to use these: each scoped_ptr_malloc should have its own object - template <class C2, class GP> - bool operator==(scoped_ptr_malloc<C2, GP> const& p) const; - template <class C2, class GP> - bool operator!=(scoped_ptr_malloc<C2, GP> const& p) const; - - // Disallow evil constructors - scoped_ptr_malloc(const scoped_ptr_malloc&); - void operator=(const scoped_ptr_malloc&); -}; - -template<class C, class FP> inline -void swap(scoped_ptr_malloc<C, FP>& a, scoped_ptr_malloc<C, FP>& b) { - a.swap(b); -} - -template<class C, class FP> inline -bool operator==(C* p, const scoped_ptr_malloc<C, FP>& b) { - return p == b.get(); -} - -template<class C, class FP> inline -bool operator!=(C* p, const scoped_ptr_malloc<C, FP>& b) { - return p != b.get(); -} - -} // namespace google_breakpad - -#endif // COMMON_SCOPED_PTR_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.cc b/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.cc deleted file mode 100644 index e0a74ceeb..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.cc +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2007, 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/simple_string_dictionary.h" - -namespace google_breakpad { - -namespace { - -// In C++98 (ISO 14882), section 9.5.1 says that a union cannot have a member -// with a non-trivial ctor, copy ctor, dtor, or assignment operator. Use this -// property to ensure that Entry remains POD. -union Compile_Assert { - NonAllocatingMap<1, 1, 1>::Entry Compile_Assert__entry_must_be_pod; -}; - -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.h b/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.h deleted file mode 100644 index d2ab17fda..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary.h +++ /dev/null @@ -1,260 +0,0 @@ -// Copyright (c) 2007, 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_SIMPLE_STRING_DICTIONARY_H_ -#define COMMON_SIMPLE_STRING_DICTIONARY_H_ - -#include <assert.h> -#include <string.h> - -#include "common/basictypes.h" - -namespace google_breakpad { - -// Opaque type for the serialized representation of a NonAllocatingMap. One is -// created in NonAllocatingMap::Serialize and can be deserialized using one of -// the constructors. -struct SerializedNonAllocatingMap; - -// NonAllocatingMap is an implementation of a map/dictionary collection that -// uses a fixed amount of storage, so that it does not perform any dynamic -// allocations for its operations. -// -// The actual map storage (the Entry) is guaranteed to be POD, so that it can -// be transmitted over various IPC mechanisms. -// -// The template parameters control the amount of storage used for the key, -// value, and map. The KeySize and ValueSize are measured in bytes, not glyphs, -// and includes space for a \0 byte. This gives space for KeySize-1 and -// ValueSize-1 characters in an entry. NumEntries is the total number of -// entries that will fit in the map. -template <size_t KeySize, size_t ValueSize, size_t NumEntries> -class NonAllocatingMap { - public: - // Constant and publicly accessible versions of the template parameters. - static const size_t key_size = KeySize; - static const size_t value_size = ValueSize; - static const size_t num_entries = NumEntries; - - // An Entry object is a single entry in the map. If the key is a 0-length - // NUL-terminated string, the entry is empty. - struct Entry { - char key[KeySize]; - char value[ValueSize]; - - bool is_active() const { - return key[0] != '\0'; - } - }; - - // An Iterator can be used to iterate over all the active entries in a - // NonAllocatingMap. - class Iterator { - public: - explicit Iterator(const NonAllocatingMap& map) - : map_(map), - current_(0) { - } - - // Returns the next entry in the map, or NULL if at the end of the - // collection. - const Entry* Next() { - while (current_ < map_.num_entries) { - const Entry* entry = &map_.entries_[current_++]; - if (entry->is_active()) { - return entry; - } - } - return NULL; - } - - private: - const NonAllocatingMap& map_; - size_t current_; - - DISALLOW_COPY_AND_ASSIGN(Iterator); - }; - - NonAllocatingMap() : entries_() { - } - - NonAllocatingMap(const NonAllocatingMap& other) { - *this = other; - } - - NonAllocatingMap& operator=(const NonAllocatingMap& other) { - assert(other.key_size == key_size); - assert(other.value_size == value_size); - assert(other.num_entries == num_entries); - if (other.key_size == key_size && other.value_size == value_size && - other.num_entries == num_entries) { - memcpy(entries_, other.entries_, sizeof(entries_)); - } - return *this; - } - - // Constructs a map from its serialized form. |map| should be the out - // parameter from Serialize() and |size| should be its return value. - NonAllocatingMap(const SerializedNonAllocatingMap* map, size_t size) { - assert(size == sizeof(entries_)); - if (size == sizeof(entries_)) { - memcpy(entries_, map, size); - } - } - - // Returns the number of active key/value pairs. The upper limit for this - // is NumEntries. - size_t GetCount() const { - size_t count = 0; - for (size_t i = 0; i < num_entries; ++i) { - if (entries_[i].is_active()) { - ++count; - } - } - return count; - } - - // Given |key|, returns its corresponding |value|. |key| must not be NULL. If - // the key is not found, NULL is returned. - const char* GetValueForKey(const char* key) const { - assert(key); - if (!key) - return NULL; - - const Entry* entry = GetConstEntryForKey(key); - if (!entry) - return NULL; - - return entry->value; - } - - // Stores |value| into |key|, replacing the existing value if |key| is - // already present. |key| must not be NULL. If |value| is NULL, the key is - // removed from the map. If there is no more space in the map, then the - // operation silently fails. - void SetKeyValue(const char* key, const char* value) { - if (!value) { - RemoveKey(key); - return; - } - - assert(key); - if (!key) - return; - - // Key must not be an empty string. - assert(key[0] != '\0'); - if (key[0] == '\0') - return; - - Entry* entry = GetEntryForKey(key); - - // If it does not yet exist, attempt to insert it. - if (!entry) { - for (size_t i = 0; i < num_entries; ++i) { - if (!entries_[i].is_active()) { - entry = &entries_[i]; - - strncpy(entry->key, key, key_size); - entry->key[key_size - 1] = '\0'; - - break; - } - } - } - - // If the map is out of space, entry will be NULL. - if (!entry) - return; - -#ifndef NDEBUG - // Sanity check that the key only appears once. - int count = 0; - for (size_t i = 0; i < num_entries; ++i) { - if (strncmp(entries_[i].key, key, key_size) == 0) - ++count; - } - assert(count == 1); -#endif - - strncpy(entry->value, value, value_size); - entry->value[value_size - 1] = '\0'; - } - - // Given |key|, removes any associated value. |key| must not be NULL. If - // the key is not found, this is a noop. - void RemoveKey(const char* key) { - assert(key); - if (!key) - return; - - Entry* entry = GetEntryForKey(key); - if (entry) { - entry->key[0] = '\0'; - entry->value[0] = '\0'; - } - -#ifndef NDEBUG - assert(GetEntryForKey(key) == NULL); -#endif - } - - // Places a serialized version of the map into |map| and returns the size. - // Both of these should be passed to the deserializing constructor. Note that - // the serialized |map| is scoped to the lifetime of the non-serialized - // instance of this class. The |map| can be copied across IPC boundaries. - size_t Serialize(const SerializedNonAllocatingMap** map) const { - *map = reinterpret_cast<const SerializedNonAllocatingMap*>(entries_); - return sizeof(entries_); - } - - private: - const Entry* GetConstEntryForKey(const char* key) const { - for (size_t i = 0; i < num_entries; ++i) { - if (strncmp(key, entries_[i].key, key_size) == 0) { - return &entries_[i]; - } - } - return NULL; - } - - Entry* GetEntryForKey(const char* key) { - return const_cast<Entry*>(GetConstEntryForKey(key)); - } - - Entry entries_[NumEntries]; -}; - -// For historical reasons this specialized version is available with the same -// size factors as a previous implementation. -typedef NonAllocatingMap<256, 256, 64> SimpleStringDictionary; - -} // namespace google_breakpad - -#endif // COMMON_SIMPLE_STRING_DICTIONARY_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary_unittest.cc deleted file mode 100644 index 34f4b9ef5..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/simple_string_dictionary_unittest.cc +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright (c) 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "breakpad_googletest_includes.h" -#include "common/simple_string_dictionary.h" - -namespace google_breakpad { - -TEST(NonAllocatingMapTest, Entry) { - typedef NonAllocatingMap<5, 9, 15> TestMap; - TestMap map; - - const TestMap::Entry* entry = TestMap::Iterator(map).Next(); - EXPECT_FALSE(entry); - - // Try setting a key/value and then verify. - map.SetKeyValue("key1", "value1"); - entry = TestMap::Iterator(map).Next(); - ASSERT_TRUE(entry); - EXPECT_STREQ(entry->key, "key1"); - EXPECT_STREQ(entry->value, "value1"); - - // Try setting a new value. - map.SetKeyValue("key1", "value3"); - EXPECT_STREQ(entry->value, "value3"); - - // Make sure the key didn't change. - EXPECT_STREQ(entry->key, "key1"); - - // Clear the entry and verify the key and value are empty strings. - map.RemoveKey("key1"); - EXPECT_FALSE(entry->is_active()); - EXPECT_EQ(strlen(entry->key), 0u); - EXPECT_EQ(strlen(entry->value), 0u); -} - -TEST(NonAllocatingMapTest, SimpleStringDictionary) { - // Make a new dictionary - SimpleStringDictionary dict; - - // Set three distinct values on three keys - dict.SetKeyValue("key1", "value1"); - dict.SetKeyValue("key2", "value2"); - dict.SetKeyValue("key3", "value3"); - - EXPECT_NE(dict.GetValueForKey("key1"), "value1"); - EXPECT_NE(dict.GetValueForKey("key2"), "value2"); - EXPECT_NE(dict.GetValueForKey("key3"), "value3"); - EXPECT_EQ(dict.GetCount(), 3u); - // try an unknown key - EXPECT_FALSE(dict.GetValueForKey("key4")); - - // Remove a key - dict.RemoveKey("key3"); - - // Now make sure it's not there anymore - EXPECT_FALSE(dict.GetValueForKey("key3")); - - // Remove by setting value to NULL - dict.SetKeyValue("key2", NULL); - - // Now make sure it's not there anymore - EXPECT_FALSE(dict.GetValueForKey("key2")); -} - -TEST(NonAllocatingMapTest, CopyAndAssign) { - NonAllocatingMap<10, 10, 10> map; - map.SetKeyValue("one", "a"); - map.SetKeyValue("two", "b"); - map.SetKeyValue("three", "c"); - map.RemoveKey("two"); - EXPECT_EQ(2u, map.GetCount()); - - // Test copy. - NonAllocatingMap<10, 10, 10> map_copy(map); - EXPECT_EQ(2u, map_copy.GetCount()); - EXPECT_STREQ("a", map_copy.GetValueForKey("one")); - EXPECT_STREQ("c", map_copy.GetValueForKey("three")); - map_copy.SetKeyValue("four", "d"); - EXPECT_STREQ("d", map_copy.GetValueForKey("four")); - EXPECT_FALSE(map.GetValueForKey("four")); - - // Test assign. - NonAllocatingMap<10, 10, 10> map_assign; - map_assign = map; - EXPECT_EQ(2u, map_assign.GetCount()); - EXPECT_STREQ("a", map_assign.GetValueForKey("one")); - EXPECT_STREQ("c", map_assign.GetValueForKey("three")); - map_assign.SetKeyValue("four", "d"); - EXPECT_STREQ("d", map_assign.GetValueForKey("four")); - EXPECT_FALSE(map.GetValueForKey("four")); - - map.RemoveKey("one"); - EXPECT_FALSE(map.GetValueForKey("one")); - EXPECT_STREQ("a", map_copy.GetValueForKey("one")); - EXPECT_STREQ("a", map_assign.GetValueForKey("one")); -} - -// Add a bunch of values to the dictionary, remove some entries in the middle, -// and then add more. -TEST(NonAllocatingMapTest, Iterator) { - SimpleStringDictionary* dict = new SimpleStringDictionary(); - ASSERT_TRUE(dict); - - char key[SimpleStringDictionary::key_size]; - char value[SimpleStringDictionary::value_size]; - - const int kDictionaryCapacity = SimpleStringDictionary::num_entries; - const int kPartitionIndex = kDictionaryCapacity - 5; - - // We assume at least this size in the tests below - ASSERT_GE(kDictionaryCapacity, 64); - - // We'll keep track of the number of key/value pairs we think should - // be in the dictionary - int expectedDictionarySize = 0; - - // Set a bunch of key/value pairs like key0/value0, key1/value1, ... - for (int i = 0; i < kPartitionIndex; ++i) { - sprintf(key, "key%d", i); - sprintf(value, "value%d", i); - dict->SetKeyValue(key, value); - } - expectedDictionarySize = kPartitionIndex; - - // set a couple of the keys twice (with the same value) - should be nop - dict->SetKeyValue("key2", "value2"); - dict->SetKeyValue("key4", "value4"); - dict->SetKeyValue("key15", "value15"); - - // Remove some random elements in the middle - dict->RemoveKey("key7"); - dict->RemoveKey("key18"); - dict->RemoveKey("key23"); - dict->RemoveKey("key31"); - expectedDictionarySize -= 4; // we just removed four key/value pairs - - // Set some more key/value pairs like key59/value59, key60/value60, ... - for (int i = kPartitionIndex; i < kDictionaryCapacity; ++i) { - sprintf(key, "key%d", i); - sprintf(value, "value%d", i); - dict->SetKeyValue(key, value); - } - expectedDictionarySize += kDictionaryCapacity - kPartitionIndex; - - // Now create an iterator on the dictionary - SimpleStringDictionary::Iterator iter(*dict); - - // We then verify that it iterates through exactly the number of - // key/value pairs we expect, and that they match one-for-one with what we - // would expect. The ordering of the iteration does not matter... - - // used to keep track of number of occurrences found for key/value pairs - int count[kDictionaryCapacity]; - memset(count, 0, sizeof(count)); - - int totalCount = 0; - - const SimpleStringDictionary::Entry* entry; - while ((entry = iter.Next())) { - totalCount++; - - // Extract keyNumber from a string of the form key<keyNumber> - int keyNumber; - sscanf(entry->key, "key%d", &keyNumber); - - // Extract valueNumber from a string of the form value<valueNumber> - int valueNumber; - sscanf(entry->value, "value%d", &valueNumber); - - // The value number should equal the key number since that's how we set them - EXPECT_EQ(keyNumber, valueNumber); - - // Key and value numbers should be in proper range: - // 0 <= keyNumber < kDictionaryCapacity - bool isKeyInGoodRange = - (keyNumber >= 0 && keyNumber < kDictionaryCapacity); - bool isValueInGoodRange = - (valueNumber >= 0 && valueNumber < kDictionaryCapacity); - EXPECT_TRUE(isKeyInGoodRange); - EXPECT_TRUE(isValueInGoodRange); - - if (isKeyInGoodRange && isValueInGoodRange) { - ++count[keyNumber]; - } - } - - // Make sure each of the key/value pairs showed up exactly one time, except - // for the ones which we removed. - for (size_t i = 0; i < kDictionaryCapacity; ++i) { - // Skip over key7, key18, key23, and key31, since we removed them - if (!(i == 7 || i == 18 || i == 23 || i == 31)) { - EXPECT_EQ(count[i], 1); - } - } - - // Make sure the number of iterations matches the expected dictionary size. - EXPECT_EQ(totalCount, expectedDictionarySize); -} - - -TEST(NonAllocatingMapTest, AddRemove) { - NonAllocatingMap<5, 7, 6> map; - map.SetKeyValue("rob", "ert"); - map.SetKeyValue("mike", "pink"); - map.SetKeyValue("mark", "allays"); - - EXPECT_EQ(3u, map.GetCount()); - EXPECT_STREQ("ert", map.GetValueForKey("rob")); - EXPECT_STREQ("pink", map.GetValueForKey("mike")); - EXPECT_STREQ("allays", map.GetValueForKey("mark")); - - map.RemoveKey("mike"); - - EXPECT_EQ(2u, map.GetCount()); - EXPECT_FALSE(map.GetValueForKey("mike")); - - map.SetKeyValue("mark", "mal"); - EXPECT_EQ(2u, map.GetCount()); - EXPECT_STREQ("mal", map.GetValueForKey("mark")); - - map.RemoveKey("mark"); - EXPECT_EQ(1u, map.GetCount()); - EXPECT_FALSE(map.GetValueForKey("mark")); -} - -TEST(NonAllocatingMapTest, Serialize) { - typedef NonAllocatingMap<4, 5, 7> TestMap; - TestMap map; - map.SetKeyValue("one", "abc"); - map.SetKeyValue("two", "def"); - map.SetKeyValue("tre", "hig"); - - EXPECT_STREQ("abc", map.GetValueForKey("one")); - EXPECT_STREQ("def", map.GetValueForKey("two")); - EXPECT_STREQ("hig", map.GetValueForKey("tre")); - - const SerializedNonAllocatingMap* serialized; - size_t size = map.Serialize(&serialized); - - SerializedNonAllocatingMap* serialized_copy = - reinterpret_cast<SerializedNonAllocatingMap*>(malloc(size)); - ASSERT_TRUE(serialized_copy); - memcpy(serialized_copy, serialized, size); - - TestMap deserialized(serialized_copy, size); - free(serialized_copy); - - EXPECT_EQ(3u, deserialized.GetCount()); - EXPECT_STREQ("abc", deserialized.GetValueForKey("one")); - EXPECT_STREQ("def", deserialized.GetValueForKey("two")); - EXPECT_STREQ("hig", deserialized.GetValueForKey("tre")); -} - -// Running out of space shouldn't crash. -TEST(NonAllocatingMapTest, OutOfSpace) { - NonAllocatingMap<3, 2, 2> map; - map.SetKeyValue("a", "1"); - map.SetKeyValue("b", "2"); - map.SetKeyValue("c", "3"); - EXPECT_EQ(2u, map.GetCount()); - EXPECT_FALSE(map.GetValueForKey("c")); -} - -#ifndef NDEBUG - -TEST(NonAllocatingMapTest, NullKey) { - NonAllocatingMap<4, 6, 6> map; - ASSERT_DEATH(map.SetKeyValue(NULL, "hello"), ""); - - map.SetKeyValue("hi", "there"); - ASSERT_DEATH(map.GetValueForKey(NULL), ""); - EXPECT_STREQ("there", map.GetValueForKey("hi")); - - ASSERT_DEATH(map.GetValueForKey(NULL), ""); - map.RemoveKey("hi"); - EXPECT_EQ(0u, map.GetCount()); -} - -#endif // !NDEBUG - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc b/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc deleted file mode 100644 index 168d0b287..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc +++ /dev/null @@ -1,681 +0,0 @@ -// 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. - -// Author: Alfred Peng - -#include <demangle.h> -#include <fcntl.h> -#include <gelf.h> -#include <link.h> -#include <sys/mman.h> -#include <stab.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include <functional> -#include <map> -#include <vector> - -#include "common/scoped_ptr.h" -#include "common/solaris/dump_symbols.h" -#include "common/solaris/file_id.h" -#include "common/solaris/guid_creator.h" - -// This namespace contains helper functions. -namespace { - -using std::make_pair; - -#if defined(_LP64) -typedef Elf64_Sym Elf_Sym; -#else -typedef Elf32_Sym Elf_Sym; -#endif - -// Symbol table entry from stabs. Sun CC specific. -struct slist { - // String table index. - unsigned int n_strx; - // Stab type. - unsigned char n_type; - char n_other; - short n_desc; - unsigned long n_value; -}; - -// Symbol table entry -struct SymbolEntry { - // Offset from the start of the file. - GElf_Addr offset; - // Function size. - GElf_Word size; -}; - -// Infomation of a line. -struct LineInfo { - // Offset from start of the function. - // Load from stab symbol. - GElf_Off rva_to_func; - // Offset from base of the loading binary. - GElf_Off rva_to_base; - // Size of the line. - // The first line: equals to rva_to_func. - // The other lines: the difference of rva_to_func of the line and - // rva_to_func of the previous N_SLINE. - uint32_t size; - // Line number. - uint32_t line_num; -}; - -// Information of a function. -struct FuncInfo { - // Name of the function. - const char *name; - // Offset from the base of the loading address. - GElf_Off rva_to_base; - // Virtual address of the function. - // Load from stab symbol. - GElf_Addr addr; - // Size of the function. - // Equal to rva_to_func of the last function line. - uint32_t size; - // Total size of stack parameters. - uint32_t stack_param_size; - // Line information array. - std::vector<struct LineInfo> line_info; -}; - -// Information of a source file. -struct SourceFileInfo { - // Name of the source file. - const char *name; - // Starting address of the source file. - GElf_Addr addr; - // Id of the source file. - int source_id; - // Functions information. - std::vector<struct FuncInfo> func_info; -}; - -struct CompareString { - bool operator()(const char *s1, const char *s2) const { - return strcmp(s1, s2) < 0; - } -}; - -typedef std::map<const char *, struct SymbolEntry *, CompareString> SymbolMap; - -// Information of a symbol table. -// This is the root of all types of symbol. -struct SymbolInfo { - std::vector<struct SourceFileInfo> source_file_info; - // Symbols information. - SymbolMap symbol_entries; -}; - -// Stab section name. -const char *kStabName = ".stab"; - -// Stab str section name. -const char *kStabStrName = ".stabstr"; - -// Symtab section name. -const char *kSymtabName = ".symtab"; - -// Strtab section name. -const char *kStrtabName = ".strtab"; - -// Default buffer lenght for demangle. -const int demangleLen = 20000; - -// Offset to the string table. -uint64_t stringOffset = 0; - -// Update the offset to the start of the string index of the next -// object module for every N_ENDM stabs. -inline void RecalculateOffset(struct slist* cur_list, char *stabstr) { - while ((--cur_list)->n_strx == 0) ; - stringOffset += cur_list->n_strx; - - char *temp = stabstr + stringOffset; - while (*temp != '\0') { - ++stringOffset; - ++temp; - } - // Skip the extra '\0' - ++stringOffset; -} - -// Demangle using demangle library on Solaris. -std::string Demangle(const char *mangled) { - int status = 0; - std::string str(mangled); - char *demangled = (char *)malloc(demangleLen); - - if (!demangled) { - fprintf(stderr, "no enough memory.\n"); - goto out; - } - - if ((status = cplus_demangle(mangled, demangled, demangleLen)) == - DEMANGLE_ESPACE) { - fprintf(stderr, "incorrect demangle.\n"); - goto out; - } - - str = demangled; - free(demangled); - -out: - return str; -} - -bool WriteFormat(int fd, const char *fmt, ...) { - va_list list; - char buffer[4096]; - ssize_t expected, written; - va_start(list, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, list); - expected = strlen(buffer); - written = write(fd, buffer, strlen(buffer)); - va_end(list); - return expected == written; -} - -bool IsValidElf(const GElf_Ehdr *elf_header) { - return memcmp(elf_header, ELFMAG, SELFMAG) == 0; -} - -static bool FindSectionByName(Elf *elf, const char *name, - int shstrndx, - GElf_Shdr *shdr) { - assert(name != NULL); - - if (strlen(name) == 0) - return false; - - Elf_Scn *scn = NULL; - - while ((scn = elf_nextscn(elf, scn)) != NULL) { - if (gelf_getshdr(scn, shdr) == (GElf_Shdr *)0) { - fprintf(stderr, "failed to read section header: %s\n", elf_errmsg(0)); - return false; - } - - const char *section_name = elf_strptr(elf, shstrndx, shdr->sh_name); - if (!section_name) { - fprintf(stderr, "Section name error: %s\n", elf_errmsg(-1)); - continue; - } - - if (strcmp(section_name, name) == 0) - return true; - } - - return false; -} - -// The parameter size is used for FPO-optimized code, and -// this is all tied up with the debugging data for Windows x86. -// Set it to 0 on Solaris. -int LoadStackParamSize(struct slist *list, - struct slist *list_end, - struct FuncInfo *func_info) { - struct slist *cur_list = list; - int step = 1; - while (cur_list < list_end && cur_list->n_type == N_PSYM) { - ++cur_list; - ++step; - } - - func_info->stack_param_size = 0; - return step; -} - -int LoadLineInfo(struct slist *list, - struct slist *list_end, - struct FuncInfo *func_info) { - struct slist *cur_list = list; - do { - // Skip non line information. - while (cur_list < list_end && cur_list->n_type != N_SLINE) { - // Only exit when got another function, or source file, or end stab. - if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO || - cur_list->n_type == N_ENDM) { - return cur_list - list; - } - ++cur_list; - } - struct LineInfo line; - while (cur_list < list_end && cur_list->n_type == N_SLINE) { - line.rva_to_func = cur_list->n_value; - // n_desc is a signed short - line.line_num = (unsigned short)cur_list->n_desc; - func_info->line_info.push_back(line); - ++cur_list; - } - if (cur_list == list_end && cur_list->n_type == N_ENDM) - break; - } while (list < list_end); - - return cur_list - list; -} - -int LoadFuncSymbols(struct slist *list, - struct slist *list_end, - char *stabstr, - GElf_Word base, - struct SourceFileInfo *source_file_info) { - struct slist *cur_list = list; - assert(cur_list->n_type == N_SO); - ++cur_list; - - source_file_info->func_info.clear(); - while (cur_list < list_end) { - // Go until the function symbol. - while (cur_list < list_end && cur_list->n_type != N_FUN) { - if (cur_list->n_type == N_SO) { - return cur_list - list; - } - ++cur_list; - if (cur_list->n_type == N_ENDM) - RecalculateOffset(cur_list, stabstr); - continue; - } - while (cur_list->n_type == N_FUN) { - struct FuncInfo func_info; - memset(&func_info, 0, sizeof(func_info)); - func_info.name = stabstr + cur_list->n_strx + stringOffset; - // The n_value field is always 0 from stab generated by Sun CC. - // TODO(Alfred): Find the correct value. - func_info.addr = cur_list->n_value; - ++cur_list; - if (cur_list->n_type == N_ENDM) - RecalculateOffset(cur_list, stabstr); - if (cur_list->n_type != N_ESYM && cur_list->n_type != N_ISYM && - cur_list->n_type != N_FUN) { - // Stack parameter size. - cur_list += LoadStackParamSize(cur_list, list_end, &func_info); - // Line info. - cur_list += LoadLineInfo(cur_list, list_end, &func_info); - } - if (cur_list < list_end && cur_list->n_type == N_ENDM) - RecalculateOffset(cur_list, stabstr); - // Functions in this module should have address bigger than the module - // starting address. - // - // These two values are always 0 with Sun CC. - // TODO(Alfred): Get the correct value or remove the condition statement. - if (func_info.addr >= source_file_info->addr) { - source_file_info->func_info.push_back(func_info); - } - } - } - return cur_list - list; -} - -// Compute size and rva information based on symbols loaded from stab section. -bool ComputeSizeAndRVA(struct SymbolInfo *symbols) { - std::vector<struct SourceFileInfo> *sorted_files = - &(symbols->source_file_info); - SymbolMap *symbol_entries = &(symbols->symbol_entries); - for (size_t i = 0; i < sorted_files->size(); ++i) { - struct SourceFileInfo &source_file = (*sorted_files)[i]; - std::vector<struct FuncInfo> *sorted_functions = &(source_file.func_info); - int func_size = sorted_functions->size(); - - for (size_t j = 0; j < func_size; ++j) { - struct FuncInfo &func_info = (*sorted_functions)[j]; - int line_count = func_info.line_info.size(); - - // Discard the ending part of the name. - std::string func_name(func_info.name); - std::string::size_type last_colon = func_name.find_first_of(':'); - if (last_colon != std::string::npos) - func_name = func_name.substr(0, last_colon); - - // Fine the symbol offset from the loading address and size by name. - SymbolMap::const_iterator it = symbol_entries->find(func_name.c_str()); - if (it->second) { - func_info.rva_to_base = it->second->offset; - func_info.size = (line_count == 0) ? 0 : it->second->size; - } else { - func_info.rva_to_base = 0; - func_info.size = 0; - } - - // Compute function and line size. - for (size_t k = 0; k < line_count; ++k) { - struct LineInfo &line_info = func_info.line_info[k]; - - line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base; - if (k == line_count - 1) { - line_info.size = func_info.size - line_info.rva_to_func; - } else { - struct LineInfo &next_line = func_info.line_info[k + 1]; - line_info.size = next_line.rva_to_func - line_info.rva_to_func; - } - } // for each line. - } // for each function. - } // for each source file. - for (SymbolMap::iterator it = symbol_entries->begin(); - it != symbol_entries->end(); ++it) { - free(it->second); - } - return true; -} - -bool LoadAllSymbols(const GElf_Shdr *stab_section, - const GElf_Shdr *stabstr_section, - GElf_Word base, - struct SymbolInfo *symbols) { - if (stab_section == NULL || stabstr_section == NULL) - return false; - - char *stabstr = - reinterpret_cast<char *>(stabstr_section->sh_offset + base); - struct slist *lists = - reinterpret_cast<struct slist *>(stab_section->sh_offset + base); - int nstab = stab_section->sh_size / sizeof(struct slist); - int source_id = 0; - - // First pass, load all symbols from the object file. - for (int i = 0; i < nstab; ) { - int step = 1; - struct slist *cur_list = lists + i; - if (cur_list->n_type == N_SO) { - // FUNC <address> <size> <param_stack_size> <function> - struct SourceFileInfo source_file_info; - source_file_info.name = stabstr + cur_list->n_strx + stringOffset; - // The n_value field is always 0 from stab generated by Sun CC. - // TODO(Alfred): Find the correct value. - source_file_info.addr = cur_list->n_value; - if (strchr(source_file_info.name, '.')) - source_file_info.source_id = source_id++; - else - source_file_info.source_id = -1; - step = LoadFuncSymbols(cur_list, lists + nstab - 1, stabstr, - base, &source_file_info); - symbols->source_file_info.push_back(source_file_info); - } - i += step; - } - // Second pass, compute the size of functions and lines. - return ComputeSizeAndRVA(symbols); -} - -bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols, - void *obj_base) { - GElf_Word base = reinterpret_cast<GElf_Word>(obj_base); - - const GElf_Shdr *sections = - reinterpret_cast<GElf_Shdr *>(elf_header->e_shoff + base); - GElf_Shdr stab_section; - if (!FindSectionByName(elf, kStabName, elf_header->e_shstrndx, - &stab_section)) { - fprintf(stderr, "Stab section not found.\n"); - return false; - } - GElf_Shdr stabstr_section; - if (!FindSectionByName(elf, kStabStrName, elf_header->e_shstrndx, - &stabstr_section)) { - fprintf(stderr, "Stabstr section not found.\n"); - return false; - } - GElf_Shdr symtab_section; - if (!FindSectionByName(elf, kSymtabName, elf_header->e_shstrndx, - &symtab_section)) { - fprintf(stderr, "Symtab section not found.\n"); - return false; - } - GElf_Shdr strtab_section; - if (!FindSectionByName(elf, kStrtabName, elf_header->e_shstrndx, - &strtab_section)) { - fprintf(stderr, "Strtab section not found.\n"); - return false; - } - - Elf_Sym *symbol = (Elf_Sym *)((char *)base + symtab_section.sh_offset); - for (int i = 0; i < symtab_section.sh_size/symtab_section.sh_entsize; ++i) { - struct SymbolEntry *symbol_entry = - (struct SymbolEntry *)malloc(sizeof(struct SymbolEntry)); - const char *name = reinterpret_cast<char *>( - strtab_section.sh_offset + (GElf_Word)base + symbol->st_name); - symbol_entry->offset = symbol->st_value; - symbol_entry->size = symbol->st_size; - symbols->symbol_entries.insert(make_pair(name, symbol_entry)); - ++symbol; - } - - - // Load symbols. - return LoadAllSymbols(&stab_section, &stabstr_section, base, symbols); -} - -bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) { - const char *arch_name = NULL; - if (arch == EM_386) - arch_name = "x86"; - else if (arch == EM_X86_64) - arch_name = "x86_64"; - else if (arch == EM_SPARC32PLUS) - arch_name = "SPARC_32+"; - else { - printf("Please add more ARCH support\n"); - return false; - } - - unsigned char identifier[16]; - google_breakpad::FileID file_id(obj_file.c_str()); - if (file_id.ElfFileIdentifier(identifier)) { - char identifier_str[40]; - file_id.ConvertIdentifierToString(identifier, - identifier_str, sizeof(identifier_str)); - std::string filename = obj_file; - size_t slash_pos = obj_file.find_last_of("/"); - if (slash_pos != std::string::npos) - filename = obj_file.substr(slash_pos + 1); - return WriteFormat(fd, "MODULE solaris %s %s %s\n", arch_name, - identifier_str, filename.c_str()); - } - return false; -} - -bool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) { - for (size_t i = 0; i < symbols.source_file_info.size(); ++i) { - if (symbols.source_file_info[i].source_id != -1) { - const char *name = symbols.source_file_info[i].name; - if (!WriteFormat(fd, "FILE %d %s\n", - symbols.source_file_info[i].source_id, name)) - return false; - } - } - return true; -} - -bool WriteOneFunction(int fd, int source_id, - const struct FuncInfo &func_info){ - // Discard the ending part of the name. - std::string func_name(func_info.name); - std::string::size_type last_colon = func_name.find_last_of(':'); - if (last_colon != std::string::npos) - func_name = func_name.substr(0, last_colon); - func_name = Demangle(func_name.c_str()); - - if (func_info.size <= 0) - return true; - - // rva_to_base could be unsigned long(32 bit) or unsigned long long(64 bit). - if (WriteFormat(fd, "FUNC %llx %x %d %s\n", - (long long)func_info.rva_to_base, - func_info.size, - func_info.stack_param_size, - func_name.c_str())) { - for (size_t i = 0; i < func_info.line_info.size(); ++i) { - const struct LineInfo &line_info = func_info.line_info[i]; - if (line_info.line_num == 0) - return true; - if (!WriteFormat(fd, "%llx %x %d %d\n", - (long long)line_info.rva_to_base, - line_info.size, - line_info.line_num, - source_id)) - return false; - } - return true; - } - return false; -} - -bool WriteFunctionInfo(int fd, const struct SymbolInfo &symbols) { - for (size_t i = 0; i < symbols.source_file_info.size(); ++i) { - const struct SourceFileInfo &file_info = symbols.source_file_info[i]; - for (size_t j = 0; j < file_info.func_info.size(); ++j) { - const struct FuncInfo &func_info = file_info.func_info[j]; - if (!WriteOneFunction(fd, file_info.source_id, func_info)) - return false; - } - } - return true; -} - -bool DumpStabSymbols(int fd, const struct SymbolInfo &symbols) { - return WriteSourceFileInfo(fd, symbols) && - WriteFunctionInfo(fd, symbols); -} - -// -// 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(void *mapped_address, size_t mapped_size) : - base_(mapped_address), size_(mapped_size) { - } - ~MmapWrapper() { - if (base_ != NULL) { - assert(size_ > 0); - munmap((char *)base_, size_); - } - } - void release() { - base_ = NULL; - size_ = 0; - } - - private: - void *base_; - size_t size_; -}; - -} // namespace - -namespace google_breakpad { - -class AutoElfEnder { - public: - AutoElfEnder(Elf *elf) : elf_(elf) {} - ~AutoElfEnder() { if (elf_) elf_end(elf_); } - private: - Elf *elf_; -}; - - -bool DumpSymbols::WriteSymbolFile(const std::string &obj_file, int sym_fd) { - if (elf_version(EV_CURRENT) == EV_NONE) { - fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); - return false; - } - - int obj_fd = open(obj_file.c_str(), O_RDONLY); - if (obj_fd < 0) - return false; - FDWrapper obj_fd_wrapper(obj_fd); - struct stat st; - if (fstat(obj_fd, &st) != 0 && st.st_size <= 0) - return false; - void *obj_base = mmap(NULL, st.st_size, - PROT_READ, MAP_PRIVATE, obj_fd, 0); - if (obj_base == MAP_FAILED) - return false; - MmapWrapper map_wrapper(obj_base, st.st_size); - GElf_Ehdr elf_header; - Elf *elf = elf_begin(obj_fd, ELF_C_READ, NULL); - AutoElfEnder elfEnder(elf); - - if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) { - fprintf(stderr, "failed to read elf header: %s\n", elf_errmsg(-1)); - return false; - } - - if (!IsValidElf(&elf_header)) { - fprintf(stderr, "header magic doesn't match\n"); - return false; - } - struct SymbolInfo symbols; - if (!LoadSymbols(elf, &elf_header, &symbols, obj_base)) - return false; - // Write to symbol file. - if (WriteModuleInfo(sym_fd, elf_header.e_machine, obj_file) && - DumpStabSymbols(sym_fd, symbols)) - return true; - - return false; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.h b/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.h deleted file mode 100644 index 7f4baadcf..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) 2007, 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.cc: Implements a Solaris stab debugging format dumper. -// -// Author: Alfred Peng - -#ifndef COMMON_SOLARIS_DUMP_SYMBOLS_H__ -#define COMMON_SOLARIS_DUMP_SYMBOLS_H__ - -#include <string> - -namespace google_breakpad { - -class DumpSymbols { - public: - bool WriteSymbolFile(const std::string &obj_file, - int sym_fd); -}; - -} // namespace google_breakpad - -#endif // COMMON_SOLARIS_DUMP_SYMBOLS_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.cc b/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.cc deleted file mode 100644 index 643a14629..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.cc +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2007, 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 -// -// Author: Alfred Peng - -#include <elf.h> -#include <fcntl.h> -#include <gelf.h> -#include <sys/mman.h> -#include <sys/ksyms.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -#include <cassert> -#include <cstdio> - -#include "common/md5.h" -#include "common/solaris/file_id.h" -#include "common/solaris/message_output.h" -#include "google_breakpad/common/minidump_format.h" - -namespace google_breakpad { - -class AutoElfEnder { - public: - AutoElfEnder(Elf *elf) : elf_(elf) {} - ~AutoElfEnder() { if (elf_) elf_end(elf_); } - private: - Elf *elf_; -}; - -// Find the text section in elf object file. -// Return the section start address and the size. -static bool FindElfTextSection(int fd, const void *elf_base, - const void **text_start, - int *text_size) { - assert(text_start); - assert(text_size); - - *text_start = NULL; - *text_size = 0; - - if (elf_version(EV_CURRENT) == EV_NONE) { - print_message2(2, "elf_version() failed: %s\n", elf_errmsg(0)); - return false; - } - - GElf_Ehdr elf_header; - lseek(fd, 0L, 0); - Elf *elf = elf_begin(fd, ELF_C_READ, NULL); - AutoElfEnder elfEnder(elf); - - if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) { - print_message2(2, "failed to read elf header: %s\n", elf_errmsg(-1)); - return false; - } - - if (elf_header.e_ident[EI_MAG0] != ELFMAG0 || - elf_header.e_ident[EI_MAG1] != ELFMAG1 || - elf_header.e_ident[EI_MAG2] != ELFMAG2 || - elf_header.e_ident[EI_MAG3] != ELFMAG3) { - print_message1(2, "header magic doesn't match\n"); - return false; - } - - static const char kTextSectionName[] = ".text"; - const GElf_Shdr *text_section = NULL; - Elf_Scn *scn = NULL; - GElf_Shdr shdr; - - while ((scn = elf_nextscn(elf, scn)) != NULL) { - if (gelf_getshdr(scn, &shdr) == (GElf_Shdr *)0) { - print_message2(2, "failed to read section header: %s\n", elf_errmsg(0)); - return false; - } - - if (shdr.sh_type == SHT_PROGBITS) { - const char *section_name = elf_strptr(elf, elf_header.e_shstrndx, - shdr.sh_name); - if (!section_name) { - print_message2(2, "Section name error: %s\n", elf_errmsg(-1)); - continue; - } - - if (strcmp(section_name, kTextSectionName) == 0) { - text_section = &shdr; - break; - } - } - } - if (text_section != NULL && text_section->sh_size > 0) { - *text_start = (char *)elf_base + text_section->sh_offset; - *text_size = text_section->sh_size; - return true; - } - - return false; -} - -FileID::FileID(const char *path) { - strcpy(path_, path); -} - -class AutoCloser { - public: - AutoCloser(int fd) : fd_(fd) {} - ~AutoCloser() { if (fd_) close(fd_); } - private: - int fd_; -}; - -bool FileID::ElfFileIdentifier(unsigned char identifier[16]) { - int fd = 0; - if ((fd = open(path_, O_RDONLY)) < 0) - return false; - - AutoCloser autocloser(fd); - struct stat st; - if (fstat(fd, &st) != 0 || st.st_size <= 0) - return false; - - void *base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (base == MAP_FAILED) - return false; - - bool success = false; - const void *text_section = NULL; - int text_size = 0; - - if (FindElfTextSection(fd, base, &text_section, &text_size)) { - MD5Context md5; - MD5Init(&md5); - MD5Update(&md5, (const unsigned char *)text_section, text_size); - MD5Final(identifier, &md5); - success = true; - } - - munmap((char *)base, st.st_size); - return success; -} - -// static -bool FileID::ConvertIdentifierToString(const unsigned char identifier[16], - char *buffer, int buffer_length) { - if (buffer_length < 34) - return false; - - int buffer_idx = 0; - for (int idx = 0; idx < 16; ++idx) { - int hi = (identifier[idx] >> 4) & 0x0F; - int lo = (identifier[idx]) & 0x0F; - - buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi; - buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo; - } - - // Add an extra "0" by the end. - buffer[buffer_idx++] = '0'; - - // NULL terminate - buffer[buffer_idx] = 0; - - return true; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.h b/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.h deleted file mode 100644 index 375e85751..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2007, 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 -// -// Author: Alfred Peng - -#ifndef COMMON_SOLARIS_FILE_ID_H__ -#define COMMON_SOLARIS_FILE_ID_H__ - -#include <limits.h> - -namespace google_breakpad { - -class FileID { - public: - FileID(const char *path); - ~FileID() {}; - - // Load the identifier for the elf file path specified in the constructor into - // |identifier|. Return false if the identifier could not be created for the - // file. - // The current implementation will return the MD5 hash of the file's bytes. - bool ElfFileIdentifier(unsigned char identifier[16]); - - // Convert the |identifier| data to a NULL terminated string. The string will - // be formatted as a MDCVInfoPDB70 struct. - // The |buffer| should be at least 34 bytes long to receive all of the data - // and termination. Shorter buffers will return false. - static bool ConvertIdentifierToString(const unsigned char identifier[16], - char *buffer, int buffer_length); - - private: - // Storage for the path specified - char path_[PATH_MAX]; -}; - -} // namespace google_breakpad - -#endif // COMMON_SOLARIS_FILE_ID_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.cc b/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.cc deleted file mode 100644 index e9e6c6f5d..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.cc +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: Alfred Peng - -#include <cassert> -#include <ctime> - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include "common/solaris/guid_creator.h" - -// -// GUIDGenerator -// -// This class is used to generate random GUID. -// Currently use random number to generate a GUID. This should be OK since -// we don't expect crash to happen very offen. -// -class GUIDGenerator { - public: - GUIDGenerator() { - srandom(time(NULL)); - } - - bool CreateGUID(GUID *guid) const { - guid->data1 = random(); - guid->data2 = (uint16_t)(random()); - guid->data3 = (uint16_t)(random()); - *reinterpret_cast<uint32_t*>(&guid->data4[0]) = random(); - *reinterpret_cast<uint32_t*>(&guid->data4[4]) = random(); - return true; - } -}; - -// Guid generator. -const GUIDGenerator kGuidGenerator; - -bool CreateGUID(GUID *guid) { - return kGuidGenerator.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, - *reinterpret_cast<const uint32_t *>(&(guid->data4[0])), - *reinterpret_cast<const uint32_t *>(&(guid->data4[4]))); - if (num != kGUIDStringLength) - return false; - - buf[num] = '\0'; - return true; -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.h b/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.h deleted file mode 100644 index 4aee3a1c2..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: Alfred Peng - -#ifndef COMMON_SOLARIS_GUID_CREATOR_H__ -#define COMMON_SOLARIS_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 // COMMON_SOLARIS_GUID_CREATOR_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/message_output.h b/toolkit/crashreporter/google-breakpad/src/common/solaris/message_output.h deleted file mode 100644 index 3e3b1d465..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/solaris/message_output.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: Alfred Peng - -#ifndef COMMON_SOLARIS_MESSAGE_OUTPUT_H__ -#define COMMON_SOLARIS_MESSAGE_OUTPUT_H__ - -namespace google_breakpad { - -const int MESSAGE_MAX = 1000; - -// Message output macros. -// snprintf doesn't operate heap on Solaris, while printf and fprintf do. -// Use snprintf here to avoid heap allocation. -#define print_message1(std, message) \ - char buffer[MESSAGE_MAX]; \ - int len = snprintf(buffer, MESSAGE_MAX, message); \ - write(std, buffer, len) - -#define print_message2(std, message, para) \ - char buffer[MESSAGE_MAX]; \ - int len = snprintf(buffer, MESSAGE_MAX, message, para); \ - write(std, buffer, len); - -} // namespace google_breakpad - -#endif // COMMON_SOLARIS_MESSAGE_OUTPUT_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/moz.build b/toolkit/crashreporter/google-breakpad/src/common/solaris/moz.build deleted file mode 100644 index c91b96fc7..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/solaris/moz.build +++ /dev/null @@ -1,34 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -UNIFIED_SOURCES += [ - 'dump_symbols.cc', - 'file_id.cc', - 'guid_creator.cc', -] - -HostLibrary('host_breakpad_solaris_common_s') - -Library('breakpad_solaris_common_s') - -# not compiling http_upload.cc currently -# since it depends on libcurl -HOST_SOURCES += [ - 'dump_symbols.cc', - 'file_id.cc', - 'guid_creator.cc', -] -HOST_CXXFLAGS += [ - '-O2', - '-g', -] - -FINAL_LIBRARY = 'xul' - -LOCAL_INCLUDES += [ - '../..', -] - diff --git a/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.cc b/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.cc deleted file mode 100644 index 6019fc7ee..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.cc +++ /dev/null @@ -1,315 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// This file implements the google_breakpad::StabsReader class. -// See stabs_reader.h. - -#include "common/stabs_reader.h" - -#include <assert.h> -#include <stab.h> -#include <string.h> - -#include <string> - -#include "common/using_std_string.h" - -using std::vector; - -namespace google_breakpad { - -StabsReader::EntryIterator::EntryIterator(const ByteBuffer *buffer, - bool big_endian, size_t value_size) - : value_size_(value_size), cursor_(buffer, big_endian) { - // Actually, we could handle weird sizes just fine, but they're - // probably mistakes --- expressed in bits, say. - assert(value_size == 4 || value_size == 8); - entry_.index = 0; - Fetch(); -} - -void StabsReader::EntryIterator::Fetch() { - cursor_ - .Read(4, false, &entry_.name_offset) - .Read(1, false, &entry_.type) - .Read(1, false, &entry_.other) - .Read(2, false, &entry_.descriptor) - .Read(value_size_, false, &entry_.value); - entry_.at_end = !cursor_; -} - -StabsReader::StabsReader(const uint8_t *stab, size_t stab_size, - const uint8_t *stabstr, size_t stabstr_size, - bool big_endian, size_t value_size, bool unitized, - StabsHandler *handler) - : entries_(stab, stab_size), - strings_(stabstr, stabstr_size), - iterator_(&entries_, big_endian, value_size), - unitized_(unitized), - handler_(handler), - string_offset_(0), - next_cu_string_offset_(0), - current_source_file_(NULL) { } - -const char *StabsReader::SymbolString() { - ptrdiff_t offset = string_offset_ + iterator_->name_offset; - if (offset < 0 || (size_t) offset >= strings_.Size()) { - handler_->Warning("symbol %d: name offset outside the string section\n", - iterator_->index); - // Return our null string, to keep our promise about all names being - // taken from the string section. - offset = 0; - } - return reinterpret_cast<const char *>(strings_.start + offset); -} - -bool StabsReader::Process() { - while (!iterator_->at_end) { - if (iterator_->type == N_SO) { - if (! ProcessCompilationUnit()) - return false; - } else if (iterator_->type == N_UNDF && unitized_) { - // In unitized STABS (including Linux STABS, and pretty much anything - // else that puts STABS data in sections), at the head of each - // compilation unit's entries there is an N_UNDF stab giving the - // number of symbols in the compilation unit, and the number of bytes - // that compilation unit's strings take up in the .stabstr section. - // Each CU's strings are separate; the n_strx values are offsets - // within the current CU's portion of the .stabstr section. - // - // As an optimization, the GNU linker combines all the - // compilation units into one, with a single N_UNDF at the - // beginning. However, other linkers, like Gold, do not perform - // this optimization. - string_offset_ = next_cu_string_offset_; - next_cu_string_offset_ = iterator_->value; - ++iterator_; - } -#if defined(HAVE_MACH_O_NLIST_H) - // Export symbols in Mach-O binaries look like this. - // This is necessary in order to be able to dump symbols - // from OS X system libraries. - else if ((iterator_->type & N_STAB) == 0 && - (iterator_->type & N_TYPE) == N_SECT) { - ProcessExtern(); - } -#endif - else { - ++iterator_; - } - } - return true; -} - -bool StabsReader::ProcessCompilationUnit() { - assert(!iterator_->at_end && iterator_->type == N_SO); - - // There may be an N_SO entry whose name ends with a slash, - // indicating the directory in which the compilation occurred. - // The build directory defaults to NULL. - const char *build_directory = NULL; - { - const char *name = SymbolString(); - if (name[0] && name[strlen(name) - 1] == '/') { - build_directory = name; - ++iterator_; - } - } - - // We expect to see an N_SO entry with a filename next, indicating - // the start of the compilation unit. - { - if (iterator_->at_end || iterator_->type != N_SO) - return true; - const char *name = SymbolString(); - if (name[0] == '\0') { - // This seems to be a stray end-of-compilation-unit marker; - // consume it, but don't report the end, since we didn't see a - // beginning. - ++iterator_; - return true; - } - current_source_file_ = name; - } - - if (! handler_->StartCompilationUnit(current_source_file_, - iterator_->value, - build_directory)) - return false; - - ++iterator_; - - // The STABS documentation says that some compilers may emit - // additional N_SO entries with names immediately following the - // first, and that they should be ignored. However, the original - // Breakpad STABS reader doesn't ignore them, so we won't either. - - // Process the body of the compilation unit, up to the next N_SO. - while (!iterator_->at_end && iterator_->type != N_SO) { - if (iterator_->type == N_FUN) { - if (! ProcessFunction()) - return false; - } else if (iterator_->type == N_SLINE) { - // Mac OS X STABS place SLINE records before functions. - Line line; - // The value of an N_SLINE entry that appears outside a function is - // the absolute address of the line. - line.address = iterator_->value; - line.filename = current_source_file_; - // The n_desc of a N_SLINE entry is the line number. It's a - // signed 16-bit field; line numbers from 32768 to 65535 are - // stored as n-65536. - line.number = (uint16_t) iterator_->descriptor; - queued_lines_.push_back(line); - ++iterator_; - } else if (iterator_->type == N_SOL) { - current_source_file_ = SymbolString(); - ++iterator_; - } else { - // Ignore anything else. - ++iterator_; - } - } - - // An N_SO with an empty name indicates the end of the compilation - // unit. Default to zero. - uint64_t ending_address = 0; - if (!iterator_->at_end) { - assert(iterator_->type == N_SO); - const char *name = SymbolString(); - if (name[0] == '\0') { - ending_address = iterator_->value; - ++iterator_; - } - } - - if (! handler_->EndCompilationUnit(ending_address)) - return false; - - queued_lines_.clear(); - - return true; -} - -bool StabsReader::ProcessFunction() { - assert(!iterator_->at_end && iterator_->type == N_FUN); - - uint64_t function_address = iterator_->value; - // The STABS string for an N_FUN entry is the name of the function, - // followed by a colon, followed by type information for the - // function. We want to pass the name alone to StartFunction. - const char *stab_string = SymbolString(); - const char *name_end = strchr(stab_string, ':'); - if (! name_end) - name_end = stab_string + strlen(stab_string); - string name(stab_string, name_end - stab_string); - if (! handler_->StartFunction(name, function_address)) - return false; - ++iterator_; - - // If there were any SLINE records given before the function, report them now. - for (vector<Line>::const_iterator it = queued_lines_.begin(); - it != queued_lines_.end(); it++) { - if (!handler_->Line(it->address, it->filename, it->number)) - return false; - } - queued_lines_.clear(); - - while (!iterator_->at_end) { - if (iterator_->type == N_SO || iterator_->type == N_FUN) - break; - else if (iterator_->type == N_SLINE) { - // The value of an N_SLINE entry is the offset of the line from - // the function's start address. - uint64_t line_address = function_address + iterator_->value; - // The n_desc of a N_SLINE entry is the line number. It's a - // signed 16-bit field; line numbers from 32768 to 65535 are - // stored as n-65536. - uint16_t line_number = iterator_->descriptor; - if (! handler_->Line(line_address, current_source_file_, line_number)) - return false; - ++iterator_; - } else if (iterator_->type == N_SOL) { - current_source_file_ = SymbolString(); - ++iterator_; - } else - // Ignore anything else. - ++iterator_; - } - - // We've reached the end of the function. See if we can figure out its - // ending address. - uint64_t ending_address = 0; - if (!iterator_->at_end) { - assert(iterator_->type == N_SO || iterator_->type == N_FUN); - if (iterator_->type == N_FUN) { - const char *symbol_name = SymbolString(); - if (symbol_name[0] == '\0') { - // An N_FUN entry with no name is a terminator for this function; - // its value is the function's size. - ending_address = function_address + iterator_->value; - ++iterator_; - } else { - // An N_FUN entry with a name is the next function, and we can take - // its value as our ending address. Don't advance the iterator, as - // we'll use this symbol to start the next function as well. - ending_address = iterator_->value; - } - } else { - // An N_SO entry could be an end-of-compilation-unit marker, or the - // start of the next compilation unit, but in either case, its value - // is our ending address. We don't advance the iterator; - // ProcessCompilationUnit will decide what to do with this symbol. - ending_address = iterator_->value; - } - } - - if (! handler_->EndFunction(ending_address)) - return false; - - return true; -} - -bool StabsReader::ProcessExtern() { -#if defined(HAVE_MACH_O_NLIST_H) - assert(!iterator_->at_end && - (iterator_->type & N_STAB) == 0 && - (iterator_->type & N_TYPE) == N_SECT); -#endif - - // TODO(mark): only do symbols in the text section? - if (!handler_->Extern(SymbolString(), iterator_->value)) - return false; - - ++iterator_; - return true; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.h b/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.h deleted file mode 100644 index 98ee2dd53..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.h +++ /dev/null @@ -1,325 +0,0 @@ -// -*- mode: c++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// stabs_reader.h: Define StabsReader, a parser for STABS debugging -// information. A description of the STABS debugging format can be -// found at: -// -// http://sourceware.org/gdb/current/onlinedocs/stabs_toc.html -// -// The comments here assume you understand the format. -// -// This parser can handle big-endian and little-endian data, and the symbol -// values may be either 32 or 64 bits long. It handles both STABS in -// sections (as used on Linux) and STABS appearing directly in an -// a.out-like symbol table (as used in Darwin OS X Mach-O files). - -#ifndef COMMON_STABS_READER_H__ -#define COMMON_STABS_READER_H__ - -#include <stddef.h> -#include <stdint.h> - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#ifdef HAVE_MACH_O_NLIST_H -#include <mach-o/nlist.h> -#elif defined(HAVE_A_OUT_H) -#include <a.out.h> -#endif - -#include <string> -#include <vector> - -#include "common/byte_cursor.h" -#include "common/using_std_string.h" - -namespace google_breakpad { - -class StabsHandler; - -class StabsReader { - public: - // Create a reader for the STABS debug information whose .stab section is - // being traversed by ITERATOR, and whose .stabstr section is referred to - // by STRINGS. The reader will call the member functions of HANDLER to - // report the information it finds, when the reader's 'Process' member - // function is called. - // - // BIG_ENDIAN should be true if the entries in the .stab section are in - // big-endian form, or false if they are in little-endian form. - // - // VALUE_SIZE should be either 4 or 8, indicating the size of the 'value' - // field in each entry in bytes. - // - // UNITIZED should be true if the STABS data is stored in units with - // N_UNDF headers. This is usually the case for STABS stored in sections, - // like .stab/.stabstr, and usually not the case for STABS stored in the - // actual symbol table; UNITIZED should be true when parsing Linux stabs, - // false when parsing Mac OS X STABS. For details, see: - // http://sourceware.org/gdb/current/onlinedocs/stabs/Stab-Section-Basics.html - // - // Note that, in ELF, the .stabstr section should be found using the - // 'sh_link' field of the .stab section header, not by name. - StabsReader(const uint8_t *stab, size_t stab_size, - const uint8_t *stabstr, size_t stabstr_size, - bool big_endian, size_t value_size, bool unitized, - StabsHandler *handler); - - // Process the STABS data, calling the handler's member functions to - // report what we find. While the handler functions return true, - // continue to process until we reach the end of the section. If we - // processed the entire section and all handlers returned true, - // return true. If any handler returned false, return false. - // - // This is only meant to be called once per StabsReader instance; - // resuming a prior processing pass that stopped abruptly isn't supported. - bool Process(); - - private: - - // An class for walking arrays of STABS entries. This isolates the main - // STABS reader from the exact format (size; endianness) of the entries - // themselves. - class EntryIterator { - public: - // The contents of a STABS entry, adjusted for the host's endianness, - // word size, 'struct nlist' layout, and so on. - struct Entry { - // True if this iterator has reached the end of the entry array. When - // this is set, the other members of this structure are not valid. - bool at_end; - - // The number of this entry within the list. - size_t index; - - // The current entry's name offset. This is the offset within the - // current compilation unit's strings, as establish by the N_UNDF entries. - size_t name_offset; - - // The current entry's type, 'other' field, descriptor, and value. - unsigned char type; - unsigned char other; - short descriptor; - uint64_t value; - }; - - // Create a EntryIterator walking the entries in BUFFER. Treat the - // entries as big-endian if BIG_ENDIAN is true, as little-endian - // otherwise. Assume each entry has a 'value' field whose size is - // VALUE_SIZE. - // - // This would not be terribly clean to extend to other format variations, - // but it's enough to handle Linux and Mac, and we'd like STABS to die - // anyway. - // - // For the record: on Linux, STABS entry values are always 32 bits, - // regardless of the architecture address size (don't ask me why); on - // Mac, they are 32 or 64 bits long. Oddly, the section header's entry - // size for a Linux ELF .stab section varies according to the ELF class - // from 12 to 20 even as the actual entries remain unchanged. - EntryIterator(const ByteBuffer *buffer, bool big_endian, size_t value_size); - - // Move to the next entry. This function's behavior is undefined if - // at_end() is true when it is called. - EntryIterator &operator++() { Fetch(); entry_.index++; return *this; } - - // Dereferencing this iterator produces a reference to an Entry structure - // that holds the current entry's values. The entry is owned by this - // EntryIterator, and will be invalidated at the next call to operator++. - const Entry &operator*() const { return entry_; } - const Entry *operator->() const { return &entry_; } - - private: - // Read the STABS entry at cursor_, and set entry_ appropriately. - void Fetch(); - - // The size of entries' value field, in bytes. - size_t value_size_; - - // A byte cursor traversing buffer_. - ByteCursor cursor_; - - // Values for the entry this iterator refers to. - Entry entry_; - }; - - // A source line, saved to be reported later. - struct Line { - uint64_t address; - const char *filename; - int number; - }; - - // Return the name of the current symbol. - const char *SymbolString(); - - // Process a compilation unit starting at symbol_. Return true - // to continue processing, or false to abort. - bool ProcessCompilationUnit(); - - // Process a function in current_source_file_ starting at symbol_. - // Return true to continue processing, or false to abort. - bool ProcessFunction(); - - // Process an exported function symbol. - // Return true to continue processing, or false to abort. - bool ProcessExtern(); - - // The STABS entries being parsed. - ByteBuffer entries_; - - // The string section to which the entries refer. - ByteBuffer strings_; - - // The iterator walking the STABS entries. - EntryIterator iterator_; - - // True if the data is "unitized"; see the explanation in the comment for - // StabsReader::StabsReader. - bool unitized_; - - StabsHandler *handler_; - - // The offset of the current compilation unit's strings within stabstr_. - size_t string_offset_; - - // The value string_offset_ should have for the next compilation unit, - // as established by N_UNDF entries. - size_t next_cu_string_offset_; - - // The current source file name. - const char *current_source_file_; - - // Mac OS X STABS place SLINE records before functions; we accumulate a - // vector of these until we see the FUN record, and then report them - // after the StartFunction call. - std::vector<Line> queued_lines_; -}; - -// Consumer-provided callback structure for the STABS reader. Clients -// of the STABS reader provide an instance of this structure. The -// reader then invokes the member functions of that instance to report -// the information it finds. -// -// The default definitions of the member functions do nothing, and return -// true so processing will continue. -class StabsHandler { - public: - StabsHandler() { } - virtual ~StabsHandler() { } - - // Some general notes about the handler callback functions: - - // Processing proceeds until the end of the .stabs section, or until - // one of these functions returns false. - - // The addresses given are as reported in the STABS info, without - // regard for whether the module may be loaded at different - // addresses at different times (a shared library, say). When - // processing STABS from an ELF shared library, the addresses given - // all assume the library is loaded at its nominal load address. - // They are *not* offsets from the nominal load address. If you - // want offsets, you must subtract off the library's nominal load - // address. - - // The arguments to these functions named FILENAME are all - // references to strings stored in the .stabstr section. Because - // both the Linux and Solaris linkers factor out duplicate strings - // from the .stabstr section, the consumer can assume that if two - // FILENAME values are different addresses, they represent different - // file names. - // - // Thus, it's safe to use (say) std::map<char *, ...>, which does - // string address comparisons, not string content comparisons. - // Since all the strings are in same array of characters --- the - // .stabstr section --- comparing their addresses produces - // predictable, if not lexicographically meaningful, results. - - // Begin processing a compilation unit whose main source file is - // named FILENAME, and whose base address is ADDRESS. If - // BUILD_DIRECTORY is non-NULL, it is the name of the build - // directory in which the compilation occurred. - virtual bool StartCompilationUnit(const char *filename, uint64_t address, - const char *build_directory) { - return true; - } - - // Finish processing the compilation unit. If ADDRESS is non-zero, - // it is the ending address of the compilation unit. If ADDRESS is - // zero, then the compilation unit's ending address is not - // available, and the consumer must infer it by other means. - virtual bool EndCompilationUnit(uint64_t address) { return true; } - - // Begin processing a function named NAME, whose starting address is - // ADDRESS. This function belongs to the compilation unit that was - // most recently started but not ended. - // - // Note that, unlike filenames, NAME is not a pointer into the - // .stabstr section; this is because the name as it appears in the - // STABS data is followed by type information. The value passed to - // StartFunction is the function name alone. - // - // In languages that use name mangling, like C++, NAME is mangled. - virtual bool StartFunction(const string &name, uint64_t address) { - return true; - } - - // Finish processing the function. If ADDRESS is non-zero, it is - // the ending address for the function. If ADDRESS is zero, then - // the function's ending address is not available, and the consumer - // must infer it by other means. - virtual bool EndFunction(uint64_t address) { return true; } - - // Report that the code at ADDRESS is attributable to line NUMBER of - // the source file named FILENAME. The caller must infer the ending - // address of the line. - virtual bool Line(uint64_t address, const char *filename, int number) { - return true; - } - - // Report that an exported function NAME is present at ADDRESS. - // The size of the function is unknown. - virtual bool Extern(const string &name, uint64_t address) { - return true; - } - - // Report a warning. FORMAT is a printf-like format string, - // specifying how to format the subsequent arguments. - virtual void Warning(const char *format, ...) = 0; -}; - -} // namespace google_breakpad - -#endif // COMMON_STABS_READER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/stabs_reader_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/stabs_reader_unittest.cc deleted file mode 100644 index a84da1c4c..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/stabs_reader_unittest.cc +++ /dev/null @@ -1,611 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// stabs_reader_unittest.cc: Unit tests for google_breakpad::StabsReader. - -#include <assert.h> -#include <errno.h> -#include <stab.h> -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> - -#include <fstream> -#include <iomanip> -#include <iostream> -#include <map> -#include <sstream> -#include <string> - -#include "breakpad_googletest_includes.h" -#include "common/stabs_reader.h" -#include "common/test_assembler.h" -#include "common/using_std_string.h" - -using ::testing::Eq; -using ::testing::InSequence; -using ::testing::Return; -using ::testing::StrEq; -using ::testing::Test; -using ::testing::_; -using google_breakpad::StabsHandler; -using google_breakpad::StabsReader; -using google_breakpad::test_assembler::Label; -using google_breakpad::test_assembler::Section; -using google_breakpad::test_assembler::kBigEndian; -using google_breakpad::test_assembler::kLittleEndian; -using std::map; - -namespace { - -// A StringAssembler is a class for generating .stabstr sections to present -// as input to the STABS parser. -class StringAssembler: public Section { - public: - StringAssembler() : in_cu_(false) { StartCU(); } - - // Add the string S to this StringAssembler, and return the string's - // offset within this compilation unit's strings. If S has been added - // already, this returns the offset of its first instance. - size_t Add(const string &s) { - map<string, size_t>::iterator it = added_.find(s); - if (it != added_.end()) - return it->second; - size_t offset = Size() - cu_start_; - AppendCString(s); - added_[s] = offset; - return offset; - } - - // Start a fresh compilation unit string collection. - void StartCU() { - // Ignore duplicate calls to StartCU. Our test data don't always call - // StartCU at all, meaning that our constructor has to take care of it, - // meaning that tests that *do* call StartCU call it twice at the - // beginning. This is not worth smoothing out. - if (in_cu_) return; - - added_.clear(); - cu_start_ = Size(); - - // Each compilation unit's strings start with an empty string. - AppendCString(""); - added_[""] = 0; - - in_cu_ = true; - } - - // Finish off the current CU's strings. - size_t EndCU() { - assert(in_cu_); - in_cu_ = false; - return Size() - cu_start_; - } - - private: - // The offset of the start of this compilation unit's strings. - size_t cu_start_; - - // True if we're in a CU. - bool in_cu_; - - // A map from the strings that have been added to this section to - // their starting indices within their compilation unit. - map<string, size_t> added_; -}; - -// A StabsAssembler is a class for generating .stab sections to present as -// test input for the STABS parser. -class StabsAssembler: public Section { - public: - // Create a StabsAssembler that uses StringAssembler for its strings. - StabsAssembler(StringAssembler *string_assembler) - : Section(string_assembler->endianness()), - string_assembler_(string_assembler), - value_size_(0), - entry_count_(0), - cu_header_(NULL) { } - ~StabsAssembler() { assert(!cu_header_); } - - // Accessor and setter for value_size_. - size_t value_size() const { return value_size_; } - StabsAssembler &set_value_size(size_t value_size) { - value_size_ = value_size; - return *this; - } - - // Append a STAB entry to the end of this section with the given - // characteristics. NAME is the offset of this entry's name string within - // its compilation unit's portion of the .stabstr section; this can be a - // value generated by a StringAssembler. Return a reference to this - // StabsAssembler. - StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor, - Label value, Label name) { - D32(name); - D8(type); - D8(other); - D16(descriptor); - Append(endianness(), value_size_, value); - entry_count_++; - return *this; - } - - // As above, but automatically add NAME to our StringAssembler. - StabsAssembler &Stab(uint8_t type, uint8_t other, Label descriptor, - Label value, const string &name) { - return Stab(type, other, descriptor, value, string_assembler_->Add(name)); - } - - // Start a compilation unit named NAME, with an N_UNDF symbol to start - // it, and its own portion of the string section. Return a reference to - // this StabsAssembler. - StabsAssembler &StartCU(const string &name) { - assert(!cu_header_); - cu_header_ = new CUHeader; - string_assembler_->StartCU(); - entry_count_ = 0; - return Stab(N_UNDF, 0, - cu_header_->final_entry_count, - cu_header_->final_string_size, - string_assembler_->Add(name)); - } - - // Close off the current compilation unit. Return a reference to this - // StabsAssembler. - StabsAssembler &EndCU() { - assert(cu_header_); - cu_header_->final_entry_count = entry_count_; - cu_header_->final_string_size = string_assembler_->EndCU(); - delete cu_header_; - cu_header_ = NULL; - return *this; - } - - private: - // Data used in a compilation unit header STAB that we won't know until - // we've finished the compilation unit. - struct CUHeader { - // The final number of entries this compilation unit will hold. - Label final_entry_count; - - // The final size of this compilation unit's strings. - Label final_string_size; - }; - - // The strings for our STABS entries. - StringAssembler *string_assembler_; - - // The size of the 'value' field of stabs entries in this section. - size_t value_size_; - - // The number of entries in this compilation unit so far. - size_t entry_count_; - - // Header labels for this compilation unit, if we've started one but not - // finished it. - CUHeader *cu_header_; -}; - -class MockStabsReaderHandler: public StabsHandler { - public: - MOCK_METHOD3(StartCompilationUnit, - bool(const char *, uint64_t, const char *)); - MOCK_METHOD1(EndCompilationUnit, bool(uint64_t)); - MOCK_METHOD2(StartFunction, bool(const string &, uint64_t)); - MOCK_METHOD1(EndFunction, bool(uint64_t)); - MOCK_METHOD3(Line, bool(uint64_t, const char *, int)); - MOCK_METHOD2(Extern, bool(const string &, uint64_t)); - void Warning(const char *format, ...) { MockWarning(format); } - MOCK_METHOD1(MockWarning, void(const char *)); -}; - -struct StabsFixture { - StabsFixture() : stabs(&strings), unitized(true) { } - - // Create a StabsReader to parse the mock stabs data in stabs and - // strings, and pass the parsed information to mock_handler. Use the - // endianness and value size of stabs to parse the data. If all goes - // well, return the result of calling the reader's Process member - // function. Otherwise, return false. - bool ApplyHandlerToMockStabsData() { - string stabs_contents, stabstr_contents; - if (!stabs.GetContents(&stabs_contents) || - !strings.GetContents(&stabstr_contents)) - return false; - - // Run the parser on the test input, passing whatever we find to HANDLER. - StabsReader reader( - reinterpret_cast<const uint8_t *>(stabs_contents.data()), - stabs_contents.size(), - reinterpret_cast<const uint8_t *>(stabstr_contents.data()), - stabstr_contents.size(), - stabs.endianness() == kBigEndian, stabs.value_size(), unitized, - &mock_handler); - return reader.Process(); - } - - StringAssembler strings; - StabsAssembler stabs; - bool unitized; - MockStabsReaderHandler mock_handler; -}; - -class Stabs: public StabsFixture, public Test { }; - -TEST_F(Stabs, MockStabsInput) { - stabs.set_endianness(kLittleEndian); - stabs.set_value_size(4); - stabs - .Stab(N_SO, 149, 40232, 0x18a2a72bU, "builddir/") - .Stab(N_FUN, 83, 50010, 0x91a5353fU, - "not the SO with source file name we expected ") - .Stab(N_SO, 165, 24791, 0xfe69d23cU, "") - .Stab(N_SO, 184, 34178, 0xca4d883aU, "builddir1/") - .Stab(N_SO, 83, 40859, 0xd2fe5df3U, "file1.c") - .Stab(N_LSYM, 147, 39565, 0x60d4bb8aU, "not the FUN we're looking for") - .Stab(N_FUN, 120, 50271, 0xa049f4b1U, "fun1") - .Stab(N_BINCL, 150, 15694, 0xef65c659U, - "something to ignore in a FUN body") - .Stab(N_SLINE, 147, 4967, 0xd904b3f, "") - .Stab(N_SOL, 177, 56135, 0xbd97b1dcU, "header.h") - .Stab(N_SLINE, 130, 24610, 0x90f145b, "") - .Stab(N_FUN, 45, 32441, 0xbf27cf93U, - "fun2:some stabs type info here:to trim from the name") - .Stab(N_SLINE, 138, 39002, 0x8148b87, "") - .Stab(N_SOL, 60, 49318, 0x1d06e025U, "file1.c") - .Stab(N_SLINE, 29, 52163, 0x6eebbb7, "") - .Stab(N_SO, 167, 4647, 0xd04b7448U, "") - .Stab(N_LSYM, 58, 37837, 0xe6b14d37U, "") - .Stab(N_SO, 152, 7810, 0x11759f10U, "file3.c") - .Stab(N_SO, 218, 12447, 0x11cfe4b5U, ""); - - { - InSequence s; - - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file1.c"), 0xd2fe5df3U, - StrEq("builddir1/"))) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, StartFunction(StrEq("fun1"), 0xa049f4b1U)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - Line(0xa049f4b1U + 0xd904b3f, StrEq("file1.c"), 4967)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - Line(0xa049f4b1U + 0x90f145b, StrEq("header.h"), 24610)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0xbf27cf93U)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, StartFunction(StrEq("fun2"), 0xbf27cf93U)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - Line(0xbf27cf93U + 0x8148b87, StrEq("header.h"), 39002)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - Line(0xbf27cf93U + 0x6eebbb7, StrEq("file1.c"), 52163)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0xd04b7448U)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0xd04b7448U)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, StartCompilationUnit(StrEq("file3.c"), - 0x11759f10U, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0x11cfe4b5U)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData()); -} - -TEST_F(Stabs, AbruptCU) { - stabs.set_endianness(kBigEndian); - stabs.set_value_size(4); - stabs.Stab(N_SO, 177, 23446, 0xbf10d5e4, "file2-1.c"); - - { - InSequence s; - - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file2-1.c"), 0xbf10d5e4, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData()); -} - -TEST_F(Stabs, AbruptFunction) { - stabs.set_endianness(kLittleEndian); - stabs.set_value_size(8); - stabs - .Stab(N_SO, 218, 26631, 0xb83ddf10U, "file3-1.c") - .Stab(N_FUN, 113, 24765, 0xbbd4a145U, "fun3_1"); - - { - InSequence s; - - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file3-1.c"), 0xb83ddf10U, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, StartFunction(StrEq("fun3_1"), 0xbbd4a145U)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData()); -} - -TEST_F(Stabs, NoCU) { - stabs.set_endianness(kBigEndian); - stabs.set_value_size(8); - stabs.Stab(N_SO, 161, 25673, 0x8f676e7bU, "build-directory/"); - - EXPECT_CALL(mock_handler, StartCompilationUnit(_, _, _)) - .Times(0); - EXPECT_CALL(mock_handler, StartFunction(_, _)) - .Times(0); - - ASSERT_TRUE(ApplyHandlerToMockStabsData()); -} - -TEST_F(Stabs, NoCUEnd) { - stabs.set_endianness(kBigEndian); - stabs.set_value_size(8); - stabs - .Stab(N_SO, 116, 58280, 0x2f7493c9U, "file5-1.c") - .Stab(N_SO, 224, 23057, 0xf9f1d50fU, "file5-2.c"); - - { - InSequence s; - - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file5-1.c"), 0x2f7493c9U, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("file5-2.c"), 0xf9f1d50fU, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData()); -} - -// On systems that store STABS in sections, string offsets are relative to -// the beginning of that compilation unit's strings, marked with N_UNDF -// symbols; see the comments for StabsReader::StabsReader. -TEST_F(Stabs, Unitized) { - stabs.set_endianness(kBigEndian); - stabs.set_value_size(4); - stabs - .StartCU("antimony") - .Stab(N_SO, 49, 26043, 0x7e259f1aU, "antimony") - .Stab(N_FUN, 101, 63253, 0x7fbcccaeU, "arsenic") - .Stab(N_SO, 124, 37175, 0x80b0014cU, "") - .EndCU() - .StartCU("aluminum") - .Stab(N_SO, 72, 23084, 0x86756839U, "aluminum") - .Stab(N_FUN, 59, 3305, 0xa8e120b0U, "selenium") - .Stab(N_SO, 178, 56949, 0xbffff983U, "") - .EndCU(); - - { - InSequence s; - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("antimony"), 0x7e259f1aU, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, StartFunction(Eq("arsenic"), 0x7fbcccaeU)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0x80b0014cU)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0x80b0014cU)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("aluminum"), 0x86756839U, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, StartFunction(Eq("selenium"), 0xa8e120b0U)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0xbffff983U)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0xbffff983U)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData()); -} - -// On systems that store STABS entries in the real symbol table, the N_UNDF -// entries have no special meaning, and shouldn't mess up the string -// indices. -TEST_F(Stabs, NonUnitized) { - stabs.set_endianness(kLittleEndian); - stabs.set_value_size(4); - unitized = false; - stabs - .Stab(N_UNDF, 21, 11551, 0x9bad2b2e, "") - .Stab(N_UNDF, 21, 11551, 0x9bad2b2e, "") - .Stab(N_SO, 71, 45139, 0x11a97352, "Tanzania") - .Stab(N_SO, 221, 41976, 0x21a97352, ""); - - { - InSequence s; - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("Tanzania"), - 0x11a97352, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0x21a97352)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData()); -} - -TEST_F(Stabs, FunctionEnd) { - stabs.set_endianness(kLittleEndian); - stabs.set_value_size(8); - stabs - .Stab(N_SO, 102, 62362, 0x52a830d644cd6942ULL, "compilation unit") - // This function is terminated by the start of the next function. - .Stab(N_FUN, 216, 38405, 0xbb5ab70ecdd23bfeULL, "function 1") - // This function is terminated by an explicit end-of-function stab, - // whose value is a size in bytes. - .Stab(N_FUN, 240, 10973, 0xc954de9b8fb3e5e2ULL, "function 2") - .Stab(N_FUN, 14, 36749, 0xc1ab, "") - // This function is terminated by the end of the compilation unit. - .Stab(N_FUN, 143, 64514, 0xdff98c9a35386e1fULL, "function 3") - .Stab(N_SO, 164, 60142, 0xfdacb856e78bbf57ULL, ""); - - { - InSequence s; - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("compilation unit"), - 0x52a830d644cd6942ULL, NULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - StartFunction(Eq("function 1"), 0xbb5ab70ecdd23bfeULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - StartFunction(Eq("function 2"), 0xc954de9b8fb3e5e2ULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0xc954de9b8fb3e5e2ULL + 0xc1ab)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - StartFunction(Eq("function 3"), 0xdff98c9a35386e1fULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0xfdacb856e78bbf57ULL)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0xfdacb856e78bbf57ULL)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData()); -} - -// On Mac OS X, SLINE records can appear before the FUN stab to which they -// belong, and their values are absolute addresses, not offsets. -TEST_F(Stabs, LeadingLine) { - stabs.set_endianness(kBigEndian); - stabs.set_value_size(4); - stabs - .Stab(N_SO, 179, 27357, 0x8adabc15, "build directory/") - .Stab(N_SO, 52, 53058, 0x4c7e3bf4, "compilation unit") - .Stab(N_SOL, 165, 12086, 0x6a797ca3, "source file name") - .Stab(N_SLINE, 229, 20015, 0x4cb3d7e0, "") - .Stab(N_SLINE, 89, 43802, 0x4cba8b88, "") - .Stab(N_FUN, 251, 51639, 0xce1b98fa, "rutabaga") - .Stab(N_FUN, 218, 16113, 0x5798, "") - .Stab(N_SO, 52, 53058, 0xd4af4415, ""); - - { - InSequence s; - EXPECT_CALL(mock_handler, - StartCompilationUnit(StrEq("compilation unit"), - 0x4c7e3bf4, StrEq("build directory/"))) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - StartFunction(Eq("rutabaga"), 0xce1b98fa)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - Line(0x4cb3d7e0, StrEq("source file name"), 20015)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - Line(0x4cba8b88, StrEq("source file name"), 43802)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndFunction(0xce1b98fa + 0x5798)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, EndCompilationUnit(0xd4af4415)) - .WillOnce(Return(true)); - } - - ASSERT_TRUE(ApplyHandlerToMockStabsData()); -} - - -#if defined(HAVE_MACH_O_NLIST_H) -// These tests have no meaning on non-Mach-O-based systems, as -// only Mach-O uses N_SECT to represent public symbols. -TEST_F(Stabs, OnePublicSymbol) { - stabs.set_endianness(kLittleEndian); - stabs.set_value_size(4); - - const uint32_t kExpectedAddress = 0x9000; - const string kExpectedFunctionName("public_function"); - stabs - .Stab(N_SECT, 1, 0, kExpectedAddress, kExpectedFunctionName); - - { - InSequence s; - EXPECT_CALL(mock_handler, - Extern(StrEq(kExpectedFunctionName), - kExpectedAddress)) - .WillOnce(Return(true)); - } - ASSERT_TRUE(ApplyHandlerToMockStabsData()); -} - -TEST_F(Stabs, TwoPublicSymbols) { - stabs.set_endianness(kLittleEndian); - stabs.set_value_size(4); - - const uint32_t kExpectedAddress1 = 0xB0B0B0B0; - const string kExpectedFunctionName1("public_function"); - const uint32_t kExpectedAddress2 = 0xF0F0F0F0; - const string kExpectedFunctionName2("something else"); - stabs - .Stab(N_SECT, 1, 0, kExpectedAddress1, kExpectedFunctionName1) - .Stab(N_SECT, 1, 0, kExpectedAddress2, kExpectedFunctionName2); - - { - InSequence s; - EXPECT_CALL(mock_handler, - Extern(StrEq(kExpectedFunctionName1), - kExpectedAddress1)) - .WillOnce(Return(true)); - EXPECT_CALL(mock_handler, - Extern(StrEq(kExpectedFunctionName2), - kExpectedAddress2)) - .WillOnce(Return(true)); - } - ASSERT_TRUE(ApplyHandlerToMockStabsData()); -} - -#endif - -} // anonymous namespace diff --git a/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.cc b/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.cc deleted file mode 100644 index 0a83cf21c..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.cc +++ /dev/null @@ -1,197 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dump_stabs.cc --- implement the StabsToModule class. - -#include <assert.h> -#include <cxxabi.h> -#include <stdarg.h> -#include <stdio.h> - -#include <algorithm> - -#include "common/stabs_to_module.h" -#include "common/using_std_string.h" - -namespace google_breakpad { - -// Demangle using abi call. -// Older GCC may not support it. -static string Demangle(const string &mangled) { - int status = 0; - char *demangled = abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status); - if (status == 0 && demangled != NULL) { - string str(demangled); - free(demangled); - return str; - } - return string(mangled); -} - -StabsToModule::~StabsToModule() { - // Free any functions we've accumulated but not added to the module. - for (vector<Module::Function *>::const_iterator func_it = functions_.begin(); - func_it != functions_.end(); func_it++) - delete *func_it; - // Free any function that we're currently within. - delete current_function_; -} - -bool StabsToModule::StartCompilationUnit(const char *name, uint64_t address, - const char *build_directory) { - assert(!in_compilation_unit_); - in_compilation_unit_ = true; - current_source_file_name_ = name; - current_source_file_ = module_->FindFile(name); - comp_unit_base_address_ = address; - boundaries_.push_back(static_cast<Module::Address>(address)); - return true; -} - -bool StabsToModule::EndCompilationUnit(uint64_t address) { - assert(in_compilation_unit_); - in_compilation_unit_ = false; - comp_unit_base_address_ = 0; - current_source_file_ = NULL; - current_source_file_name_ = NULL; - if (address) - boundaries_.push_back(static_cast<Module::Address>(address)); - return true; -} - -bool StabsToModule::StartFunction(const string &name, - uint64_t address) { - assert(!current_function_); - Module::Function *f = new Module::Function(Demangle(name), address); - f->size = 0; // We compute this in StabsToModule::Finalize(). - f->parameter_size = 0; // We don't provide this information. - current_function_ = f; - boundaries_.push_back(static_cast<Module::Address>(address)); - return true; -} - -bool StabsToModule::EndFunction(uint64_t address) { - assert(current_function_); - // Functions in this compilation unit should have address bigger - // than the compilation unit's starting address. There may be a lot - // of duplicated entries for functions in the STABS data. We will - // count on the Module to remove the duplicates. - if (current_function_->address >= comp_unit_base_address_) - functions_.push_back(current_function_); - else - delete current_function_; - current_function_ = NULL; - if (address) - boundaries_.push_back(static_cast<Module::Address>(address)); - return true; -} - -bool StabsToModule::Line(uint64_t address, const char *name, int number) { - assert(current_function_); - assert(current_source_file_); - if (name != current_source_file_name_) { - current_source_file_ = module_->FindFile(name); - current_source_file_name_ = name; - } - Module::Line line; - line.address = address; - line.size = 0; // We compute this in StabsToModule::Finalize(). - line.file = current_source_file_; - line.number = number; - current_function_->lines.push_back(line); - return true; -} - -bool StabsToModule::Extern(const string &name, uint64_t address) { - Module::Extern *ext = new Module::Extern(address); - // Older libstdc++ demangle implementations can crash on unexpected - // input, so be careful about what gets passed in. - if (name.compare(0, 3, "__Z") == 0) { - ext->name = Demangle(name.substr(1)); - } else if (name[0] == '_') { - ext->name = name.substr(1); - } else { - ext->name = name; - } - module_->AddExtern(ext); - return true; -} - -void StabsToModule::Warning(const char *format, ...) { - va_list args; - va_start(args, format); - vfprintf(stderr, format, args); - va_end(args); -} - -void StabsToModule::Finalize() { - // Sort our boundary list, so we can search it quickly. - sort(boundaries_.begin(), boundaries_.end()); - // Sort all functions by address, just for neatness. - sort(functions_.begin(), functions_.end(), - Module::Function::CompareByAddress); - - for (vector<Module::Function *>::const_iterator func_it = functions_.begin(); - func_it != functions_.end(); - func_it++) { - Module::Function *f = *func_it; - // Compute the function f's size. - vector<Module::Address>::const_iterator boundary - = std::upper_bound(boundaries_.begin(), boundaries_.end(), f->address); - if (boundary != boundaries_.end()) - f->size = *boundary - f->address; - else - // If this is the last function in the module, and the STABS - // reader was unable to give us its ending address, then assign - // it a bogus, very large value. This will happen at most once - // per module: since we've added all functions' addresses to the - // boundary table, only one can be the last. - f->size = kFallbackSize; - - // Compute sizes for each of the function f's lines --- if it has any. - if (!f->lines.empty()) { - stable_sort(f->lines.begin(), f->lines.end(), - Module::Line::CompareByAddress); - vector<Module::Line>::iterator last_line = f->lines.end() - 1; - for (vector<Module::Line>::iterator line_it = f->lines.begin(); - line_it != last_line; line_it++) - line_it[0].size = line_it[1].address - line_it[0].address; - // Compute the size of the last line from f's end address. - last_line->size = (f->address + f->size) - last_line->address; - } - } - // Now that everything has a size, add our functions to the module, and - // dispose of our private list. - module_->AddFunctions(functions_.begin(), functions_.end()); - functions_.clear(); -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.h b/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.h deleted file mode 100644 index 5e04fa792..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module.h +++ /dev/null @@ -1,143 +0,0 @@ -// -*- mode: C++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dump_stabs.h: Define the StabsToModule class, which receives -// STABS debugging information from a parser and adds it to a Breakpad -// symbol file. - -#ifndef BREAKPAD_COMMON_STABS_TO_MODULE_H_ -#define BREAKPAD_COMMON_STABS_TO_MODULE_H_ - -#include <stdint.h> - -#include <string> -#include <vector> - -#include "common/module.h" -#include "common/stabs_reader.h" -#include "common/using_std_string.h" - -namespace google_breakpad { - -using std::vector; - -// A StabsToModule is a handler that receives parsed STABS debugging -// information from a StabsReader, and uses that to populate -// a Module. (All classes are in the google_breakpad namespace.) A -// Module represents the contents of a Breakpad symbol file, and knows -// how to write itself out as such. A StabsToModule thus acts as -// the bridge between STABS and Breakpad data. -// When processing Darwin Mach-O files, this also receives public linker -// symbols, like those found in system libraries. -class StabsToModule: public google_breakpad::StabsHandler { - public: - // Receive parsed debugging information from a StabsReader, and - // store it all in MODULE. - StabsToModule(Module *module) : - module_(module), - in_compilation_unit_(false), - comp_unit_base_address_(0), - current_function_(NULL), - current_source_file_(NULL), - current_source_file_name_(NULL) { } - ~StabsToModule(); - - // The standard StabsHandler virtual member functions. - bool StartCompilationUnit(const char *name, uint64_t address, - const char *build_directory); - bool EndCompilationUnit(uint64_t address); - bool StartFunction(const string &name, uint64_t address); - bool EndFunction(uint64_t address); - bool Line(uint64_t address, const char *name, int number); - bool Extern(const string &name, uint64_t address); - void Warning(const char *format, ...); - - // Do any final processing necessary to make module_ contain all the - // data provided by the STABS reader. - // - // Because STABS does not provide reliable size information for - // functions and lines, we need to make a pass over the data after - // processing all the STABS to compute those sizes. We take care of - // that here. - void Finalize(); - - private: - - // An arbitrary, but very large, size to use for functions whose - // size we can't compute properly. - static const uint64_t kFallbackSize = 0x10000000; - - // The module we're contributing debugging info to. - Module *module_; - - // The functions we've generated so far. We don't add these to - // module_ as we parse them. Instead, we wait until we've computed - // their ending address, and their lines' ending addresses. - // - // We could just stick them in module_ from the outset, but if - // module_ already contains data gathered from other debugging - // formats, that would complicate the size computation. - vector<Module::Function *> functions_; - - // Boundary addresses. STABS doesn't necessarily supply sizes for - // functions and lines, so we need to compute them ourselves by - // finding the next object. - vector<Module::Address> boundaries_; - - // True if we are currently within a compilation unit: we have gotten a - // StartCompilationUnit call, but no matching EndCompilationUnit call - // yet. We use this for sanity checks. - bool in_compilation_unit_; - - // The base address of the current compilation unit. We use this to - // recognize functions we should omit from the symbol file. (If you - // know the details of why we omit these, please patch this - // comment.) - Module::Address comp_unit_base_address_; - - // The function we're currently contributing lines to. - Module::Function *current_function_; - - // The last Module::File we got a line number in. - Module::File *current_source_file_; - - // The pointer in the .stabstr section of the name that - // current_source_file_ is built from. This allows us to quickly - // recognize when the current line is in the same file as the - // previous one (which it usually is). - const char *current_source_file_name_; -}; - -} // namespace google_breakpad - -#endif // BREAKPAD_COMMON_STABS_TO_MODULE_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module_unittest.cc deleted file mode 100644 index d445d1d64..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/stabs_to_module_unittest.cc +++ /dev/null @@ -1,258 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// dump_stabs_unittest.cc: Unit tests for StabsToModule. - -#include <vector> - -#include "breakpad_googletest_includes.h" -#include "common/stabs_to_module.h" - -using google_breakpad::Module; -using google_breakpad::StabsToModule; -using std::vector; - -TEST(StabsToModule, SimpleCU) { - Module m("name", "os", "arch", "id"); - StabsToModule h(&m); - - // Feed in a simple compilation unit that defines a function with - // one line. - EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0x9f4d1271e50db93bLL, - "build-directory")); - EXPECT_TRUE(h.StartFunction("function", 0xfde4abbed390c394LL)); - EXPECT_TRUE(h.Line(0xfde4abbed390c394LL, "source-file-name", 174823314)); - EXPECT_TRUE(h.EndFunction(0xfde4abbed390c3a4LL)); - EXPECT_TRUE(h.EndCompilationUnit(0xfee4abbed390c3a4LL)); - h.Finalize(); - - // Now check to see what has been added to the Module. - Module::File *file = m.FindExistingFile("source-file-name"); - ASSERT_TRUE(file != NULL); - - vector<Module::Function *> functions; - m.GetFunctions(&functions, functions.end()); - ASSERT_EQ((size_t) 1, functions.size()); - Module::Function *function = functions[0]; - EXPECT_STREQ("function", function->name.c_str()); - EXPECT_EQ(0xfde4abbed390c394LL, function->address); - EXPECT_EQ(0x10U, function->size); - EXPECT_EQ(0U, function->parameter_size); - ASSERT_EQ((size_t) 1, function->lines.size()); - Module::Line *line = &function->lines[0]; - EXPECT_EQ(0xfde4abbed390c394LL, line->address); - EXPECT_EQ(0x10U, line->size); // derived from EndFunction - EXPECT_TRUE(line->file == file); - EXPECT_EQ(174823314, line->number); -} - -#ifdef __GNUC__ -// Function name mangling can vary by compiler, so only run mangled-name -// tests on GCC for simplicity's sake. -TEST(StabsToModule, Externs) { - Module m("name", "os", "arch", "id"); - StabsToModule h(&m); - - // Feed in a few Extern symbols. - EXPECT_TRUE(h.Extern("_foo", 0xffff)); - EXPECT_TRUE(h.Extern("__Z21dyldGlobalLockAcquirev", 0xaaaa)); - EXPECT_TRUE(h.Extern("_MorphTableGetNextMorphChain", 0x1111)); - h.Finalize(); - - // Now check to see what has been added to the Module. - vector<Module::Extern *> externs; - m.GetExterns(&externs, externs.end()); - ASSERT_EQ((size_t) 3, externs.size()); - Module::Extern *extern1 = externs[0]; - EXPECT_STREQ("MorphTableGetNextMorphChain", extern1->name.c_str()); - EXPECT_EQ((Module::Address)0x1111, extern1->address); - Module::Extern *extern2 = externs[1]; - EXPECT_STREQ("dyldGlobalLockAcquire()", extern2->name.c_str()); - EXPECT_EQ((Module::Address)0xaaaa, extern2->address); - Module::Extern *extern3 = externs[2]; - EXPECT_STREQ("foo", extern3->name.c_str()); - EXPECT_EQ((Module::Address)0xffff, extern3->address); -} -#endif // __GNUC__ - -TEST(StabsToModule, DuplicateFunctionNames) { - Module m("name", "os", "arch", "id"); - StabsToModule h(&m); - - // Compilation unit with one function, mangled name. - EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xf2cfda36ecf7f46cLL, - "build-directory")); - EXPECT_TRUE(h.StartFunction("funcfoo", - 0xf2cfda36ecf7f46dLL)); - EXPECT_TRUE(h.EndFunction(0)); - EXPECT_TRUE(h.StartFunction("funcfoo", - 0xf2cfda36ecf7f46dLL)); - EXPECT_TRUE(h.EndFunction(0)); - EXPECT_TRUE(h.EndCompilationUnit(0)); - - h.Finalize(); - - // Now check to see what has been added to the Module. - Module::File *file = m.FindExistingFile("compilation-unit"); - ASSERT_TRUE(file != NULL); - - vector<Module::Function *> functions; - m.GetFunctions(&functions, functions.end()); - ASSERT_EQ(1U, functions.size()); - - Module::Function *function = functions[0]; - EXPECT_EQ(0xf2cfda36ecf7f46dLL, function->address); - EXPECT_LT(0U, function->size); // should have used dummy size - EXPECT_EQ(0U, function->parameter_size); - ASSERT_EQ(0U, function->lines.size()); -} - -TEST(InferSizes, LineSize) { - Module m("name", "os", "arch", "id"); - StabsToModule h(&m); - - // Feed in a simple compilation unit that defines a function with - // one line. - EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xb4513962eff94e92LL, - "build-directory")); - EXPECT_TRUE(h.StartFunction("function", 0xb4513962eff94e92LL)); - EXPECT_TRUE(h.Line(0xb4513962eff94e92LL, "source-file-name-1", 77396614)); - EXPECT_TRUE(h.Line(0xb4513963eff94e92LL, "source-file-name-2", 87660088)); - EXPECT_TRUE(h.EndFunction(0)); // unknown function end address - EXPECT_TRUE(h.EndCompilationUnit(0)); // unknown CU end address - EXPECT_TRUE(h.StartCompilationUnit("compilation-unit-2", 0xb4523963eff94e92LL, - "build-directory-2")); // next boundary - EXPECT_TRUE(h.EndCompilationUnit(0)); - h.Finalize(); - - // Now check to see what has been added to the Module. - Module::File *file1 = m.FindExistingFile("source-file-name-1"); - ASSERT_TRUE(file1 != NULL); - Module::File *file2 = m.FindExistingFile("source-file-name-2"); - ASSERT_TRUE(file2 != NULL); - - vector<Module::Function *> functions; - m.GetFunctions(&functions, functions.end()); - ASSERT_EQ((size_t) 1, functions.size()); - - Module::Function *function = functions[0]; - EXPECT_STREQ("function", function->name.c_str()); - EXPECT_EQ(0xb4513962eff94e92LL, function->address); - EXPECT_EQ(0x1000100000000ULL, function->size); // inferred from CU end - EXPECT_EQ(0U, function->parameter_size); - ASSERT_EQ((size_t) 2, function->lines.size()); - - Module::Line *line1 = &function->lines[0]; - EXPECT_EQ(0xb4513962eff94e92LL, line1->address); - EXPECT_EQ(0x100000000ULL, line1->size); // derived from EndFunction - EXPECT_TRUE(line1->file == file1); - EXPECT_EQ(77396614, line1->number); - - Module::Line *line2 = &function->lines[1]; - EXPECT_EQ(0xb4513963eff94e92LL, line2->address); - EXPECT_EQ(0x1000000000000ULL, line2->size); // derived from EndFunction - EXPECT_TRUE(line2->file == file2); - EXPECT_EQ(87660088, line2->number); -} - -#ifdef __GNUC__ -// Function name mangling can vary by compiler, so only run mangled-name -// tests on GCC for simplicity's sake. -TEST(FunctionNames, Mangled) { - Module m("name", "os", "arch", "id"); - StabsToModule h(&m); - - // Compilation unit with one function, mangled name. - EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0xf2cfda63cef7f46cLL, - "build-directory")); - EXPECT_TRUE(h.StartFunction("_ZNSt6vectorIySaIyEE9push_backERKy", - 0xf2cfda63cef7f46dLL)); - EXPECT_TRUE(h.EndFunction(0)); - EXPECT_TRUE(h.EndCompilationUnit(0)); - - h.Finalize(); - - // Now check to see what has been added to the Module. - Module::File *file = m.FindExistingFile("compilation-unit"); - ASSERT_TRUE(file != NULL); - - vector<Module::Function *> functions; - m.GetFunctions(&functions, functions.end()); - ASSERT_EQ(1U, functions.size()); - - Module::Function *function = functions[0]; - // This is GCC-specific, but we shouldn't be seeing STABS data anywhere - // but Linux. - EXPECT_STREQ("std::vector<unsigned long long, " - "std::allocator<unsigned long long> >::" - "push_back(unsigned long long const&)", - function->name.c_str()); - EXPECT_EQ(0xf2cfda63cef7f46dLL, function->address); - EXPECT_LT(0U, function->size); // should have used dummy size - EXPECT_EQ(0U, function->parameter_size); - ASSERT_EQ(0U, function->lines.size()); -} -#endif // __GNUC__ - -// The GNU toolchain can omit functions that are not used; however, -// when it does so, it doesn't clean up the debugging information that -// refers to them. In STABS, this results in compilation units whose -// SO addresses are zero. -TEST(Omitted, Function) { - Module m("name", "os", "arch", "id"); - StabsToModule h(&m); - - // The StartCompilationUnit and EndCompilationUnit calls may both have an - // address of zero if the compilation unit has had sections removed. - EXPECT_TRUE(h.StartCompilationUnit("compilation-unit", 0, "build-directory")); - EXPECT_TRUE(h.StartFunction("function", 0x2a133596)); - EXPECT_TRUE(h.EndFunction(0)); - EXPECT_TRUE(h.EndCompilationUnit(0)); -} - -// TODO --- if we actually cared about STABS. Even without these we've -// got full coverage of non-failure source lines in dump_stabs.cc. - -// Line size from next line -// Line size from function end -// Line size from next function start -// line size from cu end -// line size from next cu start -// fallback size is something plausible - -// function size from function end -// function size from next function start -// function size from cu end -// function size from next cu start -// fallback size is something plausible - -// omitting functions outside the compilation unit's address range -// zero-line, one-line, many-line functions diff --git a/toolkit/crashreporter/google-breakpad/src/common/stdio_wrapper.h b/toolkit/crashreporter/google-breakpad/src/common/stdio_wrapper.h deleted file mode 100644 index a3dd50aab..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/stdio_wrapper.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) 2016, 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_STDIO_WRAPPER_H -#define GOOGLE_BREAKPAD_COMMON_STDIO_WRAPPER_H - -#include <stdio.h> - -#if defined(_MSC_VER) && MSC_VER < 1900 -#include <basetsd.h> - -#define snprintf _snprintf -typedef SSIZE_T ssize_t; -#endif - - -#endif // GOOGLE_BREAKPAD_COMMON_STDIO_WRAPPER_H diff --git a/toolkit/crashreporter/google-breakpad/src/common/string_conversion.cc b/toolkit/crashreporter/google-breakpad/src/common/string_conversion.cc deleted file mode 100644 index 9c0d623fc..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/string_conversion.cc +++ /dev/null @@ -1,155 +0,0 @@ -// 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 <string.h> - -#include "common/convert_UTF.h" -#include "common/scoped_ptr.h" -#include "common/string_conversion.h" -#include "common/using_std_string.h" - -namespace google_breakpad { - -using std::vector; - -void UTF8ToUTF16(const char *in, vector<uint16_t> *out) { - size_t source_length = strlen(in); - const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in); - const UTF8 *source_end_ptr = source_ptr + source_length; - // Erase the contents and zero fill to the expected size - out->clear(); - out->insert(out->begin(), source_length, 0); - uint16_t *target_ptr = &(*out)[0]; - uint16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(uint16_t); - ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr, - &target_ptr, target_end_ptr, - strictConversion); - - // Resize to be the size of the # of converted characters + NULL - out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0); -} - -int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]) { - const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in); - const UTF8 *source_end_ptr = source_ptr + sizeof(char); - uint16_t *target_ptr = out; - uint16_t *target_end_ptr = target_ptr + 2 * sizeof(uint16_t); - out[0] = out[1] = 0; - - // Process one character at a time - while (1) { - ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr, - &target_ptr, target_end_ptr, - strictConversion); - - if (result == conversionOK) - return static_cast<int>(source_ptr - reinterpret_cast<const UTF8 *>(in)); - - // Add another character to the input stream and try again - source_ptr = reinterpret_cast<const UTF8 *>(in); - ++source_end_ptr; - - if (source_end_ptr > reinterpret_cast<const UTF8 *>(in) + in_length) - break; - } - - return 0; -} - -void UTF32ToUTF16(const wchar_t *in, vector<uint16_t> *out) { - size_t source_length = wcslen(in); - const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(in); - const UTF32 *source_end_ptr = source_ptr + source_length; - // Erase the contents and zero fill to the expected size - out->clear(); - out->insert(out->begin(), source_length, 0); - uint16_t *target_ptr = &(*out)[0]; - uint16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(uint16_t); - ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr, - &target_ptr, target_end_ptr, - strictConversion); - - // Resize to be the size of the # of converted characters + NULL - out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0); -} - -void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]) { - const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(&in); - const UTF32 *source_end_ptr = source_ptr + 1; - uint16_t *target_ptr = out; - uint16_t *target_end_ptr = target_ptr + 2 * sizeof(uint16_t); - out[0] = out[1] = 0; - ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr, - &target_ptr, target_end_ptr, - strictConversion); - - if (result != conversionOK) { - out[0] = out[1] = 0; - } -} - -static inline uint16_t Swap(uint16_t value) { - return (value >> 8) | static_cast<uint16_t>(value << 8); -} - -string UTF16ToUTF8(const vector<uint16_t> &in, bool swap) { - const UTF16 *source_ptr = &in[0]; - scoped_array<uint16_t> source_buffer; - - // If we're to swap, we need to make a local copy and swap each byte pair - if (swap) { - int idx = 0; - source_buffer.reset(new uint16_t[in.size()]); - UTF16 *source_buffer_ptr = source_buffer.get(); - for (vector<uint16_t>::const_iterator it = in.begin(); - it != in.end(); ++it, ++idx) - source_buffer_ptr[idx] = Swap(*it); - - source_ptr = source_buffer.get(); - } - - // The maximum expansion would be 4x the size of the input string. - const UTF16 *source_end_ptr = source_ptr + in.size(); - size_t target_capacity = in.size() * 4; - scoped_array<UTF8> target_buffer(new UTF8[target_capacity]); - UTF8 *target_ptr = target_buffer.get(); - UTF8 *target_end_ptr = target_ptr + target_capacity; - ConversionResult result = ConvertUTF16toUTF8(&source_ptr, source_end_ptr, - &target_ptr, target_end_ptr, - strictConversion); - - if (result == conversionOK) { - const char *targetPtr = reinterpret_cast<const char *>(target_buffer.get()); - return targetPtr; - } - - return ""; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/string_conversion.h b/toolkit/crashreporter/google-breakpad/src/common/string_conversion.h deleted file mode 100644 index b9ba96a2e..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/string_conversion.h +++ /dev/null @@ -1,68 +0,0 @@ -// 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. - -// string_conversion.h: Conversion between different UTF-8/16/32 encodings. - -#ifndef COMMON_STRING_CONVERSION_H__ -#define COMMON_STRING_CONVERSION_H__ - -#include <string> -#include <vector> - -#include "common/using_std_string.h" -#include "google_breakpad/common/breakpad_types.h" - -namespace google_breakpad { - -using std::vector; - -// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the -// conversion failed, |out| will be zero length. -void UTF8ToUTF16(const char *in, vector<uint16_t> *out); - -// Convert at least one character (up to a maximum of |in_length|) from |in| -// to UTF-16 into |out|. Return the number of characters consumed from |in|. -// Any unused characters in |out| will be initialized to 0. No memory will -// be allocated by this routine. -int UTF8ToUTF16Char(const char *in, int in_length, uint16_t out[2]); - -// Convert |in| to UTF-16 into |out|. Use platform byte ordering. If the -// conversion failed, |out| will be zero length. -void UTF32ToUTF16(const wchar_t *in, vector<uint16_t> *out); - -// Convert |in| to UTF-16 into |out|. Any unused characters in |out| will be -// initialized to 0. No memory will be allocated by this routine. -void UTF32ToUTF16Char(wchar_t in, uint16_t out[2]); - -// Convert |in| to UTF-8. If |swap| is true, swap bytes before converting. -string UTF16ToUTF8(const vector<uint16_t> &in, bool swap); - -} // namespace google_breakpad - -#endif // COMMON_STRING_CONVERSION_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/symbol_data.h b/toolkit/crashreporter/google-breakpad/src/common/symbol_data.h deleted file mode 100644 index 2cf15a855..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/symbol_data.h +++ /dev/null @@ -1,42 +0,0 @@ -// -*- 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. - -#ifndef COMMON_SYMBOL_DATA_H_ -#define COMMON_SYMBOL_DATA_H_ - -// Control what data is used from the symbol file. -enum SymbolData { - ALL_SYMBOL_DATA, - NO_CFI, - ONLY_CFI -}; - -#endif // COMMON_SYMBOL_DATA_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/test_assembler.cc b/toolkit/crashreporter/google-breakpad/src/common/test_assembler.cc deleted file mode 100644 index 1e783b45c..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/test_assembler.cc +++ /dev/null @@ -1,359 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// test_assembler.cc: Implementation of google_breakpad::TestAssembler. -// See test_assembler.h for details. - -#include "common/test_assembler.h" - -#include <assert.h> -#include <stdio.h> - -#include <iterator> - -namespace google_breakpad { -namespace test_assembler { - -using std::back_insert_iterator; - -Label::Label() : value_(new Binding()) { } -Label::Label(uint64_t value) : value_(new Binding(value)) { } -Label::Label(const Label &label) { - value_ = label.value_; - value_->Acquire(); -} -Label::~Label() { - if (value_->Release()) delete value_; -} - -Label &Label::operator=(uint64_t value) { - value_->Set(NULL, value); - return *this; -} - -Label &Label::operator=(const Label &label) { - value_->Set(label.value_, 0); - return *this; -} - -Label Label::operator+(uint64_t addend) const { - Label l; - l.value_->Set(this->value_, addend); - return l; -} - -Label Label::operator-(uint64_t subtrahend) const { - Label l; - l.value_->Set(this->value_, -subtrahend); - return l; -} - -// When NDEBUG is #defined, assert doesn't evaluate its argument. This -// means you can't simply use assert to check the return value of a -// function with necessary side effects. -// -// ALWAYS_EVALUATE_AND_ASSERT(x) evaluates x regardless of whether -// NDEBUG is #defined; when NDEBUG is not #defined, it further asserts -// that x is true. -#ifdef NDEBUG -#define ALWAYS_EVALUATE_AND_ASSERT(x) x -#else -#define ALWAYS_EVALUATE_AND_ASSERT(x) assert(x) -#endif - -uint64_t Label::operator-(const Label &label) const { - uint64_t offset; - ALWAYS_EVALUATE_AND_ASSERT(IsKnownOffsetFrom(label, &offset)); - return offset; -} - -uint64_t Label::Value() const { - uint64_t v = 0; - ALWAYS_EVALUATE_AND_ASSERT(IsKnownConstant(&v)); - return v; -}; - -bool Label::IsKnownConstant(uint64_t *value_p) const { - Binding *base; - uint64_t addend; - value_->Get(&base, &addend); - if (base != NULL) return false; - if (value_p) *value_p = addend; - return true; -} - -bool Label::IsKnownOffsetFrom(const Label &label, uint64_t *offset_p) const -{ - Binding *label_base, *this_base; - uint64_t label_addend, this_addend; - label.value_->Get(&label_base, &label_addend); - value_->Get(&this_base, &this_addend); - // If this and label are related, Get will find their final - // common ancestor, regardless of how indirect the relation is. This - // comparison also handles the constant vs. constant case. - if (this_base != label_base) return false; - if (offset_p) *offset_p = this_addend - label_addend; - return true; -} - -Label::Binding::Binding() : base_(this), addend_(), reference_count_(1) { } - -Label::Binding::Binding(uint64_t addend) - : base_(NULL), addend_(addend), reference_count_(1) { } - -Label::Binding::~Binding() { - assert(reference_count_ == 0); - if (base_ && base_ != this && base_->Release()) - delete base_; -} - -void Label::Binding::Set(Binding *binding, uint64_t addend) { - if (!base_ && !binding) { - // We're equating two constants. This could be okay. - assert(addend_ == addend); - } else if (!base_) { - // We are a known constant, but BINDING may not be, so turn the - // tables and try to set BINDING's value instead. - binding->Set(NULL, addend_ - addend); - } else { - if (binding) { - // Find binding's final value. Since the final value is always either - // completely unconstrained or a constant, never a reference to - // another variable (otherwise, it wouldn't be final), this - // guarantees we won't create cycles here, even for code like this: - // l = m, m = n, n = l; - uint64_t binding_addend; - binding->Get(&binding, &binding_addend); - addend += binding_addend; - } - - // It seems likely that setting a binding to itself is a bug - // (although I can imagine this might turn out to be helpful to - // permit). - assert(binding != this); - - if (base_ != this) { - // Set the other bindings on our chain as well. Note that this - // is sufficient even though binding relationships form trees: - // All binding operations traverse their chains to the end, and - // all bindings related to us share some tail of our chain, so - // they will see the changes we make here. - base_->Set(binding, addend - addend_); - // We're not going to use base_ any more. - if (base_->Release()) delete base_; - } - - // Adopt BINDING as our base. Note that it should be correct to - // acquire here, after the release above, even though the usual - // reference-counting rules call for acquiring first, and then - // releasing: the self-reference assertion above should have - // complained if BINDING were 'this' or anywhere along our chain, - // so we didn't release BINDING. - if (binding) binding->Acquire(); - base_ = binding; - addend_ = addend; - } -} - -void Label::Binding::Get(Binding **base, uint64_t *addend) { - if (base_ && base_ != this) { - // Recurse to find the end of our reference chain (the root of our - // tree), and then rewrite every binding along the chain to refer - // to it directly, adjusting addends appropriately. (This is why - // this member function isn't this-const.) - Binding *final_base; - uint64_t final_addend; - base_->Get(&final_base, &final_addend); - if (final_base) final_base->Acquire(); - if (base_->Release()) delete base_; - base_ = final_base; - addend_ += final_addend; - } - *base = base_; - *addend = addend_; -} - -template<typename Inserter> -static inline void InsertEndian(test_assembler::Endianness endianness, - size_t size, uint64_t number, Inserter dest) { - assert(size > 0); - if (endianness == kLittleEndian) { - for (size_t i = 0; i < size; i++) { - *dest++ = (char) (number & 0xff); - number >>= 8; - } - } else { - assert(endianness == kBigEndian); - // The loop condition is odd, but it's correct for size_t. - for (size_t i = size - 1; i < size; i--) - *dest++ = (char) ((number >> (i * 8)) & 0xff); - } -} - -Section &Section::Append(Endianness endianness, size_t size, uint64_t number) { - InsertEndian(endianness, size, number, - back_insert_iterator<string>(contents_)); - return *this; -} - -Section &Section::Append(Endianness endianness, size_t size, - const Label &label) { - // If this label's value is known, there's no reason to waste an - // entry in references_ on it. - uint64_t value; - if (label.IsKnownConstant(&value)) - return Append(endianness, size, value); - - // This will get caught when the references are resolved, but it's - // nicer to find out earlier. - assert(endianness != kUnsetEndian); - - references_.push_back(Reference(contents_.size(), endianness, size, label)); - contents_.append(size, 0); - return *this; -} - -#define ENDIANNESS_L kLittleEndian -#define ENDIANNESS_B kBigEndian -#define ENDIANNESS(e) ENDIANNESS_ ## e - -#define DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ - Section &Section::e ## bits(uint ## bits ## _t v) { \ - InsertEndian(ENDIANNESS(e), bits / 8, v, \ - back_insert_iterator<string>(contents_)); \ - return *this; \ - } - -#define DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) \ - Section &Section::e ## bits(const Label &v) { \ - return Append(ENDIANNESS(e), bits / 8, v); \ - } - -// Define L16, B32, and friends. -#define DEFINE_SHORT_APPEND_ENDIAN(e, bits) \ - DEFINE_SHORT_APPEND_NUMBER_ENDIAN(e, bits) \ - DEFINE_SHORT_APPEND_LABEL_ENDIAN(e, bits) - -DEFINE_SHORT_APPEND_LABEL_ENDIAN(L, 8); -DEFINE_SHORT_APPEND_LABEL_ENDIAN(B, 8); -DEFINE_SHORT_APPEND_ENDIAN(L, 16); -DEFINE_SHORT_APPEND_ENDIAN(L, 32); -DEFINE_SHORT_APPEND_ENDIAN(L, 64); -DEFINE_SHORT_APPEND_ENDIAN(B, 16); -DEFINE_SHORT_APPEND_ENDIAN(B, 32); -DEFINE_SHORT_APPEND_ENDIAN(B, 64); - -#define DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ - Section &Section::D ## bits(uint ## bits ## _t v) { \ - InsertEndian(endianness_, bits / 8, v, \ - back_insert_iterator<string>(contents_)); \ - return *this; \ - } -#define DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) \ - Section &Section::D ## bits(const Label &v) { \ - return Append(endianness_, bits / 8, v); \ - } -#define DEFINE_SHORT_APPEND_DEFAULT(bits) \ - DEFINE_SHORT_APPEND_NUMBER_DEFAULT(bits) \ - DEFINE_SHORT_APPEND_LABEL_DEFAULT(bits) - -DEFINE_SHORT_APPEND_LABEL_DEFAULT(8) -DEFINE_SHORT_APPEND_DEFAULT(16); -DEFINE_SHORT_APPEND_DEFAULT(32); -DEFINE_SHORT_APPEND_DEFAULT(64); - -Section &Section::Append(const Section §ion) { - size_t base = contents_.size(); - contents_.append(section.contents_); - for (vector<Reference>::const_iterator it = section.references_.begin(); - it != section.references_.end(); it++) - references_.push_back(Reference(base + it->offset, it->endianness, - it->size, it->label)); - return *this; -} - -Section &Section::LEB128(long long value) { - while (value < -0x40 || 0x3f < value) { - contents_ += (value & 0x7f) | 0x80; - if (value < 0) - value = (value >> 7) | ~(((unsigned long long) -1) >> 7); - else - value = (value >> 7); - } - contents_ += value & 0x7f; - return *this; -} - -Section &Section::ULEB128(uint64_t value) { - while (value > 0x7f) { - contents_ += (value & 0x7f) | 0x80; - value = (value >> 7); - } - contents_ += value; - return *this; -} - -Section &Section::Align(size_t alignment, uint8_t pad_byte) { - // ALIGNMENT must be a power of two. - assert(((alignment - 1) & alignment) == 0); - size_t new_size = (contents_.size() + alignment - 1) & ~(alignment - 1); - contents_.append(new_size - contents_.size(), pad_byte); - assert((contents_.size() & (alignment - 1)) == 0); - return *this; -} - -void Section::Clear() { - contents_.clear(); - references_.clear(); -} - -bool Section::GetContents(string *contents) { - // For each label reference, find the label's value, and patch it into - // the section's contents. - for (size_t i = 0; i < references_.size(); i++) { - Reference &r = references_[i]; - uint64_t value; - if (!r.label.IsKnownConstant(&value)) { - fprintf(stderr, "Undefined label #%zu at offset 0x%zx\n", i, r.offset); - return false; - } - assert(r.offset < contents_.size()); - assert(contents_.size() - r.offset >= r.size); - InsertEndian(r.endianness, r.size, value, contents_.begin() + r.offset); - } - contents->clear(); - std::swap(contents_, *contents); - references_.clear(); - return true; -} - -} // namespace test_assembler -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/test_assembler.h b/toolkit/crashreporter/google-breakpad/src/common/test_assembler.h deleted file mode 100644 index 373dbebac..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/test_assembler.h +++ /dev/null @@ -1,484 +0,0 @@ -// -*- mode: C++ -*- - -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// test-assembler.h: interface to class for building complex binary streams. - -// To test the Breakpad symbol dumper and processor thoroughly, for -// all combinations of host system and minidump processor -// architecture, we need to be able to easily generate complex test -// data like debugging information and minidump files. -// -// For example, if we want our unit tests to provide full code -// coverage for stack walking, it may be difficult to persuade the -// compiler to generate every possible sort of stack walking -// information that we want to support; there are probably DWARF CFI -// opcodes that GCC never emits. Similarly, if we want to test our -// error handling, we will need to generate damaged minidumps or -// debugging information that (we hope) the client or compiler will -// never produce on its own. -// -// google_breakpad::TestAssembler provides a predictable and -// (relatively) simple way to generate complex formatted data streams -// like minidumps and CFI. Furthermore, because TestAssembler is -// portable, developers without access to (say) Visual Studio or a -// SPARC assembler can still work on test data for those targets. - -#ifndef PROCESSOR_TEST_ASSEMBLER_H_ -#define PROCESSOR_TEST_ASSEMBLER_H_ - -#include <list> -#include <vector> -#include <string> - -#include "common/using_std_string.h" -#include "google_breakpad/common/breakpad_types.h" - -namespace google_breakpad { - -using std::list; -using std::vector; - -namespace test_assembler { - -// A Label represents a value not yet known that we need to store in a -// section. As long as all the labels a section refers to are defined -// by the time we retrieve its contents as bytes, we can use undefined -// labels freely in that section's construction. -// -// A label can be in one of three states: -// - undefined, -// - defined as the sum of some other label and a constant, or -// - a constant. -// -// A label's value never changes, but it can accumulate constraints. -// Adding labels and integers is permitted, and yields a label. -// Subtracting a constant from a label is permitted, and also yields a -// label. Subtracting two labels that have some relationship to each -// other is permitted, and yields a constant. -// -// For example: -// -// Label a; // a's value is undefined -// Label b; // b's value is undefined -// { -// Label c = a + 4; // okay, even though a's value is unknown -// b = c + 4; // also okay; b is now a+8 -// } -// Label d = b - 2; // okay; d == a+6, even though c is gone -// d.Value(); // error: d's value is not yet known -// d - a; // is 6, even though their values are not known -// a = 12; // now b == 20, and d == 18 -// d.Value(); // 18: no longer an error -// b.Value(); // 20 -// d = 10; // error: d is already defined. -// -// Label objects' lifetimes are unconstrained: notice that, in the -// above example, even though a and b are only related through c, and -// c goes out of scope, the assignment to a sets b's value as well. In -// particular, it's not necessary to ensure that a Label lives beyond -// Sections that refer to it. -class Label { - public: - Label(); // An undefined label. - Label(uint64_t value); // A label with a fixed value - Label(const Label &value); // A label equal to another. - ~Label(); - - // Return this label's value; it must be known. - // - // Providing this as a cast operator is nifty, but the conversions - // happen in unexpected places. In particular, ISO C++ says that - // Label + size_t becomes ambigious, because it can't decide whether - // to convert the Label to a uint64_t and then to a size_t, or use - // the overloaded operator that returns a new label, even though the - // former could fail if the label is not yet defined and the latter won't. - uint64_t Value() const; - - Label &operator=(uint64_t value); - Label &operator=(const Label &value); - Label operator+(uint64_t addend) const; - Label operator-(uint64_t subtrahend) const; - uint64_t operator-(const Label &subtrahend) const; - - // We could also provide == and != that work on undefined, but - // related, labels. - - // Return true if this label's value is known. If VALUE_P is given, - // set *VALUE_P to the known value if returning true. - bool IsKnownConstant(uint64_t *value_p = NULL) const; - - // Return true if the offset from LABEL to this label is known. If - // OFFSET_P is given, set *OFFSET_P to the offset when returning true. - // - // You can think of l.KnownOffsetFrom(m, &d) as being like 'd = l-m', - // except that it also returns a value indicating whether the - // subtraction is possible given what we currently know of l and m. - // It can be possible even if we don't know l and m's values. For - // example: - // - // Label l, m; - // m = l + 10; - // l.IsKnownConstant(); // false - // m.IsKnownConstant(); // false - // uint64_t d; - // l.IsKnownOffsetFrom(m, &d); // true, and sets d to -10. - // l-m // -10 - // m-l // 10 - // m.Value() // error: m's value is not known - bool IsKnownOffsetFrom(const Label &label, uint64_t *offset_p = NULL) const; - - private: - // A label's value, or if that is not yet known, how the value is - // related to other labels' values. A binding may be: - // - a known constant, - // - constrained to be equal to some other binding plus a constant, or - // - unconstrained, and free to take on any value. - // - // Many labels may point to a single binding, and each binding may - // refer to another, so bindings and labels form trees whose leaves - // are labels, whose interior nodes (and roots) are bindings, and - // where links point from children to parents. Bindings are - // reference counted, allowing labels to be lightweight, copyable, - // assignable, placed in containers, and so on. - class Binding { - public: - Binding(); - Binding(uint64_t addend); - ~Binding(); - - // Increment our reference count. - void Acquire() { reference_count_++; }; - // Decrement our reference count, and return true if it is zero. - bool Release() { return --reference_count_ == 0; } - - // Set this binding to be equal to BINDING + ADDEND. If BINDING is - // NULL, then set this binding to the known constant ADDEND. - // Update every binding on this binding's chain to point directly - // to BINDING, or to be a constant, with addends adjusted - // appropriately. - void Set(Binding *binding, uint64_t value); - - // Return what we know about the value of this binding. - // - If this binding's value is a known constant, set BASE to - // NULL, and set ADDEND to its value. - // - If this binding is not a known constant but related to other - // bindings, set BASE to the binding at the end of the relation - // chain (which will always be unconstrained), and set ADDEND to the - // value to add to that binding's value to get this binding's - // value. - // - If this binding is unconstrained, set BASE to this, and leave - // ADDEND unchanged. - void Get(Binding **base, uint64_t *addend); - - private: - // There are three cases: - // - // - A binding representing a known constant value has base_ NULL, - // and addend_ equal to the value. - // - // - A binding representing a completely unconstrained value has - // base_ pointing to this; addend_ is unused. - // - // - A binding whose value is related to some other binding's - // value has base_ pointing to that other binding, and addend_ - // set to the amount to add to that binding's value to get this - // binding's value. We only represent relationships of the form - // x = y+c. - // - // Thus, the bind_ links form a chain terminating in either a - // known constant value or a completely unconstrained value. Most - // operations on bindings do path compression: they change every - // binding on the chain to point directly to the final value, - // adjusting addends as appropriate. - Binding *base_; - uint64_t addend_; - - // The number of Labels and Bindings pointing to this binding. - // (When a binding points to itself, indicating a completely - // unconstrained binding, that doesn't count as a reference.) - int reference_count_; - }; - - // This label's value. - Binding *value_; -}; - -inline Label operator+(uint64_t a, const Label &l) { return l + a; } -// Note that int-Label isn't defined, as negating a Label is not an -// operation we support. - -// Conventions for representing larger numbers as sequences of bytes. -enum Endianness { - kBigEndian, // Big-endian: the most significant byte comes first. - kLittleEndian, // Little-endian: the least significant byte comes first. - kUnsetEndian, // used internally -}; - -// A section is a sequence of bytes, constructed by appending bytes -// to the end. Sections have a convenient and flexible set of member -// functions for appending data in various formats: big-endian and -// little-endian signed and unsigned values of different sizes; -// LEB128 and ULEB128 values (see below), and raw blocks of bytes. -// -// If you need to append a value to a section that is not convenient -// to compute immediately, you can create a label, append the -// label's value to the section, and then set the label's value -// later, when it's convenient to do so. Once a label's value is -// known, the section class takes care of updating all previously -// appended references to it. -// -// Once all the labels to which a section refers have had their -// values determined, you can get a copy of the section's contents -// as a string. -// -// Note that there is no specified "start of section" label. This is -// because there are typically several different meanings for "the -// start of a section": the offset of the section within an object -// file, the address in memory at which the section's content appear, -// and so on. It's up to the code that uses the Section class to -// keep track of these explicitly, as they depend on the application. -class Section { - public: - Section(Endianness endianness = kUnsetEndian) - : endianness_(endianness) { }; - - // A base class destructor should be either public and virtual, - // or protected and nonvirtual. - virtual ~Section() { }; - - // Set the default endianness of this section to ENDIANNESS. This - // sets the behavior of the D<N> appending functions. If the - // assembler's default endianness was set, this is the - void set_endianness(Endianness endianness) { - endianness_ = endianness; - } - - // Return the default endianness of this section. - Endianness endianness() const { return endianness_; } - - // Append the SIZE bytes at DATA or the contents of STRING to the - // end of this section. Return a reference to this section. - Section &Append(const uint8_t *data, size_t size) { - contents_.append(reinterpret_cast<const char *>(data), size); - return *this; - }; - Section &Append(const string &data) { - contents_.append(data); - return *this; - }; - - // Append SIZE copies of BYTE to the end of this section. Return a - // reference to this section. - Section &Append(size_t size, uint8_t byte) { - contents_.append(size, (char) byte); - return *this; - } - - // Append NUMBER to this section. ENDIANNESS is the endianness to - // use to write the number. SIZE is the length of the number in - // bytes. Return a reference to this section. - Section &Append(Endianness endianness, size_t size, uint64_t number); - Section &Append(Endianness endianness, size_t size, const Label &label); - - // Append SECTION to the end of this section. The labels SECTION - // refers to need not be defined yet. - // - // Note that this has no effect on any Labels' values, or on - // SECTION. If placing SECTION within 'this' provides new - // constraints on existing labels' values, then it's up to the - // caller to fiddle with those labels as needed. - Section &Append(const Section §ion); - - // Append the contents of DATA as a series of bytes terminated by - // a NULL character. - Section &AppendCString(const string &data) { - Append(data); - contents_ += '\0'; - return *this; - } - - // Append at most SIZE bytes from DATA; if DATA is less than SIZE bytes - // long, pad with '\0' characters. - Section &AppendCString(const string &data, size_t size) { - contents_.append(data, 0, size); - if (data.size() < size) - Append(size - data.size(), 0); - return *this; - } - - // Append VALUE or LABEL to this section, with the given bit width and - // endianness. Return a reference to this section. - // - // The names of these functions have the form <ENDIANNESS><BITWIDTH>: - // <ENDIANNESS> is either 'L' (little-endian, least significant byte first), - // 'B' (big-endian, most significant byte first), or - // 'D' (default, the section's default endianness) - // <BITWIDTH> is 8, 16, 32, or 64. - // - // Since endianness doesn't matter for a single byte, all the - // <BITWIDTH>=8 functions are equivalent. - // - // These can be used to write both signed and unsigned values, as - // the compiler will properly sign-extend a signed value before - // passing it to the function, at which point the function's - // behavior is the same either way. - Section &L8(uint8_t value) { contents_ += value; return *this; } - Section &B8(uint8_t value) { contents_ += value; return *this; } - Section &D8(uint8_t value) { contents_ += value; return *this; } - Section &L16(uint16_t), &L32(uint32_t), &L64(uint64_t), - &B16(uint16_t), &B32(uint32_t), &B64(uint64_t), - &D16(uint16_t), &D32(uint32_t), &D64(uint64_t); - Section &L8(const Label &label), &L16(const Label &label), - &L32(const Label &label), &L64(const Label &label), - &B8(const Label &label), &B16(const Label &label), - &B32(const Label &label), &B64(const Label &label), - &D8(const Label &label), &D16(const Label &label), - &D32(const Label &label), &D64(const Label &label); - - // Append VALUE in a signed LEB128 (Little-Endian Base 128) form. - // - // The signed LEB128 representation of an integer N is a variable - // number of bytes: - // - // - If N is between -0x40 and 0x3f, then its signed LEB128 - // representation is a single byte whose value is N. - // - // - Otherwise, its signed LEB128 representation is (N & 0x7f) | - // 0x80, followed by the signed LEB128 representation of N / 128, - // rounded towards negative infinity. - // - // In other words, we break VALUE into groups of seven bits, put - // them in little-endian order, and then write them as eight-bit - // bytes with the high bit on all but the last. - // - // Note that VALUE cannot be a Label (we would have to implement - // relaxation). - Section &LEB128(long long value); - - // Append VALUE in unsigned LEB128 (Little-Endian Base 128) form. - // - // The unsigned LEB128 representation of an integer N is a variable - // number of bytes: - // - // - If N is between 0 and 0x7f, then its unsigned LEB128 - // representation is a single byte whose value is N. - // - // - Otherwise, its unsigned LEB128 representation is (N & 0x7f) | - // 0x80, followed by the unsigned LEB128 representation of N / - // 128, rounded towards negative infinity. - // - // Note that VALUE cannot be a Label (we would have to implement - // relaxation). - Section &ULEB128(uint64_t value); - - // Jump to the next location aligned on an ALIGNMENT-byte boundary, - // relative to the start of the section. Fill the gap with PAD_BYTE. - // ALIGNMENT must be a power of two. Return a reference to this - // section. - Section &Align(size_t alignment, uint8_t pad_byte = 0); - - // Clear the contents of this section. - void Clear(); - - // Return the current size of the section. - size_t Size() const { return contents_.size(); } - - // Return a label representing the start of the section. - // - // It is up to the user whether this label represents the section's - // position in an object file, the section's address in memory, or - // what have you; some applications may need both, in which case - // this simple-minded interface won't be enough. This class only - // provides a single start label, for use with the Here and Mark - // member functions. - // - // Ideally, we'd provide this in a subclass that actually knows more - // about the application at hand and can provide an appropriate - // collection of start labels. But then the appending member - // functions like Append and D32 would return a reference to the - // base class, not the derived class, and the chaining won't work. - // Since the only value here is in pretty notation, that's a fatal - // flaw. - Label start() const { return start_; } - - // Return a label representing the point at which the next Appended - // item will appear in the section, relative to start(). - Label Here() const { return start_ + Size(); } - - // Set *LABEL to Here, and return a reference to this section. - Section &Mark(Label *label) { *label = Here(); return *this; } - - // If there are no undefined label references left in this - // section, set CONTENTS to the contents of this section, as a - // string, and clear this section. Return true on success, or false - // if there were still undefined labels. - bool GetContents(string *contents); - - private: - // Used internally. A reference to a label's value. - struct Reference { - Reference(size_t set_offset, Endianness set_endianness, size_t set_size, - const Label &set_label) - : offset(set_offset), endianness(set_endianness), size(set_size), - label(set_label) { } - - // The offset of the reference within the section. - size_t offset; - - // The endianness of the reference. - Endianness endianness; - - // The size of the reference. - size_t size; - - // The label to which this is a reference. - Label label; - }; - - // The default endianness of this section. - Endianness endianness_; - - // The contents of the section. - string contents_; - - // References to labels within those contents. - vector<Reference> references_; - - // A label referring to the beginning of the section. - Label start_; -}; - -} // namespace test_assembler -} // namespace google_breakpad - -#endif // PROCESSOR_TEST_ASSEMBLER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/test_assembler_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/test_assembler_unittest.cc deleted file mode 100644 index 94b5a5ce5..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/test_assembler_unittest.cc +++ /dev/null @@ -1,1662 +0,0 @@ -// 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. - -// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> - -// test_assembler_unittest.cc: Unit tests for google_breakpad::TestAssembler. - -#include <string> -#include <string.h> - -#include "breakpad_googletest_includes.h" -#include "common/test_assembler.h" -#include "common/using_std_string.h" - -using google_breakpad::test_assembler::Label; -using google_breakpad::test_assembler::Section; -using google_breakpad::test_assembler::kBigEndian; -using google_breakpad::test_assembler::kLittleEndian; -using testing::Test; - -TEST(ConstructLabel, Simple) { - Label l; -} - -TEST(ConstructLabel, Undefined) { - Label l; - EXPECT_FALSE(l.IsKnownConstant()); -} - -TEST(ConstructLabelDeathTest, Undefined) { - Label l; - ASSERT_DEATH(l.Value(), "IsKnownConstant\\(&v\\)"); -} - -TEST(ConstructLabel, Constant) { - Label l(0x060b9f974eaf301eULL); - uint64_t v; - EXPECT_TRUE(l.IsKnownConstant(&v)); - EXPECT_EQ(v, 0x060b9f974eaf301eULL); - EXPECT_EQ(l.Value(), 0x060b9f974eaf301eULL); -} - -TEST(ConstructLabel, Copy) { - Label l; - Label m(l); - uint64_t v; - EXPECT_TRUE(l.IsKnownOffsetFrom(m, &v)); - EXPECT_EQ(0U, v); -} - -// The left-hand-side of a label assignment can be either -// unconstrained, related, or known. The right-hand-side can be any of -// those, or an integer. -TEST(Assignment, UnconstrainedToUnconstrained) { - Label l, m; - l = m; - EXPECT_EQ(0U, l-m); - EXPECT_TRUE(l.IsKnownOffsetFrom(m)); - uint64_t d; - EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d)); - EXPECT_EQ(0U, d); - EXPECT_FALSE(l.IsKnownConstant()); -} - -TEST(Assignment, UnconstrainedToRelated) { - Label l, m, n; - l = n; - l = m; - EXPECT_EQ(0U, l-m); - EXPECT_TRUE(l.IsKnownOffsetFrom(m)); - uint64_t d; - EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d)); - EXPECT_EQ(0U, d); - EXPECT_FALSE(l.IsKnownConstant()); -} - -TEST(Assignment, UnconstrainedToKnown) { - Label l, m; - l = 0x8fd16e55b20a39c1ULL; - l = m; - EXPECT_EQ(0U, l-m); - EXPECT_TRUE(l.IsKnownOffsetFrom(m)); - uint64_t d; - EXPECT_TRUE(l.IsKnownOffsetFrom(m, &d)); - EXPECT_EQ(0U, d); - EXPECT_TRUE(m.IsKnownConstant()); - EXPECT_EQ(0x8fd16e55b20a39c1ULL, m.Value()); -} - -TEST(Assignment, RelatedToUnconstrained) { - Label l, m, n; - m = n; - l = m; - EXPECT_EQ(0U, l-n); - EXPECT_TRUE(l.IsKnownOffsetFrom(n)); - uint64_t d; - EXPECT_TRUE(l.IsKnownOffsetFrom(n, &d)); - EXPECT_EQ(0U, d); - EXPECT_FALSE(l.IsKnownConstant()); -} - -TEST(Assignment, RelatedToRelated) { - Label l, m, n, o; - l = n; - m = o; - l = m; - EXPECT_EQ(0U, n-o); - EXPECT_TRUE(n.IsKnownOffsetFrom(o)); - uint64_t d; - EXPECT_TRUE(n.IsKnownOffsetFrom(o, &d)); - EXPECT_EQ(0U, d); - EXPECT_FALSE(l.IsKnownConstant()); -} - -TEST(Assignment, RelatedToKnown) { - Label l, m, n; - m = n; - l = 0xd2011f8c82ad56f2ULL; - l = m; - EXPECT_TRUE(l.IsKnownConstant()); - EXPECT_EQ(0xd2011f8c82ad56f2ULL, l.Value()); - EXPECT_TRUE(m.IsKnownConstant()); - EXPECT_EQ(0xd2011f8c82ad56f2ULL, m.Value()); - EXPECT_TRUE(n.IsKnownConstant()); - EXPECT_EQ(0xd2011f8c82ad56f2ULL, n.Value()); -} - -TEST(Assignment, KnownToUnconstrained) { - Label l, m; - m = 0x50b024c0d6073887ULL; - l = m; - EXPECT_TRUE(l.IsKnownConstant()); - EXPECT_EQ(0x50b024c0d6073887ULL, l.Value()); - EXPECT_TRUE(m.IsKnownConstant()); - EXPECT_EQ(0x50b024c0d6073887ULL, m.Value()); -} - -TEST(Assignment, KnownToRelated) { - Label l, m, n; - l = n; - m = 0x5348883655c727e5ULL; - l = m; - EXPECT_TRUE(l.IsKnownConstant()); - EXPECT_EQ(0x5348883655c727e5ULL, l.Value()); - EXPECT_TRUE(m.IsKnownConstant()); - EXPECT_EQ(0x5348883655c727e5ULL, m.Value()); - EXPECT_TRUE(n.IsKnownConstant()); - EXPECT_EQ(0x5348883655c727e5ULL, n.Value()); -} - -TEST(Assignment, KnownToKnown) { - Label l, m; - l = 0x36c209c20987564eULL; - m = 0x36c209c20987564eULL; - l = m; - EXPECT_TRUE(l.IsKnownConstant()); - EXPECT_EQ(0x36c209c20987564eULL, l.Value()); - EXPECT_TRUE(m.IsKnownConstant()); - EXPECT_EQ(0x36c209c20987564eULL, m.Value()); -} - -TEST(Assignment, ConstantToUnconstrained) { - Label l; - l = 0xc02495f4d7f5a957ULL; - EXPECT_TRUE(l.IsKnownConstant()); - EXPECT_EQ(0xc02495f4d7f5a957ULL, l.Value()); -} - -TEST(Assignment, ConstantToRelated) { - Label l, m; - l = m; - l = 0x4577901cf275488dULL; - EXPECT_TRUE(l.IsKnownConstant()); - EXPECT_EQ(0x4577901cf275488dULL, l.Value()); - EXPECT_TRUE(m.IsKnownConstant()); - EXPECT_EQ(0x4577901cf275488dULL, m.Value()); -} - -TEST(Assignment, ConstantToKnown) { - Label l; - l = 0xec0b9c369b7e8ea7ULL; - l = 0xec0b9c369b7e8ea7ULL; - EXPECT_TRUE(l.IsKnownConstant()); - EXPECT_EQ(0xec0b9c369b7e8ea7ULL, l.Value()); -} - -TEST(AssignmentDeathTest, Self) { - Label l; - ASSERT_DEATH(l = l, "binding != this"); -} - -TEST(AssignmentDeathTest, IndirectCycle) { - Label l, m, n; - l = m; - m = n; - ASSERT_DEATH(n = l, "binding != this"); -} - -TEST(AssignmentDeathTest, Cycle) { - Label l, m, n, o; - l = m; - m = n; - o = n; - ASSERT_DEATH(o = l, "binding != this"); -} - -TEST(Addition, LabelConstant) { - Label l, m; - m = l + 0x5248d93e8bbe9497ULL; - EXPECT_TRUE(m.IsKnownOffsetFrom(l)); - uint64_t d; - EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); - EXPECT_EQ(0x5248d93e8bbe9497ULL, d); - EXPECT_FALSE(m.IsKnownConstant()); -} - -TEST(Addition, ConstantLabel) { - Label l, m; - m = 0xf51e94e00d6e3c84ULL + l; - EXPECT_TRUE(m.IsKnownOffsetFrom(l)); - uint64_t d; - EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); - EXPECT_EQ(0xf51e94e00d6e3c84ULL, d); - EXPECT_FALSE(m.IsKnownConstant()); -} - -TEST(Addition, KnownLabelConstant) { - Label l, m; - l = 0x16286307042ce0d8ULL; - m = l + 0x3fdddd91306719d7ULL; - EXPECT_TRUE(m.IsKnownOffsetFrom(l)); - uint64_t d; - EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); - EXPECT_EQ(0x3fdddd91306719d7ULL, d); - EXPECT_TRUE(m.IsKnownConstant()); - EXPECT_EQ(0x16286307042ce0d8ULL + 0x3fdddd91306719d7ULL, m.Value()); -} - -TEST(Addition, ConstantKnownLabel) { - Label l, m; - l = 0x50f62d0cdd1031deULL; - m = 0x1b13462d8577c538ULL + l; - EXPECT_TRUE(m.IsKnownOffsetFrom(l)); - uint64_t d; - EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); - EXPECT_EQ(0x1b13462d8577c538ULL, d); - EXPECT_TRUE(m.IsKnownConstant()); - EXPECT_EQ(0x50f62d0cdd1031deULL + 0x1b13462d8577c538ULL, m.Value()); -} - -TEST(Subtraction, LabelConstant) { - Label l, m; - m = l - 0x0620884d21d3138eULL; - EXPECT_TRUE(m.IsKnownOffsetFrom(l)); - uint64_t d; - EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); - EXPECT_EQ(-0x0620884d21d3138eULL, d); - EXPECT_FALSE(m.IsKnownConstant()); -} - -TEST(Subtraction, KnownLabelConstant) { - Label l, m; - l = 0x6237fbaf9ef7929eULL; - m = l - 0x317730995d2ab6eeULL; - EXPECT_TRUE(m.IsKnownOffsetFrom(l)); - uint64_t d; - EXPECT_TRUE(m.IsKnownOffsetFrom(l, &d)); - EXPECT_EQ(-0x317730995d2ab6eeULL, d); - EXPECT_TRUE(m.IsKnownConstant()); - EXPECT_EQ(0x6237fbaf9ef7929eULL - 0x317730995d2ab6eeULL, m.Value()); -} - -TEST(SubtractionDeathTest, LabelLabel) { - Label l, m; - ASSERT_DEATH(l - m, "IsKnownOffsetFrom\\(label, &offset\\)"); -} - -TEST(Subtraction, LabelLabel) { - Label l, m; - l = m + 0x7fa77ec63e28a17aULL; - EXPECT_EQ(0x7fa77ec63e28a17aULL, l - m); - EXPECT_EQ(-0x7fa77ec63e28a17aULL, m - l); -} - -TEST(IsKnownConstant, Undefined) { - Label l; - EXPECT_FALSE(l.IsKnownConstant()); -} - -TEST(IsKnownConstant, RelatedLabel) { - Label l, m; - l = m; - EXPECT_FALSE(l.IsKnownConstant()); - EXPECT_FALSE(m.IsKnownConstant()); -} - -TEST(IsKnownConstant, Constant) { - Label l; - l = 0xf374b1bdd6a22576ULL; - EXPECT_TRUE(l.IsKnownConstant()); -} - -TEST(IsKnownOffsetFrom, Unrelated) { - Label l, m; - EXPECT_FALSE(l.IsKnownOffsetFrom(m)); -} - -TEST(IsKnownOffsetFrom, Related) { - Label l, m; - l = m; - EXPECT_TRUE(l.IsKnownOffsetFrom(m)); -} - -// Test the construction of chains of related labels, and the -// propagation of values through them. -// -// Although the relations between labels are supposed to behave -// symmetrically --- that is, 'a = b' should put a and b in -// indistinguishable states --- there's a distinction made internally -// between the target (a) and the source (b). -// -// So there are five test axes to cover: -// -// - Do we construct the chain with assignment ("Assign") or with constructors -// ("Construct")? -// -// - Do we set the value of the label at the start of the chain -// ("Start") or the label at the end ("End")? -// -// - Are we testing the propagation of a relationship between variable -// values ("Relation"), or the propagation of a known constant value -// ("Value")? -// -// - Do we set the value before building the chain ("Before") or after -// the chain has been built ("After")? -// -// - Do we add new relationships to the end of the existing chain -// ("Forward") or to the beginning ("Backward")? -// -// Of course, "Construct" and "Backward" can't be combined, which -// eliminates eight combinations, and "Construct", "End", and "Before" -// can't be combined, which eliminates two more, so there are are 22 -// combinations, not 32. - -TEST(LabelChain, AssignStartRelationBeforeForward) { - Label a, b, c, d; - Label x; - a = x; - b = a + 0x1; - c = b + 0x10; - d = c + 0x100; - EXPECT_EQ(0x111U, d-x); - EXPECT_EQ(0x11U, c-x); - EXPECT_EQ(0x1U, b-x); - EXPECT_EQ(0U, a-x); -} - -TEST(LabelChain, AssignStartRelationBeforeBackward) { - Label a, b, c, d; - Label x; - a = x; - d = c + 0x100; - c = b + 0x10; - b = a + 0x1; - EXPECT_EQ(0x111U, d-x); - EXPECT_EQ(0x11U, c-x); - EXPECT_EQ(0x1U, b-x); - EXPECT_EQ(0U, a-x); -} - -TEST(LabelChain, AssignStartRelationAfterForward) { - Label a, b, c, d; - Label x; - b = a + 0x1; - c = b + 0x10; - d = c + 0x100; - a = x; - EXPECT_EQ(0x111U, d-x); - EXPECT_EQ(0x11U, c-x); - EXPECT_EQ(0x1U, b-x); - EXPECT_EQ(0U, a-x); -} - -TEST(LabelChain, AssignStartRelationAfterBackward) { - Label a, b, c, d; - Label x; - d = c + 0x100; - c = b + 0x10; - b = a + 0x1; - a = x; - EXPECT_EQ(0x111U, d-x); - EXPECT_EQ(0x11U, c-x); - EXPECT_EQ(0x1U, b-x); - EXPECT_EQ(0U, a-x); -} - -TEST(LabelChain, AssignStartValueBeforeForward) { - Label a, b, c, d; - a = 0xa131200190546ac2ULL; - b = a + 0x1; - c = b + 0x10; - d = c + 0x100; - EXPECT_EQ(0xa131200190546ac2ULL + 0x111U, d.Value()); - EXPECT_EQ(0xa131200190546ac2ULL + 0x11U, c.Value()); - EXPECT_EQ(0xa131200190546ac2ULL + 0x1U, b.Value()); - EXPECT_EQ(0xa131200190546ac2ULL + 0U, a.Value()); -} - -TEST(LabelChain, AssignStartValueBeforeBackward) { - Label a, b, c, d; - a = 0x8da17e1670ad4fa2ULL; - d = c + 0x100; - c = b + 0x10; - b = a + 0x1; - EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x111U, d.Value()); - EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x11U, c.Value()); - EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0x1U, b.Value()); - EXPECT_EQ(0x8da17e1670ad4fa2ULL + 0U, a.Value()); -} - -TEST(LabelChain, AssignStartValueAfterForward) { - Label a, b, c, d; - b = a + 0x1; - c = b + 0x10; - d = c + 0x100; - a = 0x99b8f51bafd41adaULL; - EXPECT_EQ(0x99b8f51bafd41adaULL + 0x111U, d.Value()); - EXPECT_EQ(0x99b8f51bafd41adaULL + 0x11U, c.Value()); - EXPECT_EQ(0x99b8f51bafd41adaULL + 0x1U, b.Value()); - EXPECT_EQ(0x99b8f51bafd41adaULL + 0U, a.Value()); -} - -TEST(LabelChain, AssignStartValueAfterBackward) { - Label a, b, c, d; - d = c + 0x100; - c = b + 0x10; - b = a + 0x1; - a = 0xc86ca1d97ab5df6eULL; - EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x111U, d.Value()); - EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x11U, c.Value()); - EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0x1U, b.Value()); - EXPECT_EQ(0xc86ca1d97ab5df6eULL + 0U, a.Value()); -} - -TEST(LabelChain, AssignEndRelationBeforeForward) { - Label a, b, c, d; - Label x; - x = d; - b = a + 0x1; - c = b + 0x10; - d = c + 0x100; - EXPECT_EQ(-(uint64_t)0x111U, a-x); - EXPECT_EQ(-(uint64_t)0x110U, b-x); - EXPECT_EQ(-(uint64_t)0x100U, c-x); - EXPECT_EQ(-(uint64_t)0U, d-x); -} - -TEST(LabelChain, AssignEndRelationBeforeBackward) { - Label a, b, c, d; - Label x; - x = d; - d = c + 0x100; - c = b + 0x10; - b = a + 0x1; - EXPECT_EQ(-(uint64_t)0x111U, a-x); - EXPECT_EQ(-(uint64_t)0x110U, b-x); - EXPECT_EQ(-(uint64_t)0x100U, c-x); - EXPECT_EQ(-(uint64_t)0U, d-x); -} - -TEST(LabelChain, AssignEndRelationAfterForward) { - Label a, b, c, d; - Label x; - b = a + 0x1; - c = b + 0x10; - d = c + 0x100; - x = d; - EXPECT_EQ(-(uint64_t)0x111U, a-x); - EXPECT_EQ(-(uint64_t)0x110U, b-x); - EXPECT_EQ(-(uint64_t)0x100U, c-x); - EXPECT_EQ(-(uint64_t)0x000U, d-x); -} - -TEST(LabelChain, AssignEndRelationAfterBackward) { - Label a, b, c, d; - Label x; - d = c + 0x100; - c = b + 0x10; - b = a + 0x1; - x = d; - EXPECT_EQ(-(uint64_t)0x111U, a-x); - EXPECT_EQ(-(uint64_t)0x110U, b-x); - EXPECT_EQ(-(uint64_t)0x100U, c-x); - EXPECT_EQ(-(uint64_t)0x000U, d-x); -} - -TEST(LabelChain, AssignEndValueBeforeForward) { - Label a, b, c, d; - d = 0xa131200190546ac2ULL; - b = a + 0x1; - c = b + 0x10; - d = c + 0x100; - EXPECT_EQ(0xa131200190546ac2ULL - 0x111, a.Value()); - EXPECT_EQ(0xa131200190546ac2ULL - 0x110, b.Value()); - EXPECT_EQ(0xa131200190546ac2ULL - 0x100, c.Value()); - EXPECT_EQ(0xa131200190546ac2ULL - 0x000, d.Value()); -} - -TEST(LabelChain, AssignEndValueBeforeBackward) { - Label a, b, c, d; - d = 0x8da17e1670ad4fa2ULL; - d = c + 0x100; - c = b + 0x10; - b = a + 0x1; - EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x111, a.Value()); - EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x110, b.Value()); - EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x100, c.Value()); - EXPECT_EQ(0x8da17e1670ad4fa2ULL - 0x000, d.Value()); -} - -TEST(LabelChain, AssignEndValueAfterForward) { - Label a, b, c, d; - b = a + 0x1; - c = b + 0x10; - d = c + 0x100; - d = 0x99b8f51bafd41adaULL; - EXPECT_EQ(0x99b8f51bafd41adaULL - 0x111, a.Value()); - EXPECT_EQ(0x99b8f51bafd41adaULL - 0x110, b.Value()); - EXPECT_EQ(0x99b8f51bafd41adaULL - 0x100, c.Value()); - EXPECT_EQ(0x99b8f51bafd41adaULL - 0x000, d.Value()); -} - -TEST(LabelChain, AssignEndValueAfterBackward) { - Label a, b, c, d; - d = c + 0x100; - c = b + 0x10; - b = a + 0x1; - d = 0xc86ca1d97ab5df6eULL; - EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x111, a.Value()); - EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x110, b.Value()); - EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x100, c.Value()); - EXPECT_EQ(0xc86ca1d97ab5df6eULL - 0x000, d.Value()); -} - -TEST(LabelChain, ConstructStartRelationBeforeForward) { - Label x; - Label a(x); - Label b(a + 0x1); - Label c(b + 0x10); - Label d(c + 0x100); - EXPECT_EQ(0x111U, d-x); - EXPECT_EQ(0x11U, c-x); - EXPECT_EQ(0x1U, b-x); - EXPECT_EQ(0U, a-x); -} - -TEST(LabelChain, ConstructStartRelationAfterForward) { - Label x; - Label a; - Label b(a + 0x1); - Label c(b + 0x10); - Label d(c + 0x100); - a = x; - EXPECT_EQ(0x111U, d-x); - EXPECT_EQ(0x11U, c-x); - EXPECT_EQ(0x1U, b-x); - EXPECT_EQ(0U, a-x); -} - -TEST(LabelChain, ConstructStartValueBeforeForward) { - Label a(0x5d234d177d01ccc8ULL); - Label b(a + 0x1); - Label c(b + 0x10); - Label d(c + 0x100); - EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x111U, d.Value()); - EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x011U, c.Value()); - EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x001U, b.Value()); - EXPECT_EQ(0x5d234d177d01ccc8ULL + 0x000U, a.Value()); -} - -TEST(LabelChain, ConstructStartValueAfterForward) { - Label a; - Label b(a + 0x1); - Label c(b + 0x10); - Label d(c + 0x100); - a = 0xded85d54586e84fcULL; - EXPECT_EQ(0xded85d54586e84fcULL + 0x111U, d.Value()); - EXPECT_EQ(0xded85d54586e84fcULL + 0x011U, c.Value()); - EXPECT_EQ(0xded85d54586e84fcULL + 0x001U, b.Value()); - EXPECT_EQ(0xded85d54586e84fcULL + 0x000U, a.Value()); -} - -TEST(LabelChain, ConstructEndRelationAfterForward) { - Label x; - Label a; - Label b(a + 0x1); - Label c(b + 0x10); - Label d(c + 0x100); - x = d; - EXPECT_EQ(-(uint64_t)0x111U, a-x); - EXPECT_EQ(-(uint64_t)0x110U, b-x); - EXPECT_EQ(-(uint64_t)0x100U, c-x); - EXPECT_EQ(-(uint64_t)0x000U, d-x); -} - -TEST(LabelChain, ConstructEndValueAfterForward) { - Label a; - Label b(a + 0x1); - Label c(b + 0x10); - Label d(c + 0x100); - d = 0x99b8f51bafd41adaULL; - EXPECT_EQ(0x99b8f51bafd41adaULL - 0x111, a.Value()); - EXPECT_EQ(0x99b8f51bafd41adaULL - 0x110, b.Value()); - EXPECT_EQ(0x99b8f51bafd41adaULL - 0x100, c.Value()); - EXPECT_EQ(0x99b8f51bafd41adaULL - 0x000, d.Value()); -} - -TEST(LabelTree, KnownValue) { - Label l, m, n, o, p; - l = m; - m = n; - o = p; - p = n; - l = 0x536b5de3d468a1b5ULL; - EXPECT_EQ(0x536b5de3d468a1b5ULL, o.Value()); -} - -TEST(LabelTree, Related) { - Label l, m, n, o, p; - l = m - 1; - m = n - 10; - o = p + 100; - p = n + 1000; - EXPECT_EQ(1111U, o - l); -} - -TEST(EquationDeathTest, EqualConstants) { - Label m = 0x0d3962f280f07d24ULL; - Label n = 0x0d3962f280f07d24ULL; - m = n; // no death expected -} - -TEST(EquationDeathTest, EqualIndirectConstants) { - Label m = 0xa347f1e5238fe6a1ULL; - Label n; - Label o = n; - n = 0xa347f1e5238fe6a1ULL; - n = m; // no death expected -} - -TEST(EquationDeathTest, ConstantClash) { - Label m = 0xd4cc0f4f630ec741ULL; - Label n = 0x934cd2d8254fc3eaULL; - ASSERT_DEATH(m = n, "addend_ == addend"); -} - -TEST(EquationDeathTest, IndirectConstantClash) { - Label m = 0xd4cc0f4f630ec741ULL; - Label n, o; - n = o; - o = 0xcfbe3b83ac49ce86ULL; - ASSERT_DEATH(m = n, "addend_ == addend"); -} - -// Assigning to a related label may free the next Binding on its -// chain. This test always passes; it is interesting to memory -// checkers and coverage analysis. -TEST(LabelReferenceCount, AssignmentFree) { - Label l; - { - Label m; - l = m; - } - // This should free m's Binding. - l = 0xca8bae92f0376d4fULL; - ASSERT_EQ(0xca8bae92f0376d4fULL, l.Value()); -} - -// Finding the value of a label may free the Binding it refers to. This test -// always passes; it is interesting to memory checkers and coverage analysis. -TEST(LabelReferenceCount, FindValueFree) { - Label l; - { - Label m, n; - l = m; - m = n; - n = 0x7a0b0c576672daafULL; - // At this point, l's Binding refers to m's Binding, which refers - // to n's binding. - } - // Now, l is the only reference keeping the three Bindings alive. - // Resolving its value should free l's and m's original bindings. - ASSERT_EQ(0x7a0b0c576672daafULL, l.Value()); -} - -TEST(ConstructSection, Simple) { - Section s; -} - -TEST(ConstructSection, WithEndian) { - Section s(kBigEndian); -} - -// A fixture class for TestAssembler::Section tests. -class SectionFixture { - public: - Section section; - string contents; - static const uint8_t data[]; - static const size_t data_size; -}; - -const uint8_t SectionFixture::data[] = { - 0x87, 0x4f, 0x43, 0x67, 0x30, 0xd0, 0xd4, 0x0e -}; - -#define I0() -#define I1(a) { a } -#define I2(a,b) { a,b } -#define I3(a,b,c) { a,b,c } -#define I4(a,b,c,d) { a,b,c,d } -#define I5(a,b,c,d,e) { a,b,c,d,e } -#define I6(a,b,c,d,e,f) { a,b,c,d,e,f } -#define I7(a,b,c,d,e,f,g) { a,b,c,d,e,f,g } -#define I8(a,b,c,d,e,f,g,h) { a,b,c,d,e,f,g,h } -#define I9(a,b,c,d,e,f,g,h,i) { a,b,c,d,e,f,g,h,i } -#define ASSERT_BYTES(s, b) \ - do \ - { \ - static const uint8_t expected_bytes[] = b; \ - ASSERT_EQ(sizeof(expected_bytes), s.size()); \ - ASSERT_TRUE(memcmp(s.data(), (const char *) expected_bytes, \ - sizeof(expected_bytes)) == 0); \ - } \ - while(0) - -class Append: public SectionFixture, public Test { }; - -TEST_F(Append, Bytes) { - section.Append(data, sizeof(data)); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_EQ(sizeof(data), contents.size()); - EXPECT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data))); -} - -TEST_F(Append, BytesTwice) { - section.Append(data, sizeof(data)); - section.Append(data, sizeof(data)); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_EQ(2 * sizeof(data), contents.size()); - ASSERT_TRUE(0 == memcmp(contents.data(), (const char *) data, sizeof(data))); - ASSERT_TRUE(0 == memcmp(contents.data() + sizeof(data), - (const char *) data, sizeof(data))); -} - -TEST_F(Append, String) { - string s1 = "howdy "; - string s2 = "there"; - section.Append(s1); - section.Append(s2); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_STREQ(contents.c_str(), "howdy there"); -} - -TEST_F(Append, CString) { - section.AppendCString("howdy"); - section.AppendCString(""); - section.AppendCString("there"); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_EQ(string("howdy\0\0there\0", 13), contents); -} - -TEST_F(Append, CStringSize) { - section.AppendCString("howdy", 3); - section.AppendCString("there", 5); - section.AppendCString("fred", 6); - section.AppendCString("natalie", 0); - section.AppendCString("", 10); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_EQ(string("howtherefred\0\0\0\0\0\0\0\0\0\0\0\0", 24), contents); -} - -TEST_F(Append, RepeatedBytes) { - section.Append((size_t) 10, '*'); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_STREQ(contents.c_str(), "**********"); -} - -TEST_F(Append, GeneralLE1) { - section.Append(kLittleEndian, 1, 42); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I1(42)); -} - -TEST_F(Append, GeneralLE2) { - section.Append(kLittleEndian, 2, 0x15a1); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I2(0xa1, 0x15)); -} - -TEST_F(Append, GeneralLE3) { - section.Append(kLittleEndian, 3, 0x59ae8d); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I3(0x8d, 0xae, 0x59)); -} - -TEST_F(Append, GeneralLE4) { - section.Append(kLittleEndian, 4, 0x51603c56); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I4(0x56, 0x3c, 0x60, 0x51)); -} - -TEST_F(Append, GeneralLE5) { - section.Append(kLittleEndian, 5, 0x385e2803b4ULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I5(0xb4, 0x03, 0x28, 0x5e, 0x38)); -} - -TEST_F(Append, GeneralLE6) { - section.Append(kLittleEndian, 6, 0xc7db9534dd1fULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I6(0x1f, 0xdd, 0x34, 0x95, 0xdb, 0xc7)); -} - -TEST_F(Append, GeneralLE7) { - section.Append(kLittleEndian, 7, 0x1445c9f1b843e6ULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I7(0xe6, 0x43, 0xb8, 0xf1, 0xc9, 0x45, 0x14)); -} - -TEST_F(Append, GeneralLE8) { - section.Append(kLittleEndian, 8, 0xaf48019dfe5c01e5ULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I8(0xe5, 0x01, 0x5c, 0xfe, 0x9d, 0x01, 0x48, 0xaf)); -} - -TEST_F(Append, GeneralBE1) { - section.Append(kBigEndian, 1, 0xd0ULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I1(0xd0)); -} - -TEST_F(Append, GeneralBE2) { - section.Append(kBigEndian, 2, 0x2e7eULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I2(0x2e, 0x7e)); -} - -TEST_F(Append, GeneralBE3) { - section.Append(kBigEndian, 3, 0x37dad6ULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I3(0x37, 0xda, 0xd6)); -} - -TEST_F(Append, GeneralBE4) { - section.Append(kBigEndian, 4, 0x715935c7ULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I4(0x71, 0x59, 0x35, 0xc7)); -} - -TEST_F(Append, GeneralBE5) { - section.Append(kBigEndian, 5, 0x42baeb02b7ULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I5(0x42, 0xba, 0xeb, 0x02, 0xb7)); -} - -TEST_F(Append, GeneralBE6) { - section.Append(kBigEndian, 6, 0xf1cdf10e7b18ULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I6(0xf1, 0xcd, 0xf1, 0x0e, 0x7b, 0x18)); -} - -TEST_F(Append, GeneralBE7) { - section.Append(kBigEndian, 7, 0xf50a724f0b0d20ULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I7(0xf5, 0x0a, 0x72, 0x4f, 0x0b, 0x0d, 0x20)); -} - -TEST_F(Append, GeneralBE8) { - section.Append(kBigEndian, 8, 0xa6b2cb5e98dc9c16ULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I8(0xa6, 0xb2, 0xcb, 0x5e, 0x98, 0xdc, 0x9c, 0x16)); -} - -TEST_F(Append, GeneralLE1Label) { - Label l; - section.Append(kLittleEndian, 1, l); - l = 42; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I1(42)); -} - -TEST_F(Append, GeneralLE2Label) { - Label l; - section.Append(kLittleEndian, 2, l); - l = 0x15a1; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I2(0xa1, 0x15)); -} - -TEST_F(Append, GeneralLE3Label) { - Label l; - section.Append(kLittleEndian, 3, l); - l = 0x59ae8d; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I3(0x8d, 0xae, 0x59)); -} - -TEST_F(Append, GeneralLE4Label) { - Label l; - section.Append(kLittleEndian, 4, l); - l = 0x51603c56; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I4(0x56, 0x3c, 0x60, 0x51)); -} - -TEST_F(Append, GeneralLE5Label) { - Label l; - section.Append(kLittleEndian, 5, l); - l = 0x385e2803b4ULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I5(0xb4, 0x03, 0x28, 0x5e, 0x38)); -} - -TEST_F(Append, GeneralLE6Label) { - Label l; - section.Append(kLittleEndian, 6, l); - l = 0xc7db9534dd1fULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I6(0x1f, 0xdd, 0x34, 0x95, 0xdb, 0xc7)); -} - -TEST_F(Append, GeneralLE7Label) { - Label l; - section.Append(kLittleEndian, 7, l); - l = 0x1445c9f1b843e6ULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I7(0xe6, 0x43, 0xb8, 0xf1, 0xc9, 0x45, 0x14)); -} - -TEST_F(Append, GeneralLE8Label) { - Label l; - section.Append(kLittleEndian, 8, l); - l = 0xaf48019dfe5c01e5ULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I8(0xe5, 0x01, 0x5c, 0xfe, 0x9d, 0x01, 0x48, 0xaf)); -} - -TEST_F(Append, GeneralBE1Label) { - Label l; - section.Append(kBigEndian, 1, l); - l = 0xd0ULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I1(0xd0)); -} - -TEST_F(Append, GeneralBE2Label) { - Label l; - section.Append(kBigEndian, 2, l); - l = 0x2e7eULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I2(0x2e, 0x7e)); -} - -TEST_F(Append, GeneralBE3Label) { - Label l; - section.Append(kBigEndian, 3, l); - l = 0x37dad6ULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I3(0x37, 0xda, 0xd6)); -} - -TEST_F(Append, GeneralBE4Label) { - Label l; - section.Append(kBigEndian, 4, l); - l = 0x715935c7ULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I4(0x71, 0x59, 0x35, 0xc7)); -} - -TEST_F(Append, GeneralBE5Label) { - Label l; - section.Append(kBigEndian, 5, l); - l = 0x42baeb02b7ULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I5(0x42, 0xba, 0xeb, 0x02, 0xb7)); -} - -TEST_F(Append, GeneralBE6Label) { - Label l; - section.Append(kBigEndian, 6, l); - l = 0xf1cdf10e7b18ULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I6(0xf1, 0xcd, 0xf1, 0x0e, 0x7b, 0x18)); -} - -TEST_F(Append, GeneralBE7Label) { - Label l; - section.Append(kBigEndian, 7, l); - l = 0xf50a724f0b0d20ULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I7(0xf5, 0x0a, 0x72, 0x4f, 0x0b, 0x0d, 0x20)); -} - -TEST_F(Append, GeneralBE8Label) { - Label l; - section.Append(kBigEndian, 8, l); - l = 0xa6b2cb5e98dc9c16ULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I8(0xa6, 0xb2, 0xcb, 0x5e, 0x98, 0xdc, 0x9c, 0x16)); -} - -TEST_F(Append, B8) { - section.Append(1, 0x2a); - section.B8(0xd3U); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I2(0x2a, 0xd3)); -} - -TEST_F(Append, B8Label) { - Label l; - section.Append(1, 0x2a); - section.B8(l); - l = 0x4bU; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I2(0x2a, 0x4b)); -} - -TEST_F(Append, B16) { - section.Append(1, 0x2a); - section.B16(0x472aU); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I3(0x2a, 0x47, 0x2a)); -} - -TEST_F(Append, B16Label) { - Label l; - section.Append(1, 0x2a); - section.B16(l); - l = 0x55e8U; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I3(0x2a, 0x55, 0xe8)); -} - -TEST_F(Append, B32) { - section.Append(1, 0x2a); - section.B32(0xbd412cbcU); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I5(0x2a, 0xbd, 0x41, 0x2c, 0xbc)); -} - -TEST_F(Append, B32Label) { - Label l; - section.Append(1, 0x2a); - section.B32(l); - l = 0x208e37d5U; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I5(0x2a, 0x20, 0x8e, 0x37, 0xd5)); -} - -TEST_F(Append, B64) { - section.Append(1, 0x2a); - section.B64(0x3402a013111e68adULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, - I9(0x2a, 0x34, 0x02, 0xa0, 0x13, 0x11, 0x1e, 0x68, 0xad)); -} - -TEST_F(Append, B64Label) { - Label l; - section.Append(1, 0x2a); - section.B64(l); - l = 0x355dbfbb4ac6d57fULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, - I9(0x2a, 0x35, 0x5d, 0xbf, 0xbb, 0x4a, 0xc6, 0xd5, 0x7f)); -} - -TEST_F(Append, L8) { - section.Append(1, 0x2a); - section.L8(0x26U); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I2(0x2a, 0x26)); -} - -TEST_F(Append, L8Label) { - Label l; - section.Append(1, 0x2a); - section.L8(l); - l = 0xa8U; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I2(0x2a, 0xa8)); -} - -TEST_F(Append, L16) { - section.Append(1, 0x2a); - section.L16(0xca6dU); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I3(0x2a, 0x6d, 0xca)); -} - -TEST_F(Append, L16Label) { - Label l; - section.Append(1, 0x2a); - section.L16(l); - l = 0xd21fU; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I3(0x2a, 0x1f, 0xd2)); -} - -TEST_F(Append, L32) { - section.Append(1, 0x2a); - section.L32(0x558f6181U); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I5(0x2a, 0x81, 0x61, 0x8f, 0x55)); -} - -TEST_F(Append, L32Label) { - Label l; - section.Append(1, 0x2a); - section.L32(l); - l = 0x4b810f82U; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I5(0x2a, 0x82, 0x0f, 0x81, 0x4b)); -} - -TEST_F(Append, L64) { - section.Append(1, 0x2a); - section.L64(0x564384f7579515bfULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, - I9(0x2a, 0xbf, 0x15, 0x95, 0x57, 0xf7, 0x84, 0x43, 0x56)); -} - -TEST_F(Append, L64Label) { - Label l; - section.Append(1, 0x2a); - section.L64(l); - l = 0x424b1d020667c8dbULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, - I9(0x2a, 0xdb, 0xc8, 0x67, 0x06, 0x02, 0x1d, 0x4b, 0x42)); -} - -TEST_F(Append, D8Big) { - section.set_endianness(kBigEndian); - section.Append(1, 0x2a); - section.D8(0xe6U); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I2(0x2a, 0xe6)); -} - -TEST_F(Append, D8BigLabel) { - Label l; - section.set_endianness(kBigEndian); - section.Append(1, 0x2a); - section.D8(l); - l = 0xeeU; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I2(0x2a, 0xee)); -} - -TEST_F(Append, D16Big) { - section.set_endianness(kBigEndian); - section.Append(1, 0x2a); - section.D16(0x83b1U); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I3(0x2a, 0x83, 0xb1)); -} - -TEST_F(Append, D16BigLabel) { - Label l; - section.set_endianness(kBigEndian); - section.Append(1, 0x2a); - section.D16(l); - l = 0x5b55U; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I3(0x2a, 0x5b, 0x55)); -} - -TEST_F(Append, D32Big) { - section.set_endianness(kBigEndian); - section.Append(1, 0x2a); - section.D32(0xd0b0e431U); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I5(0x2a, 0xd0, 0xb0, 0xe4, 0x31)); -} - -TEST_F(Append, D32BigLabel) { - Label l; - section.set_endianness(kBigEndian); - section.Append(1, 0x2a); - section.D32(l); - l = 0x312fb340U; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I5(0x2a, 0x31, 0x2f, 0xb3, 0x40)); -} - -TEST_F(Append, D64Big) { - section.set_endianness(kBigEndian); - section.Append(1, 0x2a); - section.D64(0xb109843500dbcb16ULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, - I9(0x2a, 0xb1, 0x09, 0x84, 0x35, 0x00, 0xdb, 0xcb, 0x16)); -} - -TEST_F(Append, D64BigLabel) { - Label l; - section.set_endianness(kBigEndian); - section.Append(1, 0x2a); - section.D64(l); - l = 0x9a0d61b70f671fd7ULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, - I9(0x2a, 0x9a, 0x0d, 0x61, 0xb7, 0x0f, 0x67, 0x1f, 0xd7)); -} - -TEST_F(Append, D8Little) { - section.set_endianness(kLittleEndian); - section.Append(1, 0x2a); - section.D8(0x42U); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I2(0x2a, 0x42)); -} - -TEST_F(Append, D8LittleLabel) { - Label l; - section.set_endianness(kLittleEndian); - section.Append(1, 0x2a); - section.D8(l); - l = 0x05U; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I2(0x2a, 0x05)); -} - -TEST_F(Append, D16Little) { - section.set_endianness(kLittleEndian); - section.Append(1, 0x2a); - section.D16(0xc5c5U); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I3(0x2a, 0xc5, 0xc5)); -} - -TEST_F(Append, D16LittleLabel) { - Label l; - section.set_endianness(kLittleEndian); - section.Append(1, 0x2a); - section.D16(l); - l = 0xb620U; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I3(0x2a, 0x20, 0xb6)); -} - -TEST_F(Append, D32Little) { - section.set_endianness(kLittleEndian); - section.Append(1, 0x2a); - section.D32(0x1a87d0feU); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I5(0x2a, 0xfe, 0xd0, 0x87, 0x1a)); -} - -TEST_F(Append, D32LittleLabel) { - Label l; - section.set_endianness(kLittleEndian); - section.Append(1, 0x2a); - section.D32(l); - l = 0xb8012d6bU; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I5(0x2a, 0x6b, 0x2d, 0x01, 0xb8)); -} - -TEST_F(Append, D64Little) { - section.set_endianness(kLittleEndian); - section.Append(1, 0x2a); - section.D64(0x42de75c61375a1deULL); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, - I9(0x2a, 0xde, 0xa1, 0x75, 0x13, 0xc6, 0x75, 0xde, 0x42)); -} - -TEST_F(Append, D64LittleLabel) { - Label l; - section.set_endianness(kLittleEndian); - section.Append(1, 0x2a); - section.D64(l); - l = 0x8b3bececf3fb5312ULL; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, - I9(0x2a, 0x12, 0x53, 0xfb, 0xf3, 0xec, 0xec, 0x3b, 0x8b)); -} - -TEST_F(Append, Variety) { - Label a, b, c, d, e, f, g, h; - section.Append(kBigEndian, 1, a) - .Append(kLittleEndian, 8, h) - .Append(kBigEndian, 1, 0x8bULL) - .Append(kLittleEndian, 8, 0x0ea56540448f4439ULL) - .Append(kBigEndian, 2, b) - .Append(kLittleEndian, 7, g) - .Append(kBigEndian, 2, 0xcf15ULL) - .Append(kLittleEndian, 7, 0x29694f04c5724aULL) - .Append(kBigEndian, 3, c) - .Append(kLittleEndian, 6, f) - .Append(kBigEndian, 3, 0x8c3ffdULL) - .Append(kLittleEndian, 6, 0x6f11ba80187aULL) - .Append(kBigEndian, 4, d) - .Append(kLittleEndian, 5, e) - .Append(kBigEndian, 4, 0x2fda2472ULL) - .Append(kLittleEndian, 5, 0x0aa02d423fULL) - .Append(kBigEndian, 5, e) - .Append(kLittleEndian, 4, d) - .Append(kBigEndian, 5, 0x53ba432138ULL) - .Append(kLittleEndian, 4, 0xf139ae60ULL) - .Append(kBigEndian, 6, f) - .Append(kLittleEndian, 3, c) - .Append(kBigEndian, 6, 0x168e436af716ULL) - .Append(kLittleEndian, 3, 0x3ef189ULL) - .Append(kBigEndian, 7, g) - .Append(kLittleEndian, 2, b) - .Append(kBigEndian, 7, 0xacd4ef233e47d9ULL) - .Append(kLittleEndian, 2, 0x5311ULL) - .Append(kBigEndian, 8, h) - .Append(kLittleEndian, 1, a) - .Append(kBigEndian, 8, 0x4668d5f1c93637a1ULL) - .Append(kLittleEndian, 1, 0x65ULL); - a = 0x79ac9bd8aa256b35ULL; - b = 0x22d13097ef86c91cULL; - c = 0xf204968b0a05862fULL; - d = 0x163177f15a0eb4ecULL; - e = 0xbd1b0f1d977f2246ULL; - f = 0x2b0842eee83c6461ULL; - g = 0x92f4b928a4bf875eULL; - h = 0x61a199a8f7286ba6ULL; - ASSERT_EQ(8 * 18U, section.Size()); - ASSERT_TRUE(section.GetContents(&contents)); - - static const uint8_t expected[] = { - 0x35, 0xa6, 0x6b, 0x28, 0xf7, 0xa8, 0x99, 0xa1, 0x61, - 0x8b, 0x39, 0x44, 0x8f, 0x44, 0x40, 0x65, 0xa5, 0x0e, - 0xc9, 0x1c, 0x5e, 0x87, 0xbf, 0xa4, 0x28, 0xb9, 0xf4, - 0xcf, 0x15, 0x4a, 0x72, 0xc5, 0x04, 0x4f, 0x69, 0x29, - 0x05, 0x86, 0x2f, 0x61, 0x64, 0x3c, 0xe8, 0xee, 0x42, - 0x8c, 0x3f, 0xfd, 0x7a, 0x18, 0x80, 0xba, 0x11, 0x6f, - 0x5a, 0x0e, 0xb4, 0xec, 0x46, 0x22, 0x7f, 0x97, 0x1d, - 0x2f, 0xda, 0x24, 0x72, 0x3f, 0x42, 0x2d, 0xa0, 0x0a, - 0x1d, 0x97, 0x7f, 0x22, 0x46, 0xec, 0xb4, 0x0e, 0x5a, - 0x53, 0xba, 0x43, 0x21, 0x38, 0x60, 0xae, 0x39, 0xf1, - 0x42, 0xee, 0xe8, 0x3c, 0x64, 0x61, 0x2f, 0x86, 0x05, - 0x16, 0x8e, 0x43, 0x6a, 0xf7, 0x16, 0x89, 0xf1, 0x3e, - 0xf4, 0xb9, 0x28, 0xa4, 0xbf, 0x87, 0x5e, 0x1c, 0xc9, - 0xac, 0xd4, 0xef, 0x23, 0x3e, 0x47, 0xd9, 0x11, 0x53, - 0x61, 0xa1, 0x99, 0xa8, 0xf7, 0x28, 0x6b, 0xa6, 0x35, - 0x46, 0x68, 0xd5, 0xf1, 0xc9, 0x36, 0x37, 0xa1, 0x65, - }; - - ASSERT_TRUE(0 == memcmp(contents.data(), expected, sizeof(expected))); -} - -TEST_F(Append, Section) { - section.Append("murder"); - { - Section middle; - middle.Append(" she"); - section.Append(middle); - } - section.Append(" wrote"); - EXPECT_EQ(16U, section.Size()); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_STREQ(contents.c_str(), "murder she wrote"); -} - -TEST_F(Append, SectionRefs) { - section.Append("sugar "); - Label l; - { - Section middle; - Label m; - middle.B32(m); - section.Append(middle); - m = 0x66726565; - } - section.Append(" jazz"); - EXPECT_EQ(15U, section.Size()); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_STREQ(contents.c_str(), "sugar free jazz"); -} - -TEST_F(Append, LEB128_0) { - section.LEB128(0); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\0", 1), contents); -} - -TEST_F(Append, LEB128_0x3f) { - section.LEB128(0x3f); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x3f", 1), contents); -} - -TEST_F(Append, LEB128_0x40) { - section.LEB128(0x40); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\xc0\x00", 2), contents); -} - -TEST_F(Append, LEB128_0x7f) { - section.LEB128(0x7f); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\xff\x00", 2), contents); -} - -TEST_F(Append, LEB128_0x80) { - section.LEB128(0x80); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x80\x01", 2), contents); -} - -TEST_F(Append, LEB128_0xff) { - section.LEB128(0xff); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\xff\x01", 2), contents); -} - -TEST_F(Append, LEB128_0x1fff) { - section.LEB128(0x1fff); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\xff\x3f", 2), contents); -} - -TEST_F(Append, LEB128_0x2000) { - section.LEB128(0x2000); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x80\xc0\x00", 3), contents); -} - -TEST_F(Append, LEB128_n1) { - section.LEB128(-1); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x7f", 1), contents); -} - -TEST_F(Append, LEB128_n0x40) { - section.LEB128(-0x40); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x40", 1), contents); -} - -TEST_F(Append, LEB128_n0x41) { - section.LEB128(-0x41); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\xbf\x7f", 2), contents); -} - -TEST_F(Append, LEB128_n0x7f) { - section.LEB128(-0x7f); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x81\x7f", 2), contents); -} - -TEST_F(Append, LEB128_n0x80) { - section.LEB128(-0x80); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x80\x7f", 2), contents); -} - -TEST_F(Append, LEB128_n0x2000) { - section.LEB128(-0x2000); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x80\x40", 2), contents); -} - -TEST_F(Append, LEB128_n0x2001) { - section.LEB128(-0x2001); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\xff\xbf\x7f", 3), contents); -} - -TEST_F(Append,ULEB128_0) { - section.ULEB128(0); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\0", 1), contents); -} - -TEST_F(Append,ULEB128_1) { - section.ULEB128(1); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x01", 1), contents); -} - -TEST_F(Append,ULEB128_0x3f) { - section.ULEB128(0x3f); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x3f", 1), contents); -} - -TEST_F(Append,ULEB128_0x40) { - section.ULEB128(0x40); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x40", 1), contents); -} - -TEST_F(Append,ULEB128_0x7f) { - section.ULEB128(0x7f); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x7f", 1), contents); -} - -TEST_F(Append,ULEB128_0x80) { - section.ULEB128(0x80); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x80\x01", 2), contents); -} - -TEST_F(Append,ULEB128_0xff) { - section.ULEB128(0xff); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\xff\x01", 2), contents); -} - -TEST_F(Append,ULEB128_0x100) { - section.ULEB128(0x100); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x80\x02", 2), contents); -} - -TEST_F(Append,ULEB128_0x1fff) { - section.ULEB128(0x1fff); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\xff\x3f", 2), contents); -} - -TEST_F(Append,ULEB128_0x2000) { - section.ULEB128(0x2000); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x80\x40", 2), contents); -} - -TEST_F(Append,ULEB128_0x3fff) { - section.ULEB128(0x3fff); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\xff\x7f", 2), contents); -} - -TEST_F(Append,ULEB128_0x4000) { - section.ULEB128(0x4000); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x80\x80\x01", 3), contents); -} - -TEST_F(Append,ULEB128_12857) { - section.ULEB128(12857); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\xb9\x64", 2), contents); -} - -TEST_F(Append, LEBChain) { - section.LEB128(-0x80).ULEB128(12857).Append("*"); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(string("\x80\x7f\xb9\x64*", 5), contents); -} - - -class GetContents: public SectionFixture, public Test { }; - -TEST_F(GetContents, Undefined) { - Label l; - section.Append(kLittleEndian, 8, l); - ASSERT_FALSE(section.GetContents(&contents)); -} - -TEST_F(GetContents, ClearsContents) { - section.Append((size_t) 10, '*'); - EXPECT_EQ(10U, section.Size()); - EXPECT_TRUE(section.GetContents(&contents)); - EXPECT_EQ(0U, section.Size()); -} - -TEST_F(GetContents, ClearsReferences) { - Label l; - section.Append(kBigEndian, 1, l); - l = 42; - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_BYTES(contents, I1(42)); - ASSERT_TRUE(section.GetContents(&contents)); // should not die -} - -class Miscellanea: public SectionFixture, public Test { }; - -TEST_F(Miscellanea, Clear) { - section.Append("howdy"); - Label l; - section.L32(l); - EXPECT_EQ(9U, section.Size()); - section.Clear(); - EXPECT_EQ(0U, section.Size()); - l = 0x8d231bf0U; - ASSERT_TRUE(section.GetContents(&contents)); // should not die -} - -TEST_F(Miscellanea, Align) { - section.Append("*"); - EXPECT_EQ(1U, section.Size()); - section.Align(4).Append("*"); - EXPECT_EQ(5U, section.Size()); - section.Append("*").Align(2); - EXPECT_EQ(6U, section.Size()); -} - -TEST_F(Miscellanea, AlignPad) { - section.Append("*"); - EXPECT_EQ(1U, section.Size()); - section.Align(4, ' ').Append("*"); - EXPECT_EQ(5U, section.Size()); - section.Append("*").Align(2, ' '); - EXPECT_EQ(6U, section.Size()); - ASSERT_TRUE(section.GetContents(&contents)); - ASSERT_EQ(string("* **"), contents); -} - -TEST_F(Miscellanea, StartHereMark) { - Label m; - section.Append(42, ' ').Mark(&m).Append(13, '+'); - EXPECT_EQ(42U, m - section.start()); - EXPECT_EQ(42U + 13U, section.Here() - section.start()); - EXPECT_FALSE(section.start().IsKnownConstant()); - EXPECT_FALSE(m.IsKnownConstant()); - EXPECT_FALSE(section.Here().IsKnownConstant()); -} - -TEST_F(Miscellanea, Endianness) { - section.set_endianness(kBigEndian); - EXPECT_EQ(kBigEndian, section.endianness()); - section.set_endianness(kLittleEndian); - EXPECT_EQ(kLittleEndian, section.endianness()); -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/testdata/func-line-pairing.h b/toolkit/crashreporter/google-breakpad/src/common/testdata/func-line-pairing.h deleted file mode 100644 index 05538f961..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/testdata/func-line-pairing.h +++ /dev/null @@ -1,676 +0,0 @@ -// -*- mode: c++ -*- - -// Test data for pairing functions and lines. -// -// For a pair of functions that are adjacent (10,20),(20,25) and a -// pair that are not (10,15),(20,25), we include a test case for every -// possible arrangement of two lines relative to those functions. We -// include cases only for non-empty ranges, since empty functions and -// lines are dropped before we do any pairing. -// -// Each test case is represented by a macro call of the form: -// -// PAIRING(func1_start, func1_end, func2_start, func2_end, -// line1_start, line1_end, line2_start, line2_end, -// func1_num_lines, func2_num_lines, -// func1_line1_start, func1_line1_end, -// func1_line2_start, func1_line2_end, -// func2_line1_start, func2_line1_end, -// func2_line2_start, func2_line2_end, -// uncovered_funcs, uncovered_lines) -// -// where: -// - funcN_{start,end} is the range of the N'th function -// - lineN_{start,end} is the range of the N'th function -// - funcN_num_lines is the number of source lines that should be -// paired with the N'th function -// - funcN_lineM_{start,end} is the range of the M'th line -// paired with the N'th function, where 0,0 indicates that -// there should be no such line paired -// - uncovered_funcs is the number of functions with area that is -// uncovered by any line, and -// - uncovered_lines is the reverse. - -// func1 func2 line1 line2 num pairing1 pairing2 uncovered -PAIRING(10, 20, 20, 25, 6, 7, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #0 -PAIRING(10, 20, 20, 25, 6, 7, 7, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #1 -PAIRING(10, 20, 20, 25, 6, 7, 7, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #2 -PAIRING(10, 20, 20, 25, 6, 7, 7, 20, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 2) // #3 -PAIRING(10, 20, 20, 25, 6, 7, 7, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 2) // #4 -PAIRING(10, 20, 20, 25, 6, 7, 7, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #5 -PAIRING(10, 20, 20, 25, 6, 7, 7, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #6 -PAIRING(10, 20, 20, 25, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #7 -PAIRING(10, 20, 20, 25, 6, 7, 8, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #8 -PAIRING(10, 20, 20, 25, 6, 7, 8, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #9 -PAIRING(10, 20, 20, 25, 6, 7, 8, 20, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 2) // #10 -PAIRING(10, 20, 20, 25, 6, 7, 8, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 2) // #11 -PAIRING(10, 20, 20, 25, 6, 7, 8, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #12 -PAIRING(10, 20, 20, 25, 6, 7, 8, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #13 -PAIRING(10, 20, 20, 25, 6, 7, 10, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #14 -PAIRING(10, 20, 20, 25, 6, 7, 10, 20, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 1) // #15 -PAIRING(10, 20, 20, 25, 6, 7, 10, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #16 -PAIRING(10, 20, 20, 25, 6, 7, 10, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #17 -PAIRING(10, 20, 20, 25, 6, 7, 10, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #18 -PAIRING(10, 20, 20, 25, 6, 7, 11, 12, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #19 -PAIRING(10, 20, 20, 25, 6, 7, 11, 20, 1, 0, 11, 20, 0, 0, 0, 0, 0, 0, 2, 1) // #20 -PAIRING(10, 20, 20, 25, 6, 7, 11, 21, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 1) // #21 -PAIRING(10, 20, 20, 25, 6, 7, 11, 25, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #22 -PAIRING(10, 20, 20, 25, 6, 7, 11, 26, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 2) // #23 -PAIRING(10, 20, 20, 25, 6, 7, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #24 -PAIRING(10, 20, 20, 25, 6, 7, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #25 -PAIRING(10, 20, 20, 25, 6, 7, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #26 -PAIRING(10, 20, 20, 25, 6, 7, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #27 -PAIRING(10, 20, 20, 25, 6, 7, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #28 -PAIRING(10, 20, 20, 25, 6, 7, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #29 -PAIRING(10, 20, 20, 25, 6, 7, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #30 -PAIRING(10, 20, 20, 25, 6, 7, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #31 -PAIRING(10, 20, 20, 25, 6, 10, 10, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #32 -PAIRING(10, 20, 20, 25, 6, 10, 10, 20, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 1) // #33 -PAIRING(10, 20, 20, 25, 6, 10, 10, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #34 -PAIRING(10, 20, 20, 25, 6, 10, 10, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #35 -PAIRING(10, 20, 20, 25, 6, 10, 10, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #36 -PAIRING(10, 20, 20, 25, 6, 10, 11, 12, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #37 -PAIRING(10, 20, 20, 25, 6, 10, 11, 20, 1, 0, 11, 20, 0, 0, 0, 0, 0, 0, 2, 1) // #38 -PAIRING(10, 20, 20, 25, 6, 10, 11, 21, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 1) // #39 -PAIRING(10, 20, 20, 25, 6, 10, 11, 25, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #40 -PAIRING(10, 20, 20, 25, 6, 10, 11, 26, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 2) // #41 -PAIRING(10, 20, 20, 25, 6, 10, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #42 -PAIRING(10, 20, 20, 25, 6, 10, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #43 -PAIRING(10, 20, 20, 25, 6, 10, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #44 -PAIRING(10, 20, 20, 25, 6, 10, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #45 -PAIRING(10, 20, 20, 25, 6, 10, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #46 -PAIRING(10, 20, 20, 25, 6, 10, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #47 -PAIRING(10, 20, 20, 25, 6, 10, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #48 -PAIRING(10, 20, 20, 25, 6, 10, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #49 -PAIRING(10, 20, 20, 25, 6, 11, 11, 12, 2, 0, 10, 11, 11, 12, 0, 0, 0, 0, 2, 1) // #50 -PAIRING(10, 20, 20, 25, 6, 11, 11, 20, 2, 0, 10, 11, 11, 20, 0, 0, 0, 0, 1, 1) // #51 -PAIRING(10, 20, 20, 25, 6, 11, 11, 21, 2, 1, 10, 11, 11, 20, 20, 21, 0, 0, 1, 1) // #52 -PAIRING(10, 20, 20, 25, 6, 11, 11, 25, 2, 1, 10, 11, 11, 20, 20, 25, 0, 0, 0, 1) // #53 -PAIRING(10, 20, 20, 25, 6, 11, 11, 26, 2, 1, 10, 11, 11, 20, 20, 25, 0, 0, 0, 2) // #54 -PAIRING(10, 20, 20, 25, 6, 11, 12, 13, 2, 0, 10, 11, 12, 13, 0, 0, 0, 0, 2, 1) // #55 -PAIRING(10, 20, 20, 25, 6, 11, 12, 20, 2, 0, 10, 11, 12, 20, 0, 0, 0, 0, 2, 1) // #56 -PAIRING(10, 20, 20, 25, 6, 11, 12, 21, 2, 1, 10, 11, 12, 20, 20, 21, 0, 0, 2, 1) // #57 -PAIRING(10, 20, 20, 25, 6, 11, 12, 25, 2, 1, 10, 11, 12, 20, 20, 25, 0, 0, 1, 1) // #58 -PAIRING(10, 20, 20, 25, 6, 11, 12, 26, 2, 1, 10, 11, 12, 20, 20, 25, 0, 0, 1, 2) // #59 -PAIRING(10, 20, 20, 25, 6, 11, 20, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 1) // #60 -PAIRING(10, 20, 20, 25, 6, 11, 20, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #61 -PAIRING(10, 20, 20, 25, 6, 11, 20, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #62 -PAIRING(10, 20, 20, 25, 6, 11, 21, 22, 1, 1, 10, 11, 0, 0, 21, 22, 0, 0, 2, 1) // #63 -PAIRING(10, 20, 20, 25, 6, 11, 21, 25, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 1) // #64 -PAIRING(10, 20, 20, 25, 6, 11, 21, 26, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 2) // #65 -PAIRING(10, 20, 20, 25, 6, 11, 25, 26, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #66 -PAIRING(10, 20, 20, 25, 6, 11, 26, 27, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #67 -PAIRING(10, 20, 20, 25, 6, 20, 20, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #68 -PAIRING(10, 20, 20, 25, 6, 20, 20, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #69 -PAIRING(10, 20, 20, 25, 6, 20, 20, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #70 -PAIRING(10, 20, 20, 25, 6, 20, 21, 22, 1, 1, 10, 20, 0, 0, 21, 22, 0, 0, 1, 1) // #71 -PAIRING(10, 20, 20, 25, 6, 20, 21, 25, 1, 1, 10, 20, 0, 0, 21, 25, 0, 0, 1, 1) // #72 -PAIRING(10, 20, 20, 25, 6, 20, 21, 26, 1, 1, 10, 20, 0, 0, 21, 25, 0, 0, 1, 2) // #73 -PAIRING(10, 20, 20, 25, 6, 20, 25, 26, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 2) // #74 -PAIRING(10, 20, 20, 25, 6, 20, 26, 27, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 2) // #75 -PAIRING(10, 20, 20, 25, 6, 21, 21, 22, 1, 2, 10, 20, 0, 0, 20, 21, 21, 22, 1, 1) // #76 -PAIRING(10, 20, 20, 25, 6, 21, 21, 25, 1, 2, 10, 20, 0, 0, 20, 21, 21, 25, 0, 1) // #77 -PAIRING(10, 20, 20, 25, 6, 21, 21, 26, 1, 2, 10, 20, 0, 0, 20, 21, 21, 25, 0, 2) // #78 -PAIRING(10, 20, 20, 25, 6, 21, 22, 23, 1, 2, 10, 20, 0, 0, 20, 21, 22, 23, 1, 1) // #79 -PAIRING(10, 20, 20, 25, 6, 21, 22, 25, 1, 2, 10, 20, 0, 0, 20, 21, 22, 25, 1, 1) // #80 -PAIRING(10, 20, 20, 25, 6, 21, 22, 26, 1, 2, 10, 20, 0, 0, 20, 21, 22, 25, 1, 2) // #81 -PAIRING(10, 20, 20, 25, 6, 21, 25, 26, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 2) // #82 -PAIRING(10, 20, 20, 25, 6, 21, 26, 27, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 2) // #83 -PAIRING(10, 20, 20, 25, 6, 25, 25, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #84 -PAIRING(10, 20, 20, 25, 6, 25, 26, 27, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #85 -PAIRING(10, 20, 20, 25, 6, 26, 26, 27, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #86 -PAIRING(10, 20, 20, 25, 6, 26, 27, 28, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #87 -PAIRING(10, 20, 20, 25, 10, 11, 11, 12, 2, 0, 10, 11, 11, 12, 0, 0, 0, 0, 2, 0) // #88 -PAIRING(10, 20, 20, 25, 10, 11, 11, 20, 2, 0, 10, 11, 11, 20, 0, 0, 0, 0, 1, 0) // #89 -PAIRING(10, 20, 20, 25, 10, 11, 11, 21, 2, 1, 10, 11, 11, 20, 20, 21, 0, 0, 1, 0) // #90 -PAIRING(10, 20, 20, 25, 10, 11, 11, 25, 2, 1, 10, 11, 11, 20, 20, 25, 0, 0, 0, 0) // #91 -PAIRING(10, 20, 20, 25, 10, 11, 11, 26, 2, 1, 10, 11, 11, 20, 20, 25, 0, 0, 0, 1) // #92 -PAIRING(10, 20, 20, 25, 10, 11, 12, 13, 2, 0, 10, 11, 12, 13, 0, 0, 0, 0, 2, 0) // #93 -PAIRING(10, 20, 20, 25, 10, 11, 12, 20, 2, 0, 10, 11, 12, 20, 0, 0, 0, 0, 2, 0) // #94 -PAIRING(10, 20, 20, 25, 10, 11, 12, 21, 2, 1, 10, 11, 12, 20, 20, 21, 0, 0, 2, 0) // #95 -PAIRING(10, 20, 20, 25, 10, 11, 12, 25, 2, 1, 10, 11, 12, 20, 20, 25, 0, 0, 1, 0) // #96 -PAIRING(10, 20, 20, 25, 10, 11, 12, 26, 2, 1, 10, 11, 12, 20, 20, 25, 0, 0, 1, 1) // #97 -PAIRING(10, 20, 20, 25, 10, 11, 20, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 0) // #98 -PAIRING(10, 20, 20, 25, 10, 11, 20, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 0) // #99 -PAIRING(10, 20, 20, 25, 10, 11, 20, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #100 -PAIRING(10, 20, 20, 25, 10, 11, 21, 22, 1, 1, 10, 11, 0, 0, 21, 22, 0, 0, 2, 0) // #101 -PAIRING(10, 20, 20, 25, 10, 11, 21, 25, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 0) // #102 -PAIRING(10, 20, 20, 25, 10, 11, 21, 26, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 1) // #103 -PAIRING(10, 20, 20, 25, 10, 11, 25, 26, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #104 -PAIRING(10, 20, 20, 25, 10, 11, 26, 27, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #105 -PAIRING(10, 20, 20, 25, 10, 20, 20, 21, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 0) // #106 -PAIRING(10, 20, 20, 25, 10, 20, 20, 25, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 0) // #107 -PAIRING(10, 20, 20, 25, 10, 20, 20, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #108 -PAIRING(10, 20, 20, 25, 10, 20, 21, 22, 1, 1, 10, 20, 0, 0, 21, 22, 0, 0, 1, 0) // #109 -PAIRING(10, 20, 20, 25, 10, 20, 21, 25, 1, 1, 10, 20, 0, 0, 21, 25, 0, 0, 1, 0) // #110 -PAIRING(10, 20, 20, 25, 10, 20, 21, 26, 1, 1, 10, 20, 0, 0, 21, 25, 0, 0, 1, 1) // #111 -PAIRING(10, 20, 20, 25, 10, 20, 25, 26, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 1) // #112 -PAIRING(10, 20, 20, 25, 10, 20, 26, 27, 1, 0, 10, 20, 0, 0, 0, 0, 0, 0, 1, 1) // #113 -PAIRING(10, 20, 20, 25, 10, 21, 21, 22, 1, 2, 10, 20, 0, 0, 20, 21, 21, 22, 1, 0) // #114 -PAIRING(10, 20, 20, 25, 10, 21, 21, 25, 1, 2, 10, 20, 0, 0, 20, 21, 21, 25, 0, 0) // #115 -PAIRING(10, 20, 20, 25, 10, 21, 21, 26, 1, 2, 10, 20, 0, 0, 20, 21, 21, 25, 0, 1) // #116 -PAIRING(10, 20, 20, 25, 10, 21, 22, 23, 1, 2, 10, 20, 0, 0, 20, 21, 22, 23, 1, 0) // #117 -PAIRING(10, 20, 20, 25, 10, 21, 22, 25, 1, 2, 10, 20, 0, 0, 20, 21, 22, 25, 1, 0) // #118 -PAIRING(10, 20, 20, 25, 10, 21, 22, 26, 1, 2, 10, 20, 0, 0, 20, 21, 22, 25, 1, 1) // #119 -PAIRING(10, 20, 20, 25, 10, 21, 25, 26, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #120 -PAIRING(10, 20, 20, 25, 10, 21, 26, 27, 1, 1, 10, 20, 0, 0, 20, 21, 0, 0, 1, 1) // #121 -PAIRING(10, 20, 20, 25, 10, 25, 25, 26, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #122 -PAIRING(10, 20, 20, 25, 10, 25, 26, 27, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 1) // #123 -PAIRING(10, 20, 20, 25, 10, 26, 26, 27, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #124 -PAIRING(10, 20, 20, 25, 10, 26, 27, 28, 1, 1, 10, 20, 0, 0, 20, 25, 0, 0, 0, 2) // #125 -PAIRING(10, 20, 20, 25, 11, 12, 12, 13, 2, 0, 11, 12, 12, 13, 0, 0, 0, 0, 2, 0) // #126 -PAIRING(10, 20, 20, 25, 11, 12, 12, 20, 2, 0, 11, 12, 12, 20, 0, 0, 0, 0, 2, 0) // #127 -PAIRING(10, 20, 20, 25, 11, 12, 12, 21, 2, 1, 11, 12, 12, 20, 20, 21, 0, 0, 2, 0) // #128 -PAIRING(10, 20, 20, 25, 11, 12, 12, 25, 2, 1, 11, 12, 12, 20, 20, 25, 0, 0, 1, 0) // #129 -PAIRING(10, 20, 20, 25, 11, 12, 12, 26, 2, 1, 11, 12, 12, 20, 20, 25, 0, 0, 1, 1) // #130 -PAIRING(10, 20, 20, 25, 11, 12, 13, 14, 2, 0, 11, 12, 13, 14, 0, 0, 0, 0, 2, 0) // #131 -PAIRING(10, 20, 20, 25, 11, 12, 13, 20, 2, 0, 11, 12, 13, 20, 0, 0, 0, 0, 2, 0) // #132 -PAIRING(10, 20, 20, 25, 11, 12, 13, 21, 2, 1, 11, 12, 13, 20, 20, 21, 0, 0, 2, 0) // #133 -PAIRING(10, 20, 20, 25, 11, 12, 13, 25, 2, 1, 11, 12, 13, 20, 20, 25, 0, 0, 1, 0) // #134 -PAIRING(10, 20, 20, 25, 11, 12, 13, 26, 2, 1, 11, 12, 13, 20, 20, 25, 0, 0, 1, 1) // #135 -PAIRING(10, 20, 20, 25, 11, 12, 20, 21, 1, 1, 11, 12, 0, 0, 20, 21, 0, 0, 2, 0) // #136 -PAIRING(10, 20, 20, 25, 11, 12, 20, 25, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 0) // #137 -PAIRING(10, 20, 20, 25, 11, 12, 20, 26, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #138 -PAIRING(10, 20, 20, 25, 11, 12, 21, 22, 1, 1, 11, 12, 0, 0, 21, 22, 0, 0, 2, 0) // #139 -PAIRING(10, 20, 20, 25, 11, 12, 21, 25, 1, 1, 11, 12, 0, 0, 21, 25, 0, 0, 2, 0) // #140 -PAIRING(10, 20, 20, 25, 11, 12, 21, 26, 1, 1, 11, 12, 0, 0, 21, 25, 0, 0, 2, 1) // #141 -PAIRING(10, 20, 20, 25, 11, 12, 25, 26, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #142 -PAIRING(10, 20, 20, 25, 11, 12, 26, 27, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #143 -PAIRING(10, 20, 20, 25, 11, 20, 20, 21, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 0) // #144 -PAIRING(10, 20, 20, 25, 11, 20, 20, 25, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 0) // #145 -PAIRING(10, 20, 20, 25, 11, 20, 20, 26, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #146 -PAIRING(10, 20, 20, 25, 11, 20, 21, 22, 1, 1, 11, 20, 0, 0, 21, 22, 0, 0, 2, 0) // #147 -PAIRING(10, 20, 20, 25, 11, 20, 21, 25, 1, 1, 11, 20, 0, 0, 21, 25, 0, 0, 2, 0) // #148 -PAIRING(10, 20, 20, 25, 11, 20, 21, 26, 1, 1, 11, 20, 0, 0, 21, 25, 0, 0, 2, 1) // #149 -PAIRING(10, 20, 20, 25, 11, 20, 25, 26, 1, 0, 11, 20, 0, 0, 0, 0, 0, 0, 2, 1) // #150 -PAIRING(10, 20, 20, 25, 11, 20, 26, 27, 1, 0, 11, 20, 0, 0, 0, 0, 0, 0, 2, 1) // #151 -PAIRING(10, 20, 20, 25, 11, 21, 21, 22, 1, 2, 11, 20, 0, 0, 20, 21, 21, 22, 2, 0) // #152 -PAIRING(10, 20, 20, 25, 11, 21, 21, 25, 1, 2, 11, 20, 0, 0, 20, 21, 21, 25, 1, 0) // #153 -PAIRING(10, 20, 20, 25, 11, 21, 21, 26, 1, 2, 11, 20, 0, 0, 20, 21, 21, 25, 1, 1) // #154 -PAIRING(10, 20, 20, 25, 11, 21, 22, 23, 1, 2, 11, 20, 0, 0, 20, 21, 22, 23, 2, 0) // #155 -PAIRING(10, 20, 20, 25, 11, 21, 22, 25, 1, 2, 11, 20, 0, 0, 20, 21, 22, 25, 2, 0) // #156 -PAIRING(10, 20, 20, 25, 11, 21, 22, 26, 1, 2, 11, 20, 0, 0, 20, 21, 22, 25, 2, 1) // #157 -PAIRING(10, 20, 20, 25, 11, 21, 25, 26, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 1) // #158 -PAIRING(10, 20, 20, 25, 11, 21, 26, 27, 1, 1, 11, 20, 0, 0, 20, 21, 0, 0, 2, 1) // #159 -PAIRING(10, 20, 20, 25, 11, 25, 25, 26, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #160 -PAIRING(10, 20, 20, 25, 11, 25, 26, 27, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 1) // #161 -PAIRING(10, 20, 20, 25, 11, 26, 26, 27, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 2) // #162 -PAIRING(10, 20, 20, 25, 11, 26, 27, 28, 1, 1, 11, 20, 0, 0, 20, 25, 0, 0, 1, 2) // #163 -PAIRING(10, 20, 20, 25, 20, 21, 21, 22, 0, 2, 0, 0, 0, 0, 20, 21, 21, 22, 2, 0) // #164 -PAIRING(10, 20, 20, 25, 20, 21, 21, 25, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 0) // #165 -PAIRING(10, 20, 20, 25, 20, 21, 21, 26, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 1) // #166 -PAIRING(10, 20, 20, 25, 20, 21, 22, 23, 0, 2, 0, 0, 0, 0, 20, 21, 22, 23, 2, 0) // #167 -PAIRING(10, 20, 20, 25, 20, 21, 22, 25, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 0) // #168 -PAIRING(10, 20, 20, 25, 20, 21, 22, 26, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 1) // #169 -PAIRING(10, 20, 20, 25, 20, 21, 25, 26, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #170 -PAIRING(10, 20, 20, 25, 20, 21, 26, 27, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #171 -PAIRING(10, 20, 20, 25, 20, 25, 25, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #172 -PAIRING(10, 20, 20, 25, 20, 25, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #173 -PAIRING(10, 20, 20, 25, 20, 26, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #174 -PAIRING(10, 20, 20, 25, 20, 26, 27, 28, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #175 -PAIRING(10, 20, 20, 25, 21, 22, 22, 23, 0, 2, 0, 0, 0, 0, 21, 22, 22, 23, 2, 0) // #176 -PAIRING(10, 20, 20, 25, 21, 22, 22, 25, 0, 2, 0, 0, 0, 0, 21, 22, 22, 25, 2, 0) // #177 -PAIRING(10, 20, 20, 25, 21, 22, 22, 26, 0, 2, 0, 0, 0, 0, 21, 22, 22, 25, 2, 1) // #178 -PAIRING(10, 20, 20, 25, 21, 22, 23, 24, 0, 2, 0, 0, 0, 0, 21, 22, 23, 24, 2, 0) // #179 -PAIRING(10, 20, 20, 25, 21, 22, 23, 25, 0, 2, 0, 0, 0, 0, 21, 22, 23, 25, 2, 0) // #180 -PAIRING(10, 20, 20, 25, 21, 22, 23, 26, 0, 2, 0, 0, 0, 0, 21, 22, 23, 25, 2, 1) // #181 -PAIRING(10, 20, 20, 25, 21, 22, 25, 26, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #182 -PAIRING(10, 20, 20, 25, 21, 22, 26, 27, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #183 -PAIRING(10, 20, 20, 25, 21, 25, 25, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #184 -PAIRING(10, 20, 20, 25, 21, 25, 26, 27, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #185 -PAIRING(10, 20, 20, 25, 21, 26, 26, 27, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #186 -PAIRING(10, 20, 20, 25, 21, 26, 27, 28, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #187 -PAIRING(10, 20, 20, 25, 25, 26, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #188 -PAIRING(10, 20, 20, 25, 25, 26, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #189 -PAIRING(10, 20, 20, 25, 26, 27, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #190 -PAIRING(10, 20, 20, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #191 -PAIRING(10, 15, 20, 25, 6, 7, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #192 -PAIRING(10, 15, 20, 25, 6, 7, 7, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #193 -PAIRING(10, 15, 20, 25, 6, 7, 7, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #194 -PAIRING(10, 15, 20, 25, 6, 7, 7, 15, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #195 -PAIRING(10, 15, 20, 25, 6, 7, 7, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #196 -PAIRING(10, 15, 20, 25, 6, 7, 7, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #197 -PAIRING(10, 15, 20, 25, 6, 7, 7, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #198 -PAIRING(10, 15, 20, 25, 6, 7, 7, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #199 -PAIRING(10, 15, 20, 25, 6, 7, 7, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #200 -PAIRING(10, 15, 20, 25, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #201 -PAIRING(10, 15, 20, 25, 6, 7, 8, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #202 -PAIRING(10, 15, 20, 25, 6, 7, 8, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #203 -PAIRING(10, 15, 20, 25, 6, 7, 8, 15, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #204 -PAIRING(10, 15, 20, 25, 6, 7, 8, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #205 -PAIRING(10, 15, 20, 25, 6, 7, 8, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #206 -PAIRING(10, 15, 20, 25, 6, 7, 8, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #207 -PAIRING(10, 15, 20, 25, 6, 7, 8, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #208 -PAIRING(10, 15, 20, 25, 6, 7, 8, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #209 -PAIRING(10, 15, 20, 25, 6, 7, 10, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #210 -PAIRING(10, 15, 20, 25, 6, 7, 10, 15, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #211 -PAIRING(10, 15, 20, 25, 6, 7, 10, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #212 -PAIRING(10, 15, 20, 25, 6, 7, 10, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #213 -PAIRING(10, 15, 20, 25, 6, 7, 10, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #214 -PAIRING(10, 15, 20, 25, 6, 7, 10, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #215 -PAIRING(10, 15, 20, 25, 6, 7, 10, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #216 -PAIRING(10, 15, 20, 25, 6, 7, 11, 12, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #217 -PAIRING(10, 15, 20, 25, 6, 7, 11, 15, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #218 -PAIRING(10, 15, 20, 25, 6, 7, 11, 16, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #219 -PAIRING(10, 15, 20, 25, 6, 7, 11, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #220 -PAIRING(10, 15, 20, 25, 6, 7, 11, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #221 -PAIRING(10, 15, 20, 25, 6, 7, 11, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #222 -PAIRING(10, 15, 20, 25, 6, 7, 11, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #223 -PAIRING(10, 15, 20, 25, 6, 7, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #224 -PAIRING(10, 15, 20, 25, 6, 7, 15, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #225 -PAIRING(10, 15, 20, 25, 6, 7, 15, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #226 -PAIRING(10, 15, 20, 25, 6, 7, 15, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #227 -PAIRING(10, 15, 20, 25, 6, 7, 15, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #228 -PAIRING(10, 15, 20, 25, 6, 7, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #229 -PAIRING(10, 15, 20, 25, 6, 7, 16, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #230 -PAIRING(10, 15, 20, 25, 6, 7, 16, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #231 -PAIRING(10, 15, 20, 25, 6, 7, 16, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #232 -PAIRING(10, 15, 20, 25, 6, 7, 16, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #233 -PAIRING(10, 15, 20, 25, 6, 7, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #234 -PAIRING(10, 15, 20, 25, 6, 7, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #235 -PAIRING(10, 15, 20, 25, 6, 7, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #236 -PAIRING(10, 15, 20, 25, 6, 7, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #237 -PAIRING(10, 15, 20, 25, 6, 7, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #238 -PAIRING(10, 15, 20, 25, 6, 7, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #239 -PAIRING(10, 15, 20, 25, 6, 7, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #240 -PAIRING(10, 15, 20, 25, 6, 7, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #241 -PAIRING(10, 15, 20, 25, 6, 10, 10, 11, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #242 -PAIRING(10, 15, 20, 25, 6, 10, 10, 15, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #243 -PAIRING(10, 15, 20, 25, 6, 10, 10, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #244 -PAIRING(10, 15, 20, 25, 6, 10, 10, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #245 -PAIRING(10, 15, 20, 25, 6, 10, 10, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #246 -PAIRING(10, 15, 20, 25, 6, 10, 10, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #247 -PAIRING(10, 15, 20, 25, 6, 10, 10, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #248 -PAIRING(10, 15, 20, 25, 6, 10, 11, 12, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #249 -PAIRING(10, 15, 20, 25, 6, 10, 11, 15, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #250 -PAIRING(10, 15, 20, 25, 6, 10, 11, 16, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #251 -PAIRING(10, 15, 20, 25, 6, 10, 11, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #252 -PAIRING(10, 15, 20, 25, 6, 10, 11, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #253 -PAIRING(10, 15, 20, 25, 6, 10, 11, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #254 -PAIRING(10, 15, 20, 25, 6, 10, 11, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #255 -PAIRING(10, 15, 20, 25, 6, 10, 15, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #256 -PAIRING(10, 15, 20, 25, 6, 10, 15, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #257 -PAIRING(10, 15, 20, 25, 6, 10, 15, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #258 -PAIRING(10, 15, 20, 25, 6, 10, 15, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #259 -PAIRING(10, 15, 20, 25, 6, 10, 15, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #260 -PAIRING(10, 15, 20, 25, 6, 10, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #261 -PAIRING(10, 15, 20, 25, 6, 10, 16, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #262 -PAIRING(10, 15, 20, 25, 6, 10, 16, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #263 -PAIRING(10, 15, 20, 25, 6, 10, 16, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #264 -PAIRING(10, 15, 20, 25, 6, 10, 16, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #265 -PAIRING(10, 15, 20, 25, 6, 10, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #266 -PAIRING(10, 15, 20, 25, 6, 10, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #267 -PAIRING(10, 15, 20, 25, 6, 10, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #268 -PAIRING(10, 15, 20, 25, 6, 10, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #269 -PAIRING(10, 15, 20, 25, 6, 10, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #270 -PAIRING(10, 15, 20, 25, 6, 10, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #271 -PAIRING(10, 15, 20, 25, 6, 10, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #272 -PAIRING(10, 15, 20, 25, 6, 10, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #273 -PAIRING(10, 15, 20, 25, 6, 11, 11, 12, 2, 0, 10, 11, 11, 12, 0, 0, 0, 0, 2, 1) // #274 -PAIRING(10, 15, 20, 25, 6, 11, 11, 15, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 1) // #275 -PAIRING(10, 15, 20, 25, 6, 11, 11, 16, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 2) // #276 -PAIRING(10, 15, 20, 25, 6, 11, 11, 20, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 1) // #277 -PAIRING(10, 15, 20, 25, 6, 11, 11, 21, 2, 1, 10, 11, 11, 15, 20, 21, 0, 0, 1, 2) // #278 -PAIRING(10, 15, 20, 25, 6, 11, 11, 25, 2, 1, 10, 11, 11, 15, 20, 25, 0, 0, 0, 2) // #279 -PAIRING(10, 15, 20, 25, 6, 11, 11, 26, 2, 1, 10, 11, 11, 15, 20, 25, 0, 0, 0, 2) // #280 -PAIRING(10, 15, 20, 25, 6, 11, 12, 13, 2, 0, 10, 11, 12, 13, 0, 0, 0, 0, 2, 1) // #281 -PAIRING(10, 15, 20, 25, 6, 11, 12, 15, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 1) // #282 -PAIRING(10, 15, 20, 25, 6, 11, 12, 16, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 2) // #283 -PAIRING(10, 15, 20, 25, 6, 11, 12, 20, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 1) // #284 -PAIRING(10, 15, 20, 25, 6, 11, 12, 21, 2, 1, 10, 11, 12, 15, 20, 21, 0, 0, 2, 2) // #285 -PAIRING(10, 15, 20, 25, 6, 11, 12, 25, 2, 1, 10, 11, 12, 15, 20, 25, 0, 0, 1, 2) // #286 -PAIRING(10, 15, 20, 25, 6, 11, 12, 26, 2, 1, 10, 11, 12, 15, 20, 25, 0, 0, 1, 2) // #287 -PAIRING(10, 15, 20, 25, 6, 11, 15, 16, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #288 -PAIRING(10, 15, 20, 25, 6, 11, 15, 20, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #289 -PAIRING(10, 15, 20, 25, 6, 11, 15, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 2) // #290 -PAIRING(10, 15, 20, 25, 6, 11, 15, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #291 -PAIRING(10, 15, 20, 25, 6, 11, 15, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #292 -PAIRING(10, 15, 20, 25, 6, 11, 16, 17, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #293 -PAIRING(10, 15, 20, 25, 6, 11, 16, 20, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #294 -PAIRING(10, 15, 20, 25, 6, 11, 16, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 2) // #295 -PAIRING(10, 15, 20, 25, 6, 11, 16, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #296 -PAIRING(10, 15, 20, 25, 6, 11, 16, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #297 -PAIRING(10, 15, 20, 25, 6, 11, 20, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 1) // #298 -PAIRING(10, 15, 20, 25, 6, 11, 20, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #299 -PAIRING(10, 15, 20, 25, 6, 11, 20, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 2) // #300 -PAIRING(10, 15, 20, 25, 6, 11, 21, 22, 1, 1, 10, 11, 0, 0, 21, 22, 0, 0, 2, 1) // #301 -PAIRING(10, 15, 20, 25, 6, 11, 21, 25, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 1) // #302 -PAIRING(10, 15, 20, 25, 6, 11, 21, 26, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 2) // #303 -PAIRING(10, 15, 20, 25, 6, 11, 25, 26, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #304 -PAIRING(10, 15, 20, 25, 6, 11, 26, 27, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 2) // #305 -PAIRING(10, 15, 20, 25, 6, 15, 15, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #306 -PAIRING(10, 15, 20, 25, 6, 15, 15, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #307 -PAIRING(10, 15, 20, 25, 6, 15, 15, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #308 -PAIRING(10, 15, 20, 25, 6, 15, 15, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #309 -PAIRING(10, 15, 20, 25, 6, 15, 15, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #310 -PAIRING(10, 15, 20, 25, 6, 15, 16, 17, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #311 -PAIRING(10, 15, 20, 25, 6, 15, 16, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #312 -PAIRING(10, 15, 20, 25, 6, 15, 16, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #313 -PAIRING(10, 15, 20, 25, 6, 15, 16, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #314 -PAIRING(10, 15, 20, 25, 6, 15, 16, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #315 -PAIRING(10, 15, 20, 25, 6, 15, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #316 -PAIRING(10, 15, 20, 25, 6, 15, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #317 -PAIRING(10, 15, 20, 25, 6, 15, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #318 -PAIRING(10, 15, 20, 25, 6, 15, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 1) // #319 -PAIRING(10, 15, 20, 25, 6, 15, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #320 -PAIRING(10, 15, 20, 25, 6, 15, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 2) // #321 -PAIRING(10, 15, 20, 25, 6, 15, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #322 -PAIRING(10, 15, 20, 25, 6, 15, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #323 -PAIRING(10, 15, 20, 25, 6, 16, 16, 17, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #324 -PAIRING(10, 15, 20, 25, 6, 16, 16, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #325 -PAIRING(10, 15, 20, 25, 6, 16, 16, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #326 -PAIRING(10, 15, 20, 25, 6, 16, 16, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #327 -PAIRING(10, 15, 20, 25, 6, 16, 16, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #328 -PAIRING(10, 15, 20, 25, 6, 16, 17, 18, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #329 -PAIRING(10, 15, 20, 25, 6, 16, 17, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #330 -PAIRING(10, 15, 20, 25, 6, 16, 17, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #331 -PAIRING(10, 15, 20, 25, 6, 16, 17, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #332 -PAIRING(10, 15, 20, 25, 6, 16, 17, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #333 -PAIRING(10, 15, 20, 25, 6, 16, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #334 -PAIRING(10, 15, 20, 25, 6, 16, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #335 -PAIRING(10, 15, 20, 25, 6, 16, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #336 -PAIRING(10, 15, 20, 25, 6, 16, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 1) // #337 -PAIRING(10, 15, 20, 25, 6, 16, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #338 -PAIRING(10, 15, 20, 25, 6, 16, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 2) // #339 -PAIRING(10, 15, 20, 25, 6, 16, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #340 -PAIRING(10, 15, 20, 25, 6, 16, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #341 -PAIRING(10, 15, 20, 25, 6, 20, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #342 -PAIRING(10, 15, 20, 25, 6, 20, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #343 -PAIRING(10, 15, 20, 25, 6, 20, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #344 -PAIRING(10, 15, 20, 25, 6, 20, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 1) // #345 -PAIRING(10, 15, 20, 25, 6, 20, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #346 -PAIRING(10, 15, 20, 25, 6, 20, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 2) // #347 -PAIRING(10, 15, 20, 25, 6, 20, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #348 -PAIRING(10, 15, 20, 25, 6, 20, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #349 -PAIRING(10, 15, 20, 25, 6, 21, 21, 22, 1, 2, 10, 15, 0, 0, 20, 21, 21, 22, 1, 1) // #350 -PAIRING(10, 15, 20, 25, 6, 21, 21, 25, 1, 2, 10, 15, 0, 0, 20, 21, 21, 25, 0, 1) // #351 -PAIRING(10, 15, 20, 25, 6, 21, 21, 26, 1, 2, 10, 15, 0, 0, 20, 21, 21, 25, 0, 2) // #352 -PAIRING(10, 15, 20, 25, 6, 21, 22, 23, 1, 2, 10, 15, 0, 0, 20, 21, 22, 23, 1, 1) // #353 -PAIRING(10, 15, 20, 25, 6, 21, 22, 25, 1, 2, 10, 15, 0, 0, 20, 21, 22, 25, 1, 1) // #354 -PAIRING(10, 15, 20, 25, 6, 21, 22, 26, 1, 2, 10, 15, 0, 0, 20, 21, 22, 25, 1, 2) // #355 -PAIRING(10, 15, 20, 25, 6, 21, 25, 26, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #356 -PAIRING(10, 15, 20, 25, 6, 21, 26, 27, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #357 -PAIRING(10, 15, 20, 25, 6, 25, 25, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #358 -PAIRING(10, 15, 20, 25, 6, 25, 26, 27, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #359 -PAIRING(10, 15, 20, 25, 6, 26, 26, 27, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #360 -PAIRING(10, 15, 20, 25, 6, 26, 27, 28, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #361 -PAIRING(10, 15, 20, 25, 10, 11, 11, 12, 2, 0, 10, 11, 11, 12, 0, 0, 0, 0, 2, 0) // #362 -PAIRING(10, 15, 20, 25, 10, 11, 11, 15, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 0) // #363 -PAIRING(10, 15, 20, 25, 10, 11, 11, 16, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 1) // #364 -PAIRING(10, 15, 20, 25, 10, 11, 11, 20, 2, 0, 10, 11, 11, 15, 0, 0, 0, 0, 1, 0) // #365 -PAIRING(10, 15, 20, 25, 10, 11, 11, 21, 2, 1, 10, 11, 11, 15, 20, 21, 0, 0, 1, 1) // #366 -PAIRING(10, 15, 20, 25, 10, 11, 11, 25, 2, 1, 10, 11, 11, 15, 20, 25, 0, 0, 0, 1) // #367 -PAIRING(10, 15, 20, 25, 10, 11, 11, 26, 2, 1, 10, 11, 11, 15, 20, 25, 0, 0, 0, 1) // #368 -PAIRING(10, 15, 20, 25, 10, 11, 12, 13, 2, 0, 10, 11, 12, 13, 0, 0, 0, 0, 2, 0) // #369 -PAIRING(10, 15, 20, 25, 10, 11, 12, 15, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 0) // #370 -PAIRING(10, 15, 20, 25, 10, 11, 12, 16, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 1) // #371 -PAIRING(10, 15, 20, 25, 10, 11, 12, 20, 2, 0, 10, 11, 12, 15, 0, 0, 0, 0, 2, 0) // #372 -PAIRING(10, 15, 20, 25, 10, 11, 12, 21, 2, 1, 10, 11, 12, 15, 20, 21, 0, 0, 2, 1) // #373 -PAIRING(10, 15, 20, 25, 10, 11, 12, 25, 2, 1, 10, 11, 12, 15, 20, 25, 0, 0, 1, 1) // #374 -PAIRING(10, 15, 20, 25, 10, 11, 12, 26, 2, 1, 10, 11, 12, 15, 20, 25, 0, 0, 1, 1) // #375 -PAIRING(10, 15, 20, 25, 10, 11, 15, 16, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #376 -PAIRING(10, 15, 20, 25, 10, 11, 15, 20, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #377 -PAIRING(10, 15, 20, 25, 10, 11, 15, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 1) // #378 -PAIRING(10, 15, 20, 25, 10, 11, 15, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #379 -PAIRING(10, 15, 20, 25, 10, 11, 15, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #380 -PAIRING(10, 15, 20, 25, 10, 11, 16, 17, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #381 -PAIRING(10, 15, 20, 25, 10, 11, 16, 20, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #382 -PAIRING(10, 15, 20, 25, 10, 11, 16, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 1) // #383 -PAIRING(10, 15, 20, 25, 10, 11, 16, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #384 -PAIRING(10, 15, 20, 25, 10, 11, 16, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #385 -PAIRING(10, 15, 20, 25, 10, 11, 20, 21, 1, 1, 10, 11, 0, 0, 20, 21, 0, 0, 2, 0) // #386 -PAIRING(10, 15, 20, 25, 10, 11, 20, 25, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 0) // #387 -PAIRING(10, 15, 20, 25, 10, 11, 20, 26, 1, 1, 10, 11, 0, 0, 20, 25, 0, 0, 1, 1) // #388 -PAIRING(10, 15, 20, 25, 10, 11, 21, 22, 1, 1, 10, 11, 0, 0, 21, 22, 0, 0, 2, 0) // #389 -PAIRING(10, 15, 20, 25, 10, 11, 21, 25, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 0) // #390 -PAIRING(10, 15, 20, 25, 10, 11, 21, 26, 1, 1, 10, 11, 0, 0, 21, 25, 0, 0, 2, 1) // #391 -PAIRING(10, 15, 20, 25, 10, 11, 25, 26, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #392 -PAIRING(10, 15, 20, 25, 10, 11, 26, 27, 1, 0, 10, 11, 0, 0, 0, 0, 0, 0, 2, 1) // #393 -PAIRING(10, 15, 20, 25, 10, 15, 15, 16, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #394 -PAIRING(10, 15, 20, 25, 10, 15, 15, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #395 -PAIRING(10, 15, 20, 25, 10, 15, 15, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #396 -PAIRING(10, 15, 20, 25, 10, 15, 15, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #397 -PAIRING(10, 15, 20, 25, 10, 15, 15, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #398 -PAIRING(10, 15, 20, 25, 10, 15, 16, 17, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #399 -PAIRING(10, 15, 20, 25, 10, 15, 16, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #400 -PAIRING(10, 15, 20, 25, 10, 15, 16, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #401 -PAIRING(10, 15, 20, 25, 10, 15, 16, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #402 -PAIRING(10, 15, 20, 25, 10, 15, 16, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #403 -PAIRING(10, 15, 20, 25, 10, 15, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 0) // #404 -PAIRING(10, 15, 20, 25, 10, 15, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 0) // #405 -PAIRING(10, 15, 20, 25, 10, 15, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #406 -PAIRING(10, 15, 20, 25, 10, 15, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 0) // #407 -PAIRING(10, 15, 20, 25, 10, 15, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 0) // #408 -PAIRING(10, 15, 20, 25, 10, 15, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #409 -PAIRING(10, 15, 20, 25, 10, 15, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #410 -PAIRING(10, 15, 20, 25, 10, 15, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #411 -PAIRING(10, 15, 20, 25, 10, 16, 16, 17, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #412 -PAIRING(10, 15, 20, 25, 10, 16, 16, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #413 -PAIRING(10, 15, 20, 25, 10, 16, 16, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #414 -PAIRING(10, 15, 20, 25, 10, 16, 16, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #415 -PAIRING(10, 15, 20, 25, 10, 16, 16, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #416 -PAIRING(10, 15, 20, 25, 10, 16, 17, 18, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #417 -PAIRING(10, 15, 20, 25, 10, 16, 17, 20, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #418 -PAIRING(10, 15, 20, 25, 10, 16, 17, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #419 -PAIRING(10, 15, 20, 25, 10, 16, 17, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #420 -PAIRING(10, 15, 20, 25, 10, 16, 17, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #421 -PAIRING(10, 15, 20, 25, 10, 16, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 1) // #422 -PAIRING(10, 15, 20, 25, 10, 16, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #423 -PAIRING(10, 15, 20, 25, 10, 16, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #424 -PAIRING(10, 15, 20, 25, 10, 16, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 1) // #425 -PAIRING(10, 15, 20, 25, 10, 16, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #426 -PAIRING(10, 15, 20, 25, 10, 16, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 2) // #427 -PAIRING(10, 15, 20, 25, 10, 16, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #428 -PAIRING(10, 15, 20, 25, 10, 16, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 2) // #429 -PAIRING(10, 15, 20, 25, 10, 20, 20, 21, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 0) // #430 -PAIRING(10, 15, 20, 25, 10, 20, 20, 25, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 0) // #431 -PAIRING(10, 15, 20, 25, 10, 20, 20, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 1) // #432 -PAIRING(10, 15, 20, 25, 10, 20, 21, 22, 1, 1, 10, 15, 0, 0, 21, 22, 0, 0, 1, 0) // #433 -PAIRING(10, 15, 20, 25, 10, 20, 21, 25, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 0) // #434 -PAIRING(10, 15, 20, 25, 10, 20, 21, 26, 1, 1, 10, 15, 0, 0, 21, 25, 0, 0, 1, 1) // #435 -PAIRING(10, 15, 20, 25, 10, 20, 25, 26, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #436 -PAIRING(10, 15, 20, 25, 10, 20, 26, 27, 1, 0, 10, 15, 0, 0, 0, 0, 0, 0, 1, 1) // #437 -PAIRING(10, 15, 20, 25, 10, 21, 21, 22, 1, 2, 10, 15, 0, 0, 20, 21, 21, 22, 1, 1) // #438 -PAIRING(10, 15, 20, 25, 10, 21, 21, 25, 1, 2, 10, 15, 0, 0, 20, 21, 21, 25, 0, 1) // #439 -PAIRING(10, 15, 20, 25, 10, 21, 21, 26, 1, 2, 10, 15, 0, 0, 20, 21, 21, 25, 0, 2) // #440 -PAIRING(10, 15, 20, 25, 10, 21, 22, 23, 1, 2, 10, 15, 0, 0, 20, 21, 22, 23, 1, 1) // #441 -PAIRING(10, 15, 20, 25, 10, 21, 22, 25, 1, 2, 10, 15, 0, 0, 20, 21, 22, 25, 1, 1) // #442 -PAIRING(10, 15, 20, 25, 10, 21, 22, 26, 1, 2, 10, 15, 0, 0, 20, 21, 22, 25, 1, 2) // #443 -PAIRING(10, 15, 20, 25, 10, 21, 25, 26, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #444 -PAIRING(10, 15, 20, 25, 10, 21, 26, 27, 1, 1, 10, 15, 0, 0, 20, 21, 0, 0, 1, 2) // #445 -PAIRING(10, 15, 20, 25, 10, 25, 25, 26, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #446 -PAIRING(10, 15, 20, 25, 10, 25, 26, 27, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #447 -PAIRING(10, 15, 20, 25, 10, 26, 26, 27, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #448 -PAIRING(10, 15, 20, 25, 10, 26, 27, 28, 1, 1, 10, 15, 0, 0, 20, 25, 0, 0, 0, 2) // #449 -PAIRING(10, 15, 20, 25, 11, 12, 12, 13, 2, 0, 11, 12, 12, 13, 0, 0, 0, 0, 2, 0) // #450 -PAIRING(10, 15, 20, 25, 11, 12, 12, 15, 2, 0, 11, 12, 12, 15, 0, 0, 0, 0, 2, 0) // #451 -PAIRING(10, 15, 20, 25, 11, 12, 12, 16, 2, 0, 11, 12, 12, 15, 0, 0, 0, 0, 2, 1) // #452 -PAIRING(10, 15, 20, 25, 11, 12, 12, 20, 2, 0, 11, 12, 12, 15, 0, 0, 0, 0, 2, 0) // #453 -PAIRING(10, 15, 20, 25, 11, 12, 12, 21, 2, 1, 11, 12, 12, 15, 20, 21, 0, 0, 2, 1) // #454 -PAIRING(10, 15, 20, 25, 11, 12, 12, 25, 2, 1, 11, 12, 12, 15, 20, 25, 0, 0, 1, 1) // #455 -PAIRING(10, 15, 20, 25, 11, 12, 12, 26, 2, 1, 11, 12, 12, 15, 20, 25, 0, 0, 1, 1) // #456 -PAIRING(10, 15, 20, 25, 11, 12, 13, 14, 2, 0, 11, 12, 13, 14, 0, 0, 0, 0, 2, 0) // #457 -PAIRING(10, 15, 20, 25, 11, 12, 13, 15, 2, 0, 11, 12, 13, 15, 0, 0, 0, 0, 2, 0) // #458 -PAIRING(10, 15, 20, 25, 11, 12, 13, 16, 2, 0, 11, 12, 13, 15, 0, 0, 0, 0, 2, 1) // #459 -PAIRING(10, 15, 20, 25, 11, 12, 13, 20, 2, 0, 11, 12, 13, 15, 0, 0, 0, 0, 2, 0) // #460 -PAIRING(10, 15, 20, 25, 11, 12, 13, 21, 2, 1, 11, 12, 13, 15, 20, 21, 0, 0, 2, 1) // #461 -PAIRING(10, 15, 20, 25, 11, 12, 13, 25, 2, 1, 11, 12, 13, 15, 20, 25, 0, 0, 1, 1) // #462 -PAIRING(10, 15, 20, 25, 11, 12, 13, 26, 2, 1, 11, 12, 13, 15, 20, 25, 0, 0, 1, 1) // #463 -PAIRING(10, 15, 20, 25, 11, 12, 15, 16, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #464 -PAIRING(10, 15, 20, 25, 11, 12, 15, 20, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #465 -PAIRING(10, 15, 20, 25, 11, 12, 15, 21, 1, 1, 11, 12, 0, 0, 20, 21, 0, 0, 2, 1) // #466 -PAIRING(10, 15, 20, 25, 11, 12, 15, 25, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #467 -PAIRING(10, 15, 20, 25, 11, 12, 15, 26, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #468 -PAIRING(10, 15, 20, 25, 11, 12, 16, 17, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #469 -PAIRING(10, 15, 20, 25, 11, 12, 16, 20, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #470 -PAIRING(10, 15, 20, 25, 11, 12, 16, 21, 1, 1, 11, 12, 0, 0, 20, 21, 0, 0, 2, 1) // #471 -PAIRING(10, 15, 20, 25, 11, 12, 16, 25, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #472 -PAIRING(10, 15, 20, 25, 11, 12, 16, 26, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #473 -PAIRING(10, 15, 20, 25, 11, 12, 20, 21, 1, 1, 11, 12, 0, 0, 20, 21, 0, 0, 2, 0) // #474 -PAIRING(10, 15, 20, 25, 11, 12, 20, 25, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 0) // #475 -PAIRING(10, 15, 20, 25, 11, 12, 20, 26, 1, 1, 11, 12, 0, 0, 20, 25, 0, 0, 1, 1) // #476 -PAIRING(10, 15, 20, 25, 11, 12, 21, 22, 1, 1, 11, 12, 0, 0, 21, 22, 0, 0, 2, 0) // #477 -PAIRING(10, 15, 20, 25, 11, 12, 21, 25, 1, 1, 11, 12, 0, 0, 21, 25, 0, 0, 2, 0) // #478 -PAIRING(10, 15, 20, 25, 11, 12, 21, 26, 1, 1, 11, 12, 0, 0, 21, 25, 0, 0, 2, 1) // #479 -PAIRING(10, 15, 20, 25, 11, 12, 25, 26, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #480 -PAIRING(10, 15, 20, 25, 11, 12, 26, 27, 1, 0, 11, 12, 0, 0, 0, 0, 0, 0, 2, 1) // #481 -PAIRING(10, 15, 20, 25, 11, 15, 15, 16, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #482 -PAIRING(10, 15, 20, 25, 11, 15, 15, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #483 -PAIRING(10, 15, 20, 25, 11, 15, 15, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 1) // #484 -PAIRING(10, 15, 20, 25, 11, 15, 15, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #485 -PAIRING(10, 15, 20, 25, 11, 15, 15, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #486 -PAIRING(10, 15, 20, 25, 11, 15, 16, 17, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #487 -PAIRING(10, 15, 20, 25, 11, 15, 16, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #488 -PAIRING(10, 15, 20, 25, 11, 15, 16, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 1) // #489 -PAIRING(10, 15, 20, 25, 11, 15, 16, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #490 -PAIRING(10, 15, 20, 25, 11, 15, 16, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #491 -PAIRING(10, 15, 20, 25, 11, 15, 20, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 0) // #492 -PAIRING(10, 15, 20, 25, 11, 15, 20, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 0) // #493 -PAIRING(10, 15, 20, 25, 11, 15, 20, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #494 -PAIRING(10, 15, 20, 25, 11, 15, 21, 22, 1, 1, 11, 15, 0, 0, 21, 22, 0, 0, 2, 0) // #495 -PAIRING(10, 15, 20, 25, 11, 15, 21, 25, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 0) // #496 -PAIRING(10, 15, 20, 25, 11, 15, 21, 26, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 1) // #497 -PAIRING(10, 15, 20, 25, 11, 15, 25, 26, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #498 -PAIRING(10, 15, 20, 25, 11, 15, 26, 27, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #499 -PAIRING(10, 15, 20, 25, 11, 16, 16, 17, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #500 -PAIRING(10, 15, 20, 25, 11, 16, 16, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #501 -PAIRING(10, 15, 20, 25, 11, 16, 16, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #502 -PAIRING(10, 15, 20, 25, 11, 16, 16, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #503 -PAIRING(10, 15, 20, 25, 11, 16, 16, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #504 -PAIRING(10, 15, 20, 25, 11, 16, 17, 18, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #505 -PAIRING(10, 15, 20, 25, 11, 16, 17, 20, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #506 -PAIRING(10, 15, 20, 25, 11, 16, 17, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #507 -PAIRING(10, 15, 20, 25, 11, 16, 17, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #508 -PAIRING(10, 15, 20, 25, 11, 16, 17, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #509 -PAIRING(10, 15, 20, 25, 11, 16, 20, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 1) // #510 -PAIRING(10, 15, 20, 25, 11, 16, 20, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #511 -PAIRING(10, 15, 20, 25, 11, 16, 20, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #512 -PAIRING(10, 15, 20, 25, 11, 16, 21, 22, 1, 1, 11, 15, 0, 0, 21, 22, 0, 0, 2, 1) // #513 -PAIRING(10, 15, 20, 25, 11, 16, 21, 25, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 1) // #514 -PAIRING(10, 15, 20, 25, 11, 16, 21, 26, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 2) // #515 -PAIRING(10, 15, 20, 25, 11, 16, 25, 26, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #516 -PAIRING(10, 15, 20, 25, 11, 16, 26, 27, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 2) // #517 -PAIRING(10, 15, 20, 25, 11, 20, 20, 21, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 0) // #518 -PAIRING(10, 15, 20, 25, 11, 20, 20, 25, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 0) // #519 -PAIRING(10, 15, 20, 25, 11, 20, 20, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 1) // #520 -PAIRING(10, 15, 20, 25, 11, 20, 21, 22, 1, 1, 11, 15, 0, 0, 21, 22, 0, 0, 2, 0) // #521 -PAIRING(10, 15, 20, 25, 11, 20, 21, 25, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 0) // #522 -PAIRING(10, 15, 20, 25, 11, 20, 21, 26, 1, 1, 11, 15, 0, 0, 21, 25, 0, 0, 2, 1) // #523 -PAIRING(10, 15, 20, 25, 11, 20, 25, 26, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #524 -PAIRING(10, 15, 20, 25, 11, 20, 26, 27, 1, 0, 11, 15, 0, 0, 0, 0, 0, 0, 2, 1) // #525 -PAIRING(10, 15, 20, 25, 11, 21, 21, 22, 1, 2, 11, 15, 0, 0, 20, 21, 21, 22, 2, 1) // #526 -PAIRING(10, 15, 20, 25, 11, 21, 21, 25, 1, 2, 11, 15, 0, 0, 20, 21, 21, 25, 1, 1) // #527 -PAIRING(10, 15, 20, 25, 11, 21, 21, 26, 1, 2, 11, 15, 0, 0, 20, 21, 21, 25, 1, 2) // #528 -PAIRING(10, 15, 20, 25, 11, 21, 22, 23, 1, 2, 11, 15, 0, 0, 20, 21, 22, 23, 2, 1) // #529 -PAIRING(10, 15, 20, 25, 11, 21, 22, 25, 1, 2, 11, 15, 0, 0, 20, 21, 22, 25, 2, 1) // #530 -PAIRING(10, 15, 20, 25, 11, 21, 22, 26, 1, 2, 11, 15, 0, 0, 20, 21, 22, 25, 2, 2) // #531 -PAIRING(10, 15, 20, 25, 11, 21, 25, 26, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #532 -PAIRING(10, 15, 20, 25, 11, 21, 26, 27, 1, 1, 11, 15, 0, 0, 20, 21, 0, 0, 2, 2) // #533 -PAIRING(10, 15, 20, 25, 11, 25, 25, 26, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #534 -PAIRING(10, 15, 20, 25, 11, 25, 26, 27, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #535 -PAIRING(10, 15, 20, 25, 11, 26, 26, 27, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #536 -PAIRING(10, 15, 20, 25, 11, 26, 27, 28, 1, 1, 11, 15, 0, 0, 20, 25, 0, 0, 1, 2) // #537 -PAIRING(10, 15, 20, 25, 15, 16, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #538 -PAIRING(10, 15, 20, 25, 15, 16, 16, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #539 -PAIRING(10, 15, 20, 25, 15, 16, 16, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #540 -PAIRING(10, 15, 20, 25, 15, 16, 16, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #541 -PAIRING(10, 15, 20, 25, 15, 16, 16, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #542 -PAIRING(10, 15, 20, 25, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #543 -PAIRING(10, 15, 20, 25, 15, 16, 17, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #544 -PAIRING(10, 15, 20, 25, 15, 16, 17, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #545 -PAIRING(10, 15, 20, 25, 15, 16, 17, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #546 -PAIRING(10, 15, 20, 25, 15, 16, 17, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #547 -PAIRING(10, 15, 20, 25, 15, 16, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #548 -PAIRING(10, 15, 20, 25, 15, 16, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #549 -PAIRING(10, 15, 20, 25, 15, 16, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #550 -PAIRING(10, 15, 20, 25, 15, 16, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #551 -PAIRING(10, 15, 20, 25, 15, 16, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #552 -PAIRING(10, 15, 20, 25, 15, 16, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #553 -PAIRING(10, 15, 20, 25, 15, 16, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #554 -PAIRING(10, 15, 20, 25, 15, 16, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #555 -PAIRING(10, 15, 20, 25, 15, 20, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #556 -PAIRING(10, 15, 20, 25, 15, 20, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #557 -PAIRING(10, 15, 20, 25, 15, 20, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #558 -PAIRING(10, 15, 20, 25, 15, 20, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #559 -PAIRING(10, 15, 20, 25, 15, 20, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #560 -PAIRING(10, 15, 20, 25, 15, 20, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #561 -PAIRING(10, 15, 20, 25, 15, 20, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #562 -PAIRING(10, 15, 20, 25, 15, 20, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #563 -PAIRING(10, 15, 20, 25, 15, 21, 21, 22, 0, 2, 0, 0, 0, 0, 20, 21, 21, 22, 2, 1) // #564 -PAIRING(10, 15, 20, 25, 15, 21, 21, 25, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 1) // #565 -PAIRING(10, 15, 20, 25, 15, 21, 21, 26, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 2) // #566 -PAIRING(10, 15, 20, 25, 15, 21, 22, 23, 0, 2, 0, 0, 0, 0, 20, 21, 22, 23, 2, 1) // #567 -PAIRING(10, 15, 20, 25, 15, 21, 22, 25, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 1) // #568 -PAIRING(10, 15, 20, 25, 15, 21, 22, 26, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 2) // #569 -PAIRING(10, 15, 20, 25, 15, 21, 25, 26, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #570 -PAIRING(10, 15, 20, 25, 15, 21, 26, 27, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #571 -PAIRING(10, 15, 20, 25, 15, 25, 25, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #572 -PAIRING(10, 15, 20, 25, 15, 25, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #573 -PAIRING(10, 15, 20, 25, 15, 26, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #574 -PAIRING(10, 15, 20, 25, 15, 26, 27, 28, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #575 -PAIRING(10, 15, 20, 25, 16, 17, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #576 -PAIRING(10, 15, 20, 25, 16, 17, 17, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #577 -PAIRING(10, 15, 20, 25, 16, 17, 17, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #578 -PAIRING(10, 15, 20, 25, 16, 17, 17, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #579 -PAIRING(10, 15, 20, 25, 16, 17, 17, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #580 -PAIRING(10, 15, 20, 25, 16, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #581 -PAIRING(10, 15, 20, 25, 16, 17, 18, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #582 -PAIRING(10, 15, 20, 25, 16, 17, 18, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #583 -PAIRING(10, 15, 20, 25, 16, 17, 18, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #584 -PAIRING(10, 15, 20, 25, 16, 17, 18, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #585 -PAIRING(10, 15, 20, 25, 16, 17, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #586 -PAIRING(10, 15, 20, 25, 16, 17, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #587 -PAIRING(10, 15, 20, 25, 16, 17, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #588 -PAIRING(10, 15, 20, 25, 16, 17, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #589 -PAIRING(10, 15, 20, 25, 16, 17, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #590 -PAIRING(10, 15, 20, 25, 16, 17, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #591 -PAIRING(10, 15, 20, 25, 16, 17, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #592 -PAIRING(10, 15, 20, 25, 16, 17, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #593 -PAIRING(10, 15, 20, 25, 16, 20, 20, 21, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #594 -PAIRING(10, 15, 20, 25, 16, 20, 20, 25, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #595 -PAIRING(10, 15, 20, 25, 16, 20, 20, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #596 -PAIRING(10, 15, 20, 25, 16, 20, 21, 22, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #597 -PAIRING(10, 15, 20, 25, 16, 20, 21, 25, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #598 -PAIRING(10, 15, 20, 25, 16, 20, 21, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #599 -PAIRING(10, 15, 20, 25, 16, 20, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #600 -PAIRING(10, 15, 20, 25, 16, 20, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #601 -PAIRING(10, 15, 20, 25, 16, 21, 21, 22, 0, 2, 0, 0, 0, 0, 20, 21, 21, 22, 2, 1) // #602 -PAIRING(10, 15, 20, 25, 16, 21, 21, 25, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 1) // #603 -PAIRING(10, 15, 20, 25, 16, 21, 21, 26, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 2) // #604 -PAIRING(10, 15, 20, 25, 16, 21, 22, 23, 0, 2, 0, 0, 0, 0, 20, 21, 22, 23, 2, 1) // #605 -PAIRING(10, 15, 20, 25, 16, 21, 22, 25, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 1) // #606 -PAIRING(10, 15, 20, 25, 16, 21, 22, 26, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 2) // #607 -PAIRING(10, 15, 20, 25, 16, 21, 25, 26, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #608 -PAIRING(10, 15, 20, 25, 16, 21, 26, 27, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 2) // #609 -PAIRING(10, 15, 20, 25, 16, 25, 25, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #610 -PAIRING(10, 15, 20, 25, 16, 25, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #611 -PAIRING(10, 15, 20, 25, 16, 26, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #612 -PAIRING(10, 15, 20, 25, 16, 26, 27, 28, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #613 -PAIRING(10, 15, 20, 25, 20, 21, 21, 22, 0, 2, 0, 0, 0, 0, 20, 21, 21, 22, 2, 0) // #614 -PAIRING(10, 15, 20, 25, 20, 21, 21, 25, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 0) // #615 -PAIRING(10, 15, 20, 25, 20, 21, 21, 26, 0, 2, 0, 0, 0, 0, 20, 21, 21, 25, 1, 1) // #616 -PAIRING(10, 15, 20, 25, 20, 21, 22, 23, 0, 2, 0, 0, 0, 0, 20, 21, 22, 23, 2, 0) // #617 -PAIRING(10, 15, 20, 25, 20, 21, 22, 25, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 0) // #618 -PAIRING(10, 15, 20, 25, 20, 21, 22, 26, 0, 2, 0, 0, 0, 0, 20, 21, 22, 25, 2, 1) // #619 -PAIRING(10, 15, 20, 25, 20, 21, 25, 26, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #620 -PAIRING(10, 15, 20, 25, 20, 21, 26, 27, 0, 1, 0, 0, 0, 0, 20, 21, 0, 0, 2, 1) // #621 -PAIRING(10, 15, 20, 25, 20, 25, 25, 26, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #622 -PAIRING(10, 15, 20, 25, 20, 25, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 1) // #623 -PAIRING(10, 15, 20, 25, 20, 26, 26, 27, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #624 -PAIRING(10, 15, 20, 25, 20, 26, 27, 28, 0, 1, 0, 0, 0, 0, 20, 25, 0, 0, 1, 2) // #625 -PAIRING(10, 15, 20, 25, 21, 22, 22, 23, 0, 2, 0, 0, 0, 0, 21, 22, 22, 23, 2, 0) // #626 -PAIRING(10, 15, 20, 25, 21, 22, 22, 25, 0, 2, 0, 0, 0, 0, 21, 22, 22, 25, 2, 0) // #627 -PAIRING(10, 15, 20, 25, 21, 22, 22, 26, 0, 2, 0, 0, 0, 0, 21, 22, 22, 25, 2, 1) // #628 -PAIRING(10, 15, 20, 25, 21, 22, 23, 24, 0, 2, 0, 0, 0, 0, 21, 22, 23, 24, 2, 0) // #629 -PAIRING(10, 15, 20, 25, 21, 22, 23, 25, 0, 2, 0, 0, 0, 0, 21, 22, 23, 25, 2, 0) // #630 -PAIRING(10, 15, 20, 25, 21, 22, 23, 26, 0, 2, 0, 0, 0, 0, 21, 22, 23, 25, 2, 1) // #631 -PAIRING(10, 15, 20, 25, 21, 22, 25, 26, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #632 -PAIRING(10, 15, 20, 25, 21, 22, 26, 27, 0, 1, 0, 0, 0, 0, 21, 22, 0, 0, 2, 1) // #633 -PAIRING(10, 15, 20, 25, 21, 25, 25, 26, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #634 -PAIRING(10, 15, 20, 25, 21, 25, 26, 27, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 1) // #635 -PAIRING(10, 15, 20, 25, 21, 26, 26, 27, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #636 -PAIRING(10, 15, 20, 25, 21, 26, 27, 28, 0, 1, 0, 0, 0, 0, 21, 25, 0, 0, 2, 2) // #637 -PAIRING(10, 15, 20, 25, 25, 26, 26, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #638 -PAIRING(10, 15, 20, 25, 25, 26, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #639 -PAIRING(10, 15, 20, 25, 26, 27, 27, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #640 -PAIRING(10, 15, 20, 25, 26, 27, 28, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2) // #641 diff --git a/toolkit/crashreporter/google-breakpad/src/common/tests/auto_tempdir.h b/toolkit/crashreporter/google-breakpad/src/common/tests/auto_tempdir.h deleted file mode 100644 index 1df88db8b..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/tests/auto_tempdir.h +++ /dev/null @@ -1,100 +0,0 @@ -// 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. - -// Utility class for creating a temporary directory for unit tests -// that is deleted in the destructor. -#ifndef GOOGLE_BREAKPAD_COMMON_TESTS_AUTO_TEMPDIR -#define GOOGLE_BREAKPAD_COMMON_TESTS_AUTO_TEMPDIR - -#include <dirent.h> -#include <sys/types.h> - -#include <string> - -#include "breakpad_googletest_includes.h" -#include "common/using_std_string.h" - -#if !defined(__ANDROID__) -#define TEMPDIR "/tmp" -#else -#define TEMPDIR "/data/local/tmp" -#include "common/android/testing/mkdtemp.h" -#endif - -namespace google_breakpad { - -class AutoTempDir { - public: - AutoTempDir() { - char temp_dir[] = TEMPDIR "/breakpad.XXXXXX"; - EXPECT_TRUE(mkdtemp(temp_dir) != NULL); - path_.assign(temp_dir); - } - - ~AutoTempDir() { - DeleteRecursively(path_); - } - - const string& path() const { - return path_; - } - - private: - void DeleteRecursively(const string& path) { - // First remove any files in the dir - DIR* dir = opendir(path.c_str()); - if (!dir) - return; - - dirent* entry; - while ((entry = readdir(dir)) != NULL) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) - continue; - string entry_path = path + "/" + entry->d_name; - struct stat stats; - EXPECT_TRUE(lstat(entry_path.c_str(), &stats) == 0); - if (S_ISDIR(stats.st_mode)) - DeleteRecursively(entry_path); - else - EXPECT_TRUE(unlink(entry_path.c_str()) == 0); - } - EXPECT_TRUE(closedir(dir) == 0); - EXPECT_TRUE(rmdir(path.c_str()) == 0); - } - - // prevent copy construction and assignment - AutoTempDir(const AutoTempDir&); - AutoTempDir& operator=(const AutoTempDir&); - - string path_; -}; - -} // namespace google_breakpad - -#endif // GOOGLE_BREAKPAD_COMMON_TESTS_AUTO_TEMPDIR diff --git a/toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.cc b/toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.cc deleted file mode 100644 index 1c041777c..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.cc +++ /dev/null @@ -1,153 +0,0 @@ -// 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. - -// file_utils.cc: Implement utility functions for file manipulation. -// See file_utils.h for details. - -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <unistd.h> - -#include "common/linux/eintr_wrapper.h" -#include "common/tests/file_utils.h" - -namespace google_breakpad { - -bool CopyFile(const char* from_path, const char* to_path) { - int infile = HANDLE_EINTR(open(from_path, O_RDONLY)); - if (infile < 0) { - perror("open"); - return false; - } - - int outfile = HANDLE_EINTR(creat(to_path, 0666)); - if (outfile < 0) { - perror("creat"); - if (IGNORE_EINTR(close(infile)) < 0) { - perror("close"); - } - return false; - } - - char buffer[1024]; - bool result = true; - - while (result) { - ssize_t bytes_read = HANDLE_EINTR(read(infile, buffer, sizeof(buffer))); - if (bytes_read < 0) { - perror("read"); - result = false; - break; - } - if (bytes_read == 0) - break; - ssize_t bytes_written_per_read = 0; - do { - ssize_t bytes_written_partial = HANDLE_EINTR(write( - outfile, - &buffer[bytes_written_per_read], - bytes_read - bytes_written_per_read)); - if (bytes_written_partial < 0) { - perror("write"); - result = false; - break; - } - bytes_written_per_read += bytes_written_partial; - } while (bytes_written_per_read < bytes_read); - } - - if (IGNORE_EINTR(close(infile)) == -1) { - perror("close"); - result = false; - } - if (IGNORE_EINTR(close(outfile)) == -1) { - perror("close"); - result = false; - } - - return result; -} - -bool ReadFile(const char* path, void* buffer, ssize_t* buffer_size) { - int fd = HANDLE_EINTR(open(path, O_RDONLY)); - if (fd == -1) { - perror("open"); - return false; - } - - bool ok = true; - if (buffer && buffer_size && *buffer_size > 0) { - memset(buffer, 0, sizeof(*buffer_size)); - *buffer_size = HANDLE_EINTR(read(fd, buffer, *buffer_size)); - if (*buffer_size == -1) { - perror("read"); - ok = false; - } - } - if (IGNORE_EINTR(close(fd)) == -1) { - perror("close"); - ok = false; - } - return ok; -} - -bool WriteFile(const char* path, const void* buffer, size_t buffer_size) { - int fd = HANDLE_EINTR(open(path, O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU)); - if (fd == -1) { - perror("open"); - return false; - } - - bool ok = true; - if (buffer) { - size_t bytes_written_total = 0; - ssize_t bytes_written_partial = 0; - const char* data = reinterpret_cast<const char*>(buffer); - while (bytes_written_total < buffer_size) { - bytes_written_partial = - HANDLE_EINTR(write(fd, data + bytes_written_total, - buffer_size - bytes_written_total)); - if (bytes_written_partial < 0) { - perror("write"); - ok = false; - break; - } - bytes_written_total += bytes_written_partial; - } - } - if (IGNORE_EINTR(close(fd)) == -1) { - perror("close"); - ok = false; - } - return ok; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.h b/toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.h deleted file mode 100644 index c98a9bfa8..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/tests/file_utils.h +++ /dev/null @@ -1,52 +0,0 @@ -// 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. - -// file_utils.h: Define utility functions for file manipulation, which -// are used for testing. - -#ifndef COMMON_TESTS_FILE_UTILS_H_ -#define COMMON_TESTS_FILE_UTILS_H_ - -namespace google_breakpad { - -// Copies a file from |from_path| to |to_path|. Returns true on success. -bool CopyFile(const char* from_path, const char* to_path); - -// Reads the content of a file at |path| into |buffer|. |buffer_size| specifies -// the size of |buffer| in bytes and returns the number of bytes read from the -// file on success. Returns true on success. -bool ReadFile(const char* path, void* buffer, ssize_t* buffer_size); - -// Writes |buffer_size| bytes of the content in |buffer| to a file at |path|. -// Returns true on success. -bool WriteFile(const char* path, const void* buffer, size_t buffer_size); - -} // namespace google_breakpad - -#endif // COMMON_TESTS_FILE_UTILS_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/unordered.h b/toolkit/crashreporter/google-breakpad/src/common/unordered.h deleted file mode 100644 index ec665cc02..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/unordered.h +++ /dev/null @@ -1,62 +0,0 @@ -// 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. - -// Include this file to use unordered_map and unordered_set. If tr1 -// or C++11 is not available, you can switch to using hash_set and -// hash_map by defining BP_USE_HASH_SET. - -#ifndef COMMON_UNORDERED_H_ -#define COMMON_UNORDERED_H_ - -#if defined(BP_USE_HASH_SET) -#include <hash_map> -#include <hash_set> - -// For hash<string>. -#include "util/hash/hash.h" - -template <class T, class U, class H = __gnu_cxx::hash<T> > -struct unordered_map : public hash_map<T, U, H> {}; -template <class T, class H = __gnu_cxx::hash<T> > -struct unordered_set : public hash_set<T, H> {}; - -#elif defined(_LIBCPP_VERSION) // c++11 -#include <unordered_map> -#include <unordered_set> -using std::unordered_map; -using std::unordered_set; - -#else // Fallback to tr1::unordered -#include <tr1/unordered_map> -#include <tr1/unordered_set> -using std::tr1::unordered_map; -using std::tr1::unordered_set; -#endif - -#endif // COMMON_UNORDERED_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/using_std_string.h b/toolkit/crashreporter/google-breakpad/src/common/using_std_string.h deleted file mode 100644 index 13c1da59c..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/using_std_string.h +++ /dev/null @@ -1,65 +0,0 @@ -// -*- mode: C++ -*- - -// 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. - -// Original author: Ivan Penkov - -// using_std_string.h: Allows building this code in environments where -// global string (::string) exists. -// -// The problem: -// ------------- -// Let's say you want to build this code in an environment where a global -// string type is defined (i.e. ::string). Now, let's suppose that ::string -// is different that std::string and you'd like to have the option to easily -// choose between the two string types. Ideally you'd like to control which -// string type is chosen by simply #defining an identifier. -// -// The solution: -// ------------- -// #define HAS_GLOBAL_STRING somewhere in a global header file and then -// globally replace std::string with string. Then include this header -// file everywhere where string is used. If you want to revert back to -// using std::string, simply remove the #define (HAS_GLOBAL_STRING). - -#ifndef THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_ -#define THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_ - -#ifdef HAS_GLOBAL_STRING - typedef ::string google_breakpad_string; -#else - using std::string; - typedef std::string google_breakpad_string; -#endif - -// Inicates that type google_breakpad_string is defined -#define HAS_GOOGLE_BREAKPAD_STRING - -#endif // THIRD_PARTY_BREAKPAD_SRC_COMMON_USING_STD_STRING_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/common_windows.gyp b/toolkit/crashreporter/google-breakpad/src/common/windows/common_windows.gyp deleted file mode 100644 index c98333a34..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/common_windows.gyp +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 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. - -{ - 'includes': [ - '../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'dia_sdk', - 'type': 'none', - 'all_dependent_settings': { - 'include_dirs': [ - '<(DEPTH)', - '$(VSInstallDir)/DIA SDK/include', - ], - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalDependencies': [ - 'diaguids.lib', - 'imagehlp.lib', - ], - }, - }, - 'configurations': { - 'x86_Base': { - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalLibraryDirectories': - ['$(VSInstallDir)/DIA SDK/lib'], - }, - }, - }, - 'x64_Base': { - 'msvs_settings': { - 'VCLinkerTool': { - 'AdditionalLibraryDirectories': - ['$(VSInstallDir)/DIA SDK/lib/amd64'], - }, - }, - }, - }, - }, - }, - { - 'target_name': 'common_windows_lib', - 'type': 'static_library', - 'sources': [ - 'dia_util.cc', - 'dia_util.h', - 'guid_string.cc', - 'guid_string.h', - 'http_upload.cc', - 'http_upload.h', - 'omap.cc', - 'omap.h', - 'omap_internal.h', - 'pdb_source_line_writer.cc', - 'pdb_source_line_writer.h', - 'string_utils.cc', - 'string_utils-inl.h', - ], - 'dependencies': [ - 'dia_sdk', - ], - }, - { - 'target_name': 'common_windows_unittests', - 'type': 'executable', - 'sources': [ - 'omap_unittest.cc', - ], - 'dependencies': [ - '<(DEPTH)/client/windows/unittests/testing.gyp:gmock', - '<(DEPTH)/client/windows/unittests/testing.gyp:gtest', - 'common_windows_lib', - ], - }, - ], -} diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.cc deleted file mode 100644 index ed8cb5b65..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.cc +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright 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.
-
-#include "common/windows/dia_util.h"
-
-#include <atlbase.h>
-
-namespace google_breakpad {
-
-bool FindDebugStream(const wchar_t* name,
- IDiaSession* session,
- IDiaEnumDebugStreamData** debug_stream) {
- CComPtr<IDiaEnumDebugStreams> enum_debug_streams;
- if (FAILED(session->getEnumDebugStreams(&enum_debug_streams))) {
- fprintf(stderr, "IDiaSession::getEnumDebugStreams failed\n");
- return false;
- }
-
- CComPtr<IDiaEnumDebugStreamData> temp_debug_stream;
- ULONG fetched = 0;
- while (SUCCEEDED(enum_debug_streams->Next(1, &temp_debug_stream, &fetched)) &&
- fetched == 1) {
- CComBSTR stream_name;
- if (FAILED(temp_debug_stream->get_name(&stream_name))) {
- fprintf(stderr, "IDiaEnumDebugStreamData::get_name failed\n");
- return false;
- }
-
- // Found the stream?
- if (wcsncmp((LPWSTR)stream_name, name, stream_name.Length()) == 0) {
- *debug_stream = temp_debug_stream.Detach();
- return true;
- }
-
- temp_debug_stream.Release();
- }
-
- // No table was found.
- return false;
-}
-
-bool FindTable(REFIID iid, IDiaSession* session, void** table) {
- // Get the table enumerator.
- CComPtr<IDiaEnumTables> enum_tables;
- if (FAILED(session->getEnumTables(&enum_tables))) {
- fprintf(stderr, "IDiaSession::getEnumTables failed\n");
- return false;
- }
-
- // Iterate through the tables.
- CComPtr<IDiaTable> temp_table;
- ULONG fetched = 0;
- while (SUCCEEDED(enum_tables->Next(1, &temp_table, &fetched)) &&
- fetched == 1) {
- void* temp = NULL;
- if (SUCCEEDED(temp_table->QueryInterface(iid, &temp))) {
- *table = temp;
- return true;
- }
- temp_table.Release();
- }
-
- // The table was not found.
- return false;
-}
-
-} // namespace google_breakpad
\ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.h b/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.h deleted file mode 100644 index b9e0df2d5..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/dia_util.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 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. - -// Utilities for loading debug streams and tables from a PDB file. - -#ifndef COMMON_WINDOWS_DIA_UTIL_H_ -#define COMMON_WINDOWS_DIA_UTIL_H_ - -#include <Windows.h> -#include <dia2.h> - -namespace google_breakpad { - -// Find the debug stream of the given |name| in the given |session|. Returns -// true on success, false on error of if the stream does not exist. On success -// the stream will be returned via |debug_stream|. -bool FindDebugStream(const wchar_t* name, - IDiaSession* session, - IDiaEnumDebugStreamData** debug_stream); - -// Finds the first table implementing the COM interface with ID |iid| in the -// given |session|. Returns true on success, false on error or if no such -// table is found. On success the table will be returned via |table|. -bool FindTable(REFIID iid, IDiaSession* session, void** table); - -// A templated version of FindTable. Finds the first table implementing type -// |InterfaceType| in the given |session|. Returns true on success, false on -// error or if no such table is found. On success the table will be returned via -// |table|. -template<typename InterfaceType> -bool FindTable(IDiaSession* session, InterfaceType** table) { - return FindTable(__uuidof(InterfaceType), - session, - reinterpret_cast<void**>(table)); -} - -} // namespace google_breakpad - -#endif // COMMON_WINDOWS_DIA_UTIL_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.cc deleted file mode 100644 index b7f877e66..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.cc +++ /dev/null @@ -1,76 +0,0 @@ -// 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. - -// guid_string.cc: Convert GUIDs to strings. -// -// See guid_string.h for documentation. - -#include <wchar.h> - -#include "common/windows/string_utils-inl.h" - -#include "common/windows/guid_string.h" - -namespace google_breakpad { - -// static -wstring GUIDString::GUIDToWString(GUID *guid) { - wchar_t guid_string[37]; - swprintf( - guid_string, sizeof(guid_string) / sizeof(guid_string[0]), - L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", - guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], - guid->Data4[3], guid->Data4[4], guid->Data4[5], - guid->Data4[6], guid->Data4[7]); - - // remove when VC++7.1 is no longer supported - guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0'; - - return wstring(guid_string); -} - -// static -wstring GUIDString::GUIDToSymbolServerWString(GUID *guid) { - wchar_t guid_string[33]; - swprintf( - guid_string, sizeof(guid_string) / sizeof(guid_string[0]), - L"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", - guid->Data1, guid->Data2, guid->Data3, - guid->Data4[0], guid->Data4[1], guid->Data4[2], - guid->Data4[3], guid->Data4[4], guid->Data4[5], - guid->Data4[6], guid->Data4[7]); - - // remove when VC++7.1 is no longer supported - guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0'; - - return wstring(guid_string); -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.h b/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.h deleted file mode 100644 index 48a5c1d37..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/guid_string.h +++ /dev/null @@ -1,58 +0,0 @@ -// 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. - -// guid_string.cc: Convert GUIDs to strings. - -#ifndef COMMON_WINDOWS_GUID_STRING_H_ -#define COMMON_WINDOWS_GUID_STRING_H_ - -#include <guiddef.h> - -#include <string> - -namespace google_breakpad { - -using std::wstring; - -class GUIDString { - public: - // Converts guid to a string in the format recommended by RFC 4122 and - // returns the string. - static wstring GUIDToWString(GUID *guid); - - // Converts guid to a string formatted as uppercase hexadecimal, with - // no separators, and returns the string. This is the format used for - // symbol server identifiers, although identifiers have an age tacked - // on to the string. - static wstring GUIDToSymbolServerWString(GUID *guid); -}; - -} // namespace google_breakpad - -#endif // COMMON_WINDOWS_GUID_STRING_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc deleted file mode 100644 index 7676bdc5a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.cc +++ /dev/null @@ -1,420 +0,0 @@ -// 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 <assert.h> - -// Disable exception handler warnings. -#pragma warning(disable:4530) - -#include <fstream> - -#include "common/windows/string_utils-inl.h" - -#include "common/windows/http_upload.h" - -namespace google_breakpad { - -using std::ifstream; -using std::ios; - -static const wchar_t kUserAgent[] = L"Breakpad/1.0 (Windows)"; - -// Helper class which closes an internet handle when it goes away -class HTTPUpload::AutoInternetHandle { - public: - explicit AutoInternetHandle(HINTERNET handle) : handle_(handle) {} - ~AutoInternetHandle() { - if (handle_) { - InternetCloseHandle(handle_); - } - } - - HINTERNET get() { return handle_; } - - private: - HINTERNET handle_; -}; - -// static -bool HTTPUpload::SendRequest(const wstring &url, - const map<wstring, wstring> ¶meters, - const map<wstring, wstring> &files, - int *timeout, - wstring *response_body, - int *response_code) { - if (response_code) { - *response_code = 0; - } - - // TODO(bryner): support non-ASCII parameter names - if (!CheckParameters(parameters)) { - return false; - } - - // Break up the URL and make sure we can handle it - wchar_t scheme[16], host[256], path[256]; - URL_COMPONENTS components; - memset(&components, 0, sizeof(components)); - components.dwStructSize = sizeof(components); - components.lpszScheme = scheme; - components.dwSchemeLength = sizeof(scheme) / sizeof(scheme[0]); - components.lpszHostName = host; - components.dwHostNameLength = sizeof(host) / sizeof(host[0]); - components.lpszUrlPath = path; - components.dwUrlPathLength = sizeof(path) / sizeof(path[0]); - if (!InternetCrackUrl(url.c_str(), static_cast<DWORD>(url.size()), - 0, &components)) { - return false; - } - bool secure = false; - if (wcscmp(scheme, L"https") == 0) { - secure = true; - } else if (wcscmp(scheme, L"http") != 0) { - return false; - } - - AutoInternetHandle internet(InternetOpen(kUserAgent, - INTERNET_OPEN_TYPE_PRECONFIG, - NULL, // proxy name - NULL, // proxy bypass - 0)); // flags - if (!internet.get()) { - return false; - } - - AutoInternetHandle connection(InternetConnect(internet.get(), - host, - components.nPort, - NULL, // user name - NULL, // password - INTERNET_SERVICE_HTTP, - 0, // flags - NULL)); // context - if (!connection.get()) { - return false; - } - - DWORD http_open_flags = secure ? INTERNET_FLAG_SECURE : 0; - http_open_flags |= INTERNET_FLAG_NO_COOKIES; - AutoInternetHandle request(HttpOpenRequest(connection.get(), - L"POST", - path, - NULL, // version - NULL, // referer - NULL, // agent type - http_open_flags, - NULL)); // context - if (!request.get()) { - return false; - } - - wstring boundary = GenerateMultipartBoundary(); - wstring content_type_header = GenerateRequestHeader(boundary); - HttpAddRequestHeaders(request.get(), - content_type_header.c_str(), - static_cast<DWORD>(-1), - HTTP_ADDREQ_FLAG_ADD); - - string request_body; - if (!GenerateRequestBody(parameters, files, boundary, &request_body)) { - return false; - } - - if (timeout) { - if (!InternetSetOption(request.get(), - INTERNET_OPTION_SEND_TIMEOUT, - timeout, - sizeof(*timeout))) { - fwprintf(stderr, L"Could not unset send timeout, continuing...\n"); - } - - if (!InternetSetOption(request.get(), - INTERNET_OPTION_RECEIVE_TIMEOUT, - timeout, - sizeof(*timeout))) { - fwprintf(stderr, L"Could not unset receive timeout, continuing...\n"); - } - } - - if (!HttpSendRequest(request.get(), NULL, 0, - const_cast<char *>(request_body.data()), - static_cast<DWORD>(request_body.size()))) { - return false; - } - - // The server indicates a successful upload with HTTP status 200. - wchar_t http_status[4]; - DWORD http_status_size = sizeof(http_status); - if (!HttpQueryInfo(request.get(), HTTP_QUERY_STATUS_CODE, - static_cast<LPVOID>(&http_status), &http_status_size, - 0)) { - return false; - } - - int http_response = wcstol(http_status, NULL, 10); - if (response_code) { - *response_code = http_response; - } - - bool result = (http_response == 200); - - if (result) { - result = ReadResponse(request.get(), response_body); - } - - return result; -} - -// static -bool HTTPUpload::ReadResponse(HINTERNET request, wstring *response) { - bool has_content_length_header = false; - wchar_t content_length[32]; - DWORD content_length_size = sizeof(content_length); - DWORD claimed_size = 0; - string response_body; - - if (HttpQueryInfo(request, HTTP_QUERY_CONTENT_LENGTH, - static_cast<LPVOID>(&content_length), - &content_length_size, 0)) { - has_content_length_header = true; - claimed_size = wcstol(content_length, NULL, 10); - response_body.reserve(claimed_size); - } - - - DWORD bytes_available; - DWORD total_read = 0; - BOOL return_code; - - while (((return_code = InternetQueryDataAvailable(request, &bytes_available, - 0, 0)) != 0) && bytes_available > 0) { - vector<char> response_buffer(bytes_available); - DWORD size_read; - - return_code = InternetReadFile(request, - &response_buffer[0], - bytes_available, &size_read); - - if (return_code && size_read > 0) { - total_read += size_read; - response_body.append(&response_buffer[0], size_read); - } else { - break; - } - } - - bool succeeded = return_code && (!has_content_length_header || - (total_read == claimed_size)); - if (succeeded && response) { - *response = UTF8ToWide(response_body); - } - - return succeeded; -} - -// static -wstring HTTPUpload::GenerateMultipartBoundary() { - // The boundary has 27 '-' characters followed by 16 hex digits - static const wchar_t kBoundaryPrefix[] = L"---------------------------"; - static const int kBoundaryLength = 27 + 16 + 1; - - // Generate some random numbers to fill out the boundary - int r0 = rand(); - int r1 = rand(); - - wchar_t temp[kBoundaryLength]; - swprintf(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1); - - // remove when VC++7.1 is no longer supported - temp[kBoundaryLength - 1] = L'\0'; - - return wstring(temp); -} - -// static -wstring HTTPUpload::GenerateRequestHeader(const wstring &boundary) { - wstring header = L"Content-Type: multipart/form-data; boundary="; - header += boundary; - return header; -} - -// static -bool HTTPUpload::GenerateRequestBody(const map<wstring, wstring> ¶meters, - const map<wstring, wstring> &files, - const wstring &boundary, - string *request_body) { - string boundary_str = WideToUTF8(boundary); - if (boundary_str.empty()) { - return false; - } - - request_body->clear(); - - // Append each of the parameter pairs as a form-data part - for (map<wstring, wstring>::const_iterator pos = parameters.begin(); - pos != parameters.end(); ++pos) { - request_body->append("--" + boundary_str + "\r\n"); - request_body->append("Content-Disposition: form-data; name=\"" + - WideToUTF8(pos->first) + "\"\r\n\r\n" + - WideToUTF8(pos->second) + "\r\n"); - } - - for (map<wstring, wstring>::const_iterator pos = files.begin(); - pos != files.end(); ++pos) { - vector<char> contents; - if (!GetFileContents(pos->second, &contents)) { - return false; - } - - // Now append the upload files as a binary (octet-stream) part - string filename_utf8 = WideToUTF8(pos->second); - if (filename_utf8.empty()) { - return false; - } - - string file_part_name_utf8 = WideToUTF8(pos->first); - if (file_part_name_utf8.empty()) { - return false; - } - - request_body->append("--" + boundary_str + "\r\n"); - request_body->append("Content-Disposition: form-data; " - "name=\"" + file_part_name_utf8 + "\"; " - "filename=\"" + filename_utf8 + "\"\r\n"); - request_body->append("Content-Type: application/octet-stream\r\n"); - request_body->append("\r\n"); - - if (!contents.empty()) { - request_body->append(&(contents[0]), contents.size()); - } - request_body->append("\r\n"); - } - request_body->append("--" + boundary_str + "--\r\n"); - return true; -} - -// static -bool HTTPUpload::GetFileContents(const wstring &filename, - vector<char> *contents) { - bool rv = false; - // The "open" method on pre-MSVC8 ifstream implementations doesn't accept a - // wchar_t* filename, so use _wfopen directly in that case. For VC8 and - // later, _wfopen has been deprecated in favor of _wfopen_s, which does - // not exist in earlier versions, so let the ifstream open the file itself. - // GCC doesn't support wide file name and opening on FILE* requires ugly - // hacks, so fallback to multi byte file. -#ifdef _MSC_VER - ifstream file; - file.open(filename.c_str(), ios::binary); -#else // GCC - ifstream file(WideToMBCP(filename, CP_ACP).c_str(), ios::binary); -#endif // _MSC_VER >= 1400 - if (file.is_open()) { - file.seekg(0, ios::end); - std::streamoff length = file.tellg(); - // Check for loss of data when converting lenght from std::streamoff into - // std::vector<char>::size_type - std::vector<char>::size_type vector_size = - static_cast<std::vector<char>::size_type>(length); - if (static_cast<std::streamoff>(vector_size) == length) { - contents->resize(vector_size); - if (length != 0) { - file.seekg(0, ios::beg); - file.read(&((*contents)[0]), length); - } - rv = true; - } - file.close(); - } - return rv; -} - -// static -wstring HTTPUpload::UTF8ToWide(const string &utf8) { - if (utf8.length() == 0) { - return wstring(); - } - - // compute the length of the buffer we'll need - int charcount = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, NULL, 0); - - if (charcount == 0) { - return wstring(); - } - - // convert - wchar_t* buf = new wchar_t[charcount]; - MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), -1, buf, charcount); - wstring result(buf); - delete[] buf; - return result; -} - -// static -string HTTPUpload::WideToMBCP(const wstring &wide, unsigned int cp) { - if (wide.length() == 0) { - return string(); - } - - // compute the length of the buffer we'll need - int charcount = WideCharToMultiByte(cp, 0, wide.c_str(), -1, - NULL, 0, NULL, NULL); - if (charcount == 0) { - return string(); - } - - // convert - char *buf = new char[charcount]; - WideCharToMultiByte(cp, 0, wide.c_str(), -1, buf, charcount, - NULL, NULL); - - string result(buf); - delete[] buf; - return result; -} - -// static -bool HTTPUpload::CheckParameters(const map<wstring, wstring> ¶meters) { - for (map<wstring, wstring>::const_iterator pos = parameters.begin(); - pos != parameters.end(); ++pos) { - const wstring &str = pos->first; - if (str.size() == 0) { - return false; // disallow empty parameter names - } - for (unsigned int i = 0; i < str.size(); ++i) { - wchar_t c = str[i]; - if (c < 32 || c == '"' || c > 127) { - return false; - } - } - } - return true; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h b/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h deleted file mode 100644 index f8d48cb1b..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/http_upload.h +++ /dev/null @@ -1,129 +0,0 @@ -// 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 wininet. It currently supports requests that contain -// a set of string parameters (key/value pairs), and a file to upload. - -#ifndef COMMON_WINDOWS_HTTP_UPLOAD_H_ -#define COMMON_WINDOWS_HTTP_UPLOAD_H_ - -#pragma warning(push) -// Disable exception handler warnings. -#pragma warning(disable : 4530) - -#include <windows.h> -#include <wininet.h> - -#include <map> -#include <string> -#include <vector> - -namespace google_breakpad { - -using std::string; -using std::wstring; -using std::map; -using std::vector; - -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). - static bool SendRequest(const wstring &url, - const map<wstring, wstring> ¶meters, - const map<wstring, wstring> &files, - int *timeout, - wstring *response_body, - int *response_code); - - private: - class AutoInternetHandle; - - // Retrieves the HTTP response. If NULL is passed in for response, - // this merely checks (via the return value) that we were successfully - // able to retrieve exactly as many bytes of content in the response as - // were specified in the Content-Length header. - static bool ReadResponse(HINTERNET request, wstring* response); - - // Generates a new multipart boundary for a POST request - static wstring GenerateMultipartBoundary(); - - // Generates a HTTP request header for a multipart form submit. - static wstring GenerateRequestHeader(const wstring &boundary); - - // Given a set of parameters, a set of upload files, and a file part name, - // generates a multipart request body string with these parameters - // and minidump contents. Returns true on success. - static bool GenerateRequestBody(const map<wstring, wstring> ¶meters, - const map<wstring, wstring> &files, - const wstring &boundary, - string *request_body); - - // Fills the supplied vector with the contents of filename. - static bool GetFileContents(const wstring &filename, vector<char> *contents); - - // Converts a UTF8 string to UTF16. - static wstring UTF8ToWide(const string &utf8); - - // Converts a UTF16 string to UTF8. - static string WideToUTF8(const wstring &wide) { - return WideToMBCP(wide, CP_UTF8); - } - - // Converts a UTF16 string to specified code page. - static string WideToMBCP(const wstring &wide, unsigned int cp); - - // 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<wstring, wstring> ¶meters); - - // 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 - -#pragma warning(pop) - -#endif // COMMON_WINDOWS_HTTP_UPLOAD_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild b/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild deleted file mode 100644 index 5fcdae5a3..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/objs.mozbuild +++ /dev/null @@ -1,15 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -lobjs_common = [ - 'guid_string.cc', - 'string_utils.cc', -] - -subdir = 'toolkit/crashreporter/google-breakpad/src/common/windows' -objs_common = [ - '/%s/%s' % (subdir, s) for s in lobjs_common -] diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/omap.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/omap.cc deleted file mode 100644 index 554a57c2d..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/omap.cc +++ /dev/null @@ -1,694 +0,0 @@ -// Copyright 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. - -// This contains a suite of tools for transforming symbol information when -// when that information has been extracted from a PDB containing OMAP -// information. - -// OMAP information is a lightweight description of a mapping between two -// address spaces. It consists of two streams, each of them a vector 2-tuples. -// The OMAPTO stream contains tuples of the form -// -// (RVA in transformed image, RVA in original image) -// -// while the OMAPFROM stream contains tuples of the form -// -// (RVA in original image, RVA in transformed image) -// -// The entries in each vector are sorted by the first value of the tuple, and -// the lengths associated with a mapping are implicit as the distance between -// two successive addresses in the vector. - -// Consider a trivial 10-byte function described by the following symbol: -// -// Function: RVA 0x00001000, length 10, "foo" -// -// Now consider the same function, but with 5-bytes of instrumentation injected -// at offset 5. The OMAP streams describing this would look like: -// -// OMAPTO : [ [0x00001000, 0x00001000], -// [0x00001005, 0xFFFFFFFF], -// [0x0000100a, 0x00001005] ] -// OMAPFROM: [ [0x00001000, 0x00001000], -// [0x00001005, 0x0000100a] ] -// -// In this case the injected code has been marked as not originating in the -// source image, and thus it will have no symbol information at all. However, -// the injected code may also be associated with an original address range; -// for example, when prepending instrumentation to a basic block the -// instrumentation can be labelled as originating from the same source BB such -// that symbol resolution will still find the appropriate source code line -// number. In this case the OMAP stream would look like: -// -// OMAPTO : [ [0x00001000, 0x00001000], -// [0x00001005, 0x00001005], -// [0x0000100a, 0x00001005] ] -// OMAPFROM: [ [0x00001000, 0x00001000], -// [0x00001005, 0x0000100a] ] -// -// Suppose we asked DIA to lookup the symbol at location 0x0000100a of the -// instrumented image. It would first run this through the OMAPTO table and -// translate that address to 0x00001005. It would then lookup the symbol -// at that address and return the symbol for the function "foo". This is the -// correct result. -// -// However, if we query DIA for the length and address of the symbol it will -// tell us that it has length 10 and is at RVA 0x00001000. The location is -// correct, but the length doesn't take into account the 5-bytes of injected -// code. Symbol resolution works (starting from an instrumented address, -// mapping to an original address, and looking up a symbol), but the symbol -// metadata is incorrect. -// -// If we dump the symbols using DIA they will have their addresses -// appropriately transformed and reflect positions in the instrumented image. -// However, if we try to do a lookup using those symbols resolution can fail. -// For example, the address 0x0000100a will not map to the symbol for "foo", -// because DIA tells us it is at location 0x00001000 (correct) with length -// 10 (incorrect). The problem is one of order of operations: in this case -// we're attempting symbol resolution by looking up an instrumented address -// in the table of translated symbols. -// -// One way to handle this is to dump the OMAP information as part of the -// breakpad symbols. This requires the rest of the toolchain to be aware of -// OMAP information and to use it when present prior to performing lookup. The -// other option is to properly transform the symbols (updating length as well as -// position) so that resolution will work as expected for translated addresses. -// This is transparent to the rest of the toolchain. - -#include "common/windows/omap.h" - -#include <atlbase.h> - -#include <algorithm> -#include <cassert> -#include <set> - -#include "common/windows/dia_util.h" - -namespace google_breakpad { - -namespace { - -static const wchar_t kOmapToDebugStreamName[] = L"OMAPTO"; -static const wchar_t kOmapFromDebugStreamName[] = L"OMAPFROM"; - -// Dependending on where this is used in breakpad we sometimes get min/max from -// windef, and other times from algorithm. To get around this we simply -// define our own min/max functions. -template<typename T> -const T& Min(const T& t1, const T& t2) { return t1 < t2 ? t1 : t2; } -template<typename T> -const T& Max(const T& t1, const T& t2) { return t1 > t2 ? t1 : t2; } - -// It makes things more readable to have two different OMAP types. We cast -// normal OMAPs into these. They must be the same size as the OMAP structure -// for this to work, hence the static asserts. -struct OmapOrigToTran { - DWORD rva_original; - DWORD rva_transformed; -}; -struct OmapTranToOrig { - DWORD rva_transformed; - DWORD rva_original; -}; -static_assert(sizeof(OmapOrigToTran) == sizeof(OMAP), - "OmapOrigToTran must have same size as OMAP."); -static_assert(sizeof(OmapTranToOrig) == sizeof(OMAP), - "OmapTranToOrig must have same size as OMAP."); -typedef std::vector<OmapOrigToTran> OmapFromTable; -typedef std::vector<OmapTranToOrig> OmapToTable; - -// Used for sorting and searching through a Mapping. -bool MappedRangeOriginalLess(const MappedRange& lhs, const MappedRange& rhs) { - if (lhs.rva_original < rhs.rva_original) - return true; - if (lhs.rva_original > rhs.rva_original) - return false; - return lhs.length < rhs.length; -} -bool MappedRangeMappedLess(const MappedRange& lhs, const MappedRange& rhs) { - if (lhs.rva_transformed < rhs.rva_transformed) - return true; - if (lhs.rva_transformed > rhs.rva_transformed) - return false; - return lhs.length < rhs.length; -} - -// Used for searching through the EndpointIndexMap. -bool EndpointIndexLess(const EndpointIndex& ei1, const EndpointIndex& ei2) { - return ei1.endpoint < ei2.endpoint; -} - -// Finds the debug stream with the given |name| in the given |session|, and -// populates |table| with its contents. Casts the data directly into OMAP -// structs. -bool FindAndLoadOmapTable(const wchar_t* name, - IDiaSession* session, - OmapTable* table) { - assert(name != NULL); - assert(session != NULL); - assert(table != NULL); - - CComPtr<IDiaEnumDebugStreamData> stream; - if (!FindDebugStream(name, session, &stream)) - return false; - assert(stream.p != NULL); - - LONG count = 0; - if (FAILED(stream->get_Count(&count))) { - fprintf(stderr, "IDiaEnumDebugStreamData::get_Count failed for stream " - "\"%ws\"\n", name); - return false; - } - - // Get the length of the stream in bytes. - DWORD bytes_read = 0; - ULONG count_read = 0; - if (FAILED(stream->Next(count, 0, &bytes_read, NULL, &count_read))) { - fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading " - "length of stream \"%ws\"\n", name); - return false; - } - - // Ensure it's consistent with the OMAP data type. - DWORD bytes_expected = count * sizeof(OmapTable::value_type); - if (count * sizeof(OmapTable::value_type) != bytes_read) { - fprintf(stderr, "DIA debug stream \"%ws\" has an unexpected length", name); - return false; - } - - // Read the table. - table->resize(count); - bytes_read = 0; - count_read = 0; - if (FAILED(stream->Next(count, bytes_expected, &bytes_read, - reinterpret_cast<BYTE*>(&table->at(0)), - &count_read))) { - fprintf(stderr, "IDiaEnumDebugStreamData::Next failed while reading " - "data from stream \"%ws\"\n", name); - return false; - } - - return true; -} - -// This determines the original image length by looking through the segment -// table. -bool GetOriginalImageLength(IDiaSession* session, DWORD* image_length) { - assert(session != NULL); - assert(image_length != NULL); - - CComPtr<IDiaEnumSegments> enum_segments; - if (!FindTable(session, &enum_segments)) - return false; - assert(enum_segments.p != NULL); - - DWORD temp_image_length = 0; - CComPtr<IDiaSegment> segment; - ULONG fetched = 0; - while (SUCCEEDED(enum_segments->Next(1, &segment, &fetched)) && - fetched == 1) { - assert(segment.p != NULL); - - DWORD rva = 0; - DWORD length = 0; - DWORD frame = 0; - if (FAILED(segment->get_relativeVirtualAddress(&rva)) || - FAILED(segment->get_length(&length)) || - FAILED(segment->get_frame(&frame))) { - fprintf(stderr, "Failed to get basic properties for IDiaSegment\n"); - return false; - } - - if (frame > 0) { - DWORD segment_end = rva + length; - if (segment_end > temp_image_length) - temp_image_length = segment_end; - } - segment.Release(); - } - - *image_length = temp_image_length; - return true; -} - -// Detects regions of the original image that have been removed in the -// transformed image, and sets the 'removed' property on all mapped ranges -// immediately preceding a gap. The mapped ranges must be sorted by -// 'rva_original'. -void FillInRemovedLengths(Mapping* mapping) { - assert(mapping != NULL); - - // Find and fill gaps. We do this with two sweeps. We first sweep forward - // looking for gaps. When we identify a gap we then sweep forward with a - // second scan and set the 'removed' property for any intervals that - // immediately precede the gap. - // - // Gaps are typically between two successive intervals, but not always: - // - // Range 1: --------------- - // Range 2: ------- - // Range 3: ------------- - // Gap : ****** - // - // In the above example the gap is between range 1 and range 3. A forward - // sweep finds the gap, and a second forward sweep identifies that range 1 - // immediately precedes the gap and sets its 'removed' property. - - size_t fill = 0; - DWORD rva_front = 0; - for (size_t find = 0; find < mapping->size(); ++find) { -#ifndef NDEBUG - // We expect the mapped ranges to be sorted by 'rva_original'. - if (find > 0) { - assert(mapping->at(find - 1).rva_original <= - mapping->at(find).rva_original); - } -#endif - - if (rva_front < mapping->at(find).rva_original) { - // We've found a gap. Fill it in by setting the 'removed' property for - // any affected intervals. - DWORD removed = mapping->at(find).rva_original - rva_front; - for (; fill < find; ++fill) { - if (mapping->at(fill).rva_original + mapping->at(fill).length != - rva_front) { - continue; - } - - // This interval ends right where the gap starts. It needs to have its - // 'removed' information filled in. - mapping->at(fill).removed = removed; - } - } - - // Advance the front that indicates the covered portion of the image. - rva_front = mapping->at(find).rva_original + mapping->at(find).length; - } -} - -// Builds a unified view of the mapping between the original and transformed -// image space by merging OMAPTO and OMAPFROM data. -void BuildMapping(const OmapData& omap_data, Mapping* mapping) { - assert(mapping != NULL); - - mapping->clear(); - - if (omap_data.omap_from.empty() || omap_data.omap_to.empty()) - return; - - // The names 'omap_to' and 'omap_from' are awfully confusing, so we make - // ourselves more explicit here. This cast is only safe because the underlying - // types have the exact same size. - const OmapToTable& tran2orig = - reinterpret_cast<const OmapToTable&>(omap_data.omap_to); - const OmapFromTable& orig2tran = reinterpret_cast<const OmapFromTable&>( - omap_data.omap_from); - - // Handle the range of data at the beginning of the image. This is not usually - // specified by the OMAP data. - if (tran2orig[0].rva_transformed > 0 && orig2tran[0].rva_original > 0) { - DWORD header_transformed = tran2orig[0].rva_transformed; - DWORD header_original = orig2tran[0].rva_original; - DWORD header = Min(header_transformed, header_original); - - MappedRange mr = {}; - mr.length = header; - mr.injected = header_transformed - header; - mr.removed = header_original - header; - mapping->push_back(mr); - } - - // Convert the implied lengths to explicit lengths, and infer which content - // has been injected into the transformed image. Injected content is inferred - // as regions of the transformed address space that does not map back to - // known valid content in the original image. - for (size_t i = 0; i < tran2orig.size(); ++i) { - const OmapTranToOrig& o1 = tran2orig[i]; - - // This maps to content that is outside the original image, thus it - // describes injected content. We can skip this entry. - if (o1.rva_original >= omap_data.length_original) - continue; - - // Calculate the length of the current OMAP entry. This is implicit as the - // distance between successive |rva| values, capped at the end of the - // original image. - DWORD length = 0; - if (i + 1 < tran2orig.size()) { - const OmapTranToOrig& o2 = tran2orig[i + 1]; - - // We expect the table to be sorted by rva_transformed. - assert(o1.rva_transformed <= o2.rva_transformed); - - length = o2.rva_transformed - o1.rva_transformed; - if (o1.rva_original + length > omap_data.length_original) { - length = omap_data.length_original - o1.rva_original; - } - } else { - length = omap_data.length_original - o1.rva_original; - } - - // Zero-length entries don't describe anything and can be ignored. - if (length == 0) - continue; - - // Any gaps in the transformed address-space are due to injected content. - if (!mapping->empty()) { - MappedRange& prev_mr = mapping->back(); - prev_mr.injected += o1.rva_transformed - - (prev_mr.rva_transformed + prev_mr.length); - } - - MappedRange mr = {}; - mr.rva_original = o1.rva_original; - mr.rva_transformed = o1.rva_transformed; - mr.length = length; - mapping->push_back(mr); - } - - // Sort based on the original image addresses. - std::sort(mapping->begin(), mapping->end(), MappedRangeOriginalLess); - - // Fill in the 'removed' lengths by looking for gaps in the coverage of the - // original address space. - FillInRemovedLengths(mapping); - - return; -} - -void BuildEndpointIndexMap(ImageMap* image_map) { - assert(image_map != NULL); - - if (image_map->mapping.size() == 0) - return; - - const Mapping& mapping = image_map->mapping; - EndpointIndexMap& eim = image_map->endpoint_index_map; - - // Get the unique set of interval endpoints. - std::set<DWORD> endpoints; - for (size_t i = 0; i < mapping.size(); ++i) { - endpoints.insert(mapping[i].rva_original); - endpoints.insert(mapping[i].rva_original + - mapping[i].length + - mapping[i].removed); - } - - // Use the endpoints to initialize the secondary search structure for the - // mapping. - eim.resize(endpoints.size()); - std::set<DWORD>::const_iterator it = endpoints.begin(); - for (size_t i = 0; it != endpoints.end(); ++it, ++i) { - eim[i].endpoint = *it; - eim[i].index = mapping.size(); - } - - // For each endpoint we want the smallest index of any interval containing - // it. We iterate over the intervals and update the indices associated with - // each interval endpoint contained in the current interval. In the general - // case of an arbitrary set of intervals this is O(n^2), but the structure of - // OMAP data makes this O(n). - for (size_t i = 0; i < mapping.size(); ++i) { - EndpointIndex ei1 = { mapping[i].rva_original, 0 }; - EndpointIndexMap::iterator it1 = std::lower_bound( - eim.begin(), eim.end(), ei1, EndpointIndexLess); - - EndpointIndex ei2 = { mapping[i].rva_original + mapping[i].length + - mapping[i].removed, 0 }; - EndpointIndexMap::iterator it2 = std::lower_bound( - eim.begin(), eim.end(), ei2, EndpointIndexLess); - - for (; it1 != it2; ++it1) - it1->index = Min(i, it1->index); - } -} - -// Clips the given mapped range. -void ClipMappedRangeOriginal(const AddressRange& clip_range, - MappedRange* mapped_range) { - assert(mapped_range != NULL); - - // The clipping range is entirely outside of the mapped range. - if (clip_range.end() <= mapped_range->rva_original || - mapped_range->rva_original + mapped_range->length + - mapped_range->removed <= clip_range.rva) { - mapped_range->length = 0; - mapped_range->injected = 0; - mapped_range->removed = 0; - return; - } - - // Clip the left side. - if (mapped_range->rva_original < clip_range.rva) { - DWORD clip_left = clip_range.rva - mapped_range->rva_original; - mapped_range->rva_original += clip_left; - mapped_range->rva_transformed += clip_left; - - if (clip_left > mapped_range->length) { - // The left clipping boundary entirely erases the content section of the - // range. - DWORD trim = clip_left - mapped_range->length; - mapped_range->length = 0; - mapped_range->injected -= Min(trim, mapped_range->injected); - // We know that trim <= mapped_range->remove. - mapped_range->removed -= trim; - } else { - // The left clipping boundary removes some, but not all, of the content. - // As such it leaves the removed/injected component intact. - mapped_range->length -= clip_left; - } - } - - // Clip the right side. - DWORD end_original = mapped_range->rva_original + mapped_range->length; - if (clip_range.end() < end_original) { - // The right clipping boundary lands in the 'content' section of the range, - // entirely clearing the injected/removed portion. - DWORD clip_right = end_original - clip_range.end(); - mapped_range->length -= clip_right; - mapped_range->injected = 0; - mapped_range->removed = 0; - return; - } else { - // The right clipping boundary is outside of the content, but may affect - // the removed/injected portion of the range. - DWORD end_removed = end_original + mapped_range->removed; - if (clip_range.end() < end_removed) - mapped_range->removed = clip_range.end() - end_original; - - DWORD end_injected = end_original + mapped_range->injected; - if (clip_range.end() < end_injected) - mapped_range->injected = clip_range.end() - end_original; - } - - return; -} - -} // namespace - -int AddressRange::Compare(const AddressRange& rhs) const { - if (end() <= rhs.rva) - return -1; - if (rhs.end() <= rva) - return 1; - return 0; -} - -bool GetOmapDataAndDisableTranslation(IDiaSession* session, - OmapData* omap_data) { - assert(session != NULL); - assert(omap_data != NULL); - - CComPtr<IDiaAddressMap> address_map; - if (FAILED(session->QueryInterface(&address_map))) { - fprintf(stderr, "IDiaSession::QueryInterface(IDiaAddressMap) failed\n"); - return false; - } - assert(address_map.p != NULL); - - BOOL omap_enabled = FALSE; - if (FAILED(address_map->get_addressMapEnabled(&omap_enabled))) { - fprintf(stderr, "IDiaAddressMap::get_addressMapEnabled failed\n"); - return false; - } - - if (!omap_enabled) { - // We indicate the non-presence of OMAP data by returning empty tables. - omap_data->omap_from.clear(); - omap_data->omap_to.clear(); - omap_data->length_original = 0; - return true; - } - - // OMAP data is present. Disable translation. - if (FAILED(address_map->put_addressMapEnabled(FALSE))) { - fprintf(stderr, "IDiaAddressMap::put_addressMapEnabled failed\n"); - return false; - } - - // Read the OMAP streams. - if (!FindAndLoadOmapTable(kOmapFromDebugStreamName, - session, - &omap_data->omap_from)) { - return false; - } - if (!FindAndLoadOmapTable(kOmapToDebugStreamName, - session, - &omap_data->omap_to)) { - return false; - } - - // Get the lengths of the address spaces. - if (!GetOriginalImageLength(session, &omap_data->length_original)) - return false; - - return true; -} - -void BuildImageMap(const OmapData& omap_data, ImageMap* image_map) { - assert(image_map != NULL); - - BuildMapping(omap_data, &image_map->mapping); - BuildEndpointIndexMap(image_map); -} - -void MapAddressRange(const ImageMap& image_map, - const AddressRange& original_range, - AddressRangeVector* mapped_ranges) { - assert(mapped_ranges != NULL); - - const Mapping& map = image_map.mapping; - - // Handle the trivial case of an empty image_map. This means that there is - // no transformation to be applied, and we can simply return the original - // range. - if (map.empty()) { - mapped_ranges->push_back(original_range); - return; - } - - // If we get a query of length 0 we need to handle it by using a non-zero - // query length. - AddressRange query_range(original_range); - if (query_range.length == 0) - query_range.length = 1; - - // Find the range of intervals that can potentially intersect our query range. - size_t imin = 0; - size_t imax = 0; - { - // The index of the earliest possible range that can affect is us done by - // searching through the secondary indexing structure. - const EndpointIndexMap& eim = image_map.endpoint_index_map; - EndpointIndex q1 = { query_range.rva, 0 }; - EndpointIndexMap::const_iterator it1 = std::lower_bound( - eim.begin(), eim.end(), q1, EndpointIndexLess); - if (it1 == eim.end()) { - imin = map.size(); - } else { - // Backup to find the interval that contains our query point. - if (it1 != eim.begin() && query_range.rva < it1->endpoint) - --it1; - imin = it1->index; - } - - // The first range that can't possibly intersect us is found by searching - // through the image map directly as it is already sorted by interval start - // point. - MappedRange q2 = { query_range.end(), 0 }; - Mapping::const_iterator it2 = std::lower_bound( - map.begin(), map.end(), q2, MappedRangeOriginalLess); - imax = it2 - map.begin(); - } - - // Find all intervals that intersect the query range. - Mapping temp_map; - for (size_t i = imin; i < imax; ++i) { - MappedRange mr = map[i]; - ClipMappedRangeOriginal(query_range, &mr); - if (mr.length + mr.injected > 0) - temp_map.push_back(mr); - } - - // If there are no intersecting ranges then the query range has been removed - // from the image in question. - if (temp_map.empty()) - return; - - // Sort based on transformed addresses. - std::sort(temp_map.begin(), temp_map.end(), MappedRangeMappedLess); - - // Zero-length queries can't actually be merged. We simply output the set of - // unique RVAs that correspond to the query RVA. - if (original_range.length == 0) { - mapped_ranges->push_back(AddressRange(temp_map[0].rva_transformed, 0)); - for (size_t i = 1; i < temp_map.size(); ++i) { - if (temp_map[i].rva_transformed > mapped_ranges->back().rva) - mapped_ranges->push_back(AddressRange(temp_map[i].rva_transformed, 0)); - } - return; - } - - // Merge any ranges that are consecutive in the mapped image. We merge over - // injected content if it makes ranges contiguous, but we ignore any injected - // content at the tail end of a range. This allows us to detect symbols that - // have been lengthened by injecting content in the middle. However, it - // misses the case where content has been injected at the head or the tail. - // The problem is that it doesn't know whether to attribute it to the - // preceding or following symbol. It is up to the author of the transform to - // output explicit OMAP info in these cases to ensure full coverage of the - // transformed address space. - DWORD rva_begin = temp_map[0].rva_transformed; - DWORD rva_cur_content = rva_begin + temp_map[0].length; - DWORD rva_cur_injected = rva_cur_content + temp_map[0].injected; - for (size_t i = 1; i < temp_map.size(); ++i) { - if (rva_cur_injected < temp_map[i].rva_transformed) { - // This marks the end of a continuous range in the image. Output the - // current range and start a new one. - if (rva_begin < rva_cur_content) { - mapped_ranges->push_back( - AddressRange(rva_begin, rva_cur_content - rva_begin)); - } - rva_begin = temp_map[i].rva_transformed; - } - - rva_cur_content = temp_map[i].rva_transformed + temp_map[i].length; - rva_cur_injected = rva_cur_content + temp_map[i].injected; - } - - // Output the range in progress. - if (rva_begin < rva_cur_content) { - mapped_ranges->push_back( - AddressRange(rva_begin, rva_cur_content - rva_begin)); - } - - return; -} - -} // namespace google_breakpad
\ No newline at end of file diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/omap.h b/toolkit/crashreporter/google-breakpad/src/common/windows/omap.h deleted file mode 100644 index bc293afb5..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/omap.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 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. - -// Provides an API for mapping symbols through OMAP information, if a PDB file -// is augmented with it. This allows breakpad to work with addresses in -// transformed images by transforming the symbols themselves, rather than -// transforming addresses prior to querying symbols (the way it is typically -// done by Windows-native tools, including the DIA). - -#ifndef COMMON_WINDOWS_OMAP_H_ -#define COMMON_WINDOWS_OMAP_H_ - -#include "common/windows/omap_internal.h" - -namespace google_breakpad { - -// If the given session contains OMAP data this extracts it, populating -// |omap_data|, and then disabling automatic translation for the session. -// OMAP data is present in the PDB if |omap_data| is not empty. This returns -// true on success, false otherwise. -bool GetOmapDataAndDisableTranslation(IDiaSession* dia_session, - OmapData* omap_data); - -// Given raw OMAP data builds an ImageMap. This can be used to query individual -// image ranges using MapAddressRange. -// |omap_data|| is the OMAP data extracted from the PDB. -// |image_map| will be populated with a description of the image mapping. If -// |omap_data| is empty then this will also be empty. -void BuildImageMap(const OmapData& omap_data, ImageMap* image_map); - -// Given an address range in the original image space determines how exactly it -// has been tranformed. -// |omap_data| is the OMAP data extracted from the PDB, which must not be -// empty. -// |original_range| is the address range in the original image being queried. -// |mapped_ranges| will be populated with a full description of the mapping. -// They may be disjoint in the transformed image so a vector is needed to -// fully represent the mapping. This will be appended to if it is not -// empty. If |omap_data| is empty then |mapped_ranges| will simply be -// populated with a copy of |original_range| (the identity transform). -void MapAddressRange(const ImageMap& image_map, - const AddressRange& original_range, - AddressRangeVector* mapped_ranges); - -} // namespace google_breakpad - -#endif // COMMON_WINDOWS_OMAP_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/omap_internal.h b/toolkit/crashreporter/google-breakpad/src/common/windows/omap_internal.h deleted file mode 100644 index 3f904d7a7..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/omap_internal.h +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright 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. - -// Declares internal implementation details for functionality in omap.h and -// omap.cc. - -#ifndef COMMON_WINDOWS_OMAP_INTERNAL_H_ -#define COMMON_WINDOWS_OMAP_INTERNAL_H_ - -#include <windows.h> -#include <dia2.h> - -#include <vector> - -namespace google_breakpad { - -// The OMAP struct is defined by debughlp.h, which doesn't play nicely with -// imagehlp.h. We simply redefine it. -struct OMAP { - DWORD rva; - DWORD rvaTo; -}; -static_assert(sizeof(OMAP) == 8, "Wrong size for OMAP structure."); -typedef std::vector<OMAP> OmapTable; - -// This contains the OMAP data extracted from an image. -struct OmapData { - // The table of OMAP entries describing the transformation from the - // original image to the transformed image. - OmapTable omap_from; - // The table of OMAP entries describing the transformation from the - // instrumented image to the original image. - OmapTable omap_to; - // The length of the original untransformed image. - DWORD length_original; - - OmapData() : length_original(0) { } -}; - -// This represents a range of addresses in an image. -struct AddressRange { - DWORD rva; - DWORD length; - - AddressRange() : rva(0), length(0) { } - AddressRange(DWORD rva, DWORD length) : rva(rva), length(length) { } - - // Returns the end address of this range. - DWORD end() const { return rva + length; } - - // Addreses only compare as less-than or greater-than if they are not - // overlapping. Otherwise, they compare equal. - int Compare(const AddressRange& rhs) const; - bool operator<(const AddressRange& rhs) const { return Compare(rhs) == -1; } - bool operator>(const AddressRange& rhs) const { return Compare(rhs) == 1; } - - // Equality operators compare exact values. - bool operator==(const AddressRange& rhs) const { - return rva == rhs.rva && length == rhs.length; - } - bool operator!=(const AddressRange& rhs) const { return !((*this) == rhs); } -}; - -typedef std::vector<AddressRange> AddressRangeVector; - -// This represents an address range in an original image, and its corresponding -// range in the transformed image. -struct MappedRange { - // An address in the original image. - DWORD rva_original; - // The corresponding addresses in the transformed image. - DWORD rva_transformed; - // The length of the address range. - DWORD length; - // It is possible for code to be injected into a transformed image, for which - // there is no corresponding code in the original image. If this range of - // transformed image is immediately followed by such injected code we maintain - // a record of its length here. - DWORD injected; - // It is possible for code to be removed from the original image. This happens - // for things like padding between blocks. There is no actual content lost, - // but the spacing between items may be lost. This keeps track of any removed - // content immediately following the |original| range. - DWORD removed; -}; -// A vector of mapped ranges is used as a more useful representation of -// OMAP data. -typedef std::vector<MappedRange> Mapping; - -// Used as a secondary search structure accompanying a Mapping. -struct EndpointIndex { - DWORD endpoint; - size_t index; -}; -typedef std::vector<EndpointIndex> EndpointIndexMap; - -// An ImageMap is vector of mapped ranges, plus a secondary index into it for -// doing interval searches. (An interval tree would also work, but is overkill -// because we don't need insertion and deletion.) -struct ImageMap { - // This is a description of the mapping between original and transformed - // image, sorted by addresses in the original image. - Mapping mapping; - // For all interval endpoints in |mapping| this stores the minimum index of - // an interval in |mapping| that contains the endpoint. Useful for doing - // interval intersection queries. - EndpointIndexMap endpoint_index_map; -}; - -} // namespace google_breakpad - -#endif // COMMON_WINDOWS_OMAP_INTERNAL_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/omap_unittest.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/omap_unittest.cc deleted file mode 100644 index 960a33f46..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/omap_unittest.cc +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 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.
-
-// Unittests for OMAP related functions.
-
-#include "common/windows/omap.h"
-
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-namespace google_breakpad {
-
-// Equality operators for ContainerEq. These must be outside of the anonymous
-// namespace in order for them to be found.
-bool operator==(const MappedRange& mr1, const MappedRange& mr2) {
- return mr1.rva_original == mr2.rva_original &&
- mr1.rva_transformed == mr2.rva_transformed &&
- mr1.length == mr2.length &&
- mr1.injected == mr2.injected &&
- mr1.removed == mr2.removed;
-}
-bool operator==(const EndpointIndex& ei1, const EndpointIndex& ei2) {
- return ei1.endpoint == ei2.endpoint && ei1.index == ei2.index;
-}
-
-// Pretty printers for more meaningful error messages. Also need to be outside
-// the anonymous namespace.
-std::ostream& operator<<(std::ostream& os, const MappedRange& mr) {
- os << "MappedRange(rva_original=" << mr.rva_original
- << ", rva_transformed=" << mr.rva_transformed
- << ", length=" << mr.length
- << ", injected=" << mr.injected
- << ", removed=" << mr.removed << ")";
- return os;
-}
-std::ostream& operator<<(std::ostream& os, const EndpointIndex& ei) {
- os << "EndpointIndex(endpoint=" << ei.endpoint
- << ", index=" << ei.index << ")";
- return os;
-}
-std::ostream& operator<<(std::ostream& os, const AddressRange& ar) {
- os << "AddressRange(rva=" << ar.rva << ", length=" << ar.length << ")";
- return os;
-}
-
-namespace {
-
-OMAP CreateOmap(DWORD rva, DWORD rvaTo) {
- OMAP o = { rva, rvaTo };
- return o;
-}
-
-MappedRange CreateMappedRange(DWORD rva_original,
- DWORD rva_transformed,
- DWORD length,
- DWORD injected,
- DWORD removed) {
- MappedRange mr = { rva_original, rva_transformed, length, injected, removed };
- return mr;
-}
-
-EndpointIndex CreateEndpointIndex(DWORD endpoint, size_t index) {
- EndpointIndex ei = { endpoint, index };
- return ei;
-}
-
-// (C is removed)
-// Original : A B C D E F G H
-// Transformed: A B D F E * H1 G1 G2 H2
-// (* is injected, G is copied, H is split)
-// A is implied.
-
-// Layout of the original image.
-const AddressRange B(100, 15);
-const AddressRange C(B.end(), 10);
-const AddressRange D(C.end(), 25);
-const AddressRange E(D.end(), 10);
-const AddressRange F(E.end(), 40);
-const AddressRange G(F.end(), 3);
-const AddressRange H(G.end(), 7);
-
-// Layout of the transformed image.
-const AddressRange Bt(100, 15);
-const AddressRange Dt(Bt.end(), 20); // D is shortened.
-const AddressRange Ft(Dt.end(), F.length);
-const AddressRange Et(Ft.end(), E.length);
-const AddressRange injected(Et.end(), 5);
-const AddressRange H1t(injected.end(), 4); // H is split.
-const AddressRange G1t(H1t.end(), G.length); // G is copied.
-const AddressRange G2t(G1t.end(), G.length); // G is copied.
-const AddressRange H2t(G2t.end(), 3); // H is split.
-
-class BuildImageMapTest : public testing::Test {
- public:
- static const DWORD kInvalidAddress = 0xFFFFFFFF;
-
- void InitOmapData() {
- omap_data.length_original = H.end();
-
- // Build the OMAPTO vector (from transformed to original).
- omap_data.omap_to.push_back(CreateOmap(Bt.rva, B.rva));
- omap_data.omap_to.push_back(CreateOmap(Dt.rva, D.rva));
- omap_data.omap_to.push_back(CreateOmap(Ft.rva, F.rva));
- omap_data.omap_to.push_back(CreateOmap(Et.rva, E.rva));
- omap_data.omap_to.push_back(CreateOmap(injected.rva, kInvalidAddress));
- omap_data.omap_to.push_back(CreateOmap(H1t.rva, H.rva));
- omap_data.omap_to.push_back(CreateOmap(G1t.rva, G.rva));
- omap_data.omap_to.push_back(CreateOmap(G2t.rva, G.rva));
- omap_data.omap_to.push_back(CreateOmap(H2t.rva, H.rva + H1t.length));
- omap_data.omap_to.push_back(CreateOmap(H2t.end(), kInvalidAddress));
-
- // Build the OMAPFROM vector (from original to transformed).
- omap_data.omap_from.push_back(CreateOmap(B.rva, Bt.rva));
- omap_data.omap_from.push_back(CreateOmap(C.rva, kInvalidAddress));
- omap_data.omap_from.push_back(CreateOmap(D.rva, Dt.rva));
- omap_data.omap_from.push_back(CreateOmap(E.rva, Et.rva));
- omap_data.omap_from.push_back(CreateOmap(F.rva, Ft.rva));
- omap_data.omap_from.push_back(CreateOmap(G.rva, G1t.rva));
- omap_data.omap_from.push_back(CreateOmap(H.rva, H1t.rva));
- omap_data.omap_from.push_back(CreateOmap(H.rva + H1t.length, H2t.rva));
- omap_data.omap_from.push_back(CreateOmap(H.end(), kInvalidAddress));
- }
-
- OmapData omap_data;
-};
-
-} // namespace
-
-TEST_F(BuildImageMapTest, EmptyImageMapOnEmptyOmapData) {
- ASSERT_EQ(0u, omap_data.omap_from.size());
- ASSERT_EQ(0u, omap_data.omap_to.size());
- ASSERT_EQ(0u, omap_data.length_original);
-
- ImageMap image_map;
- BuildImageMap(omap_data, &image_map);
- EXPECT_EQ(0u, image_map.mapping.size());
- EXPECT_EQ(0u, image_map.endpoint_index_map.size());
-}
-
-TEST_F(BuildImageMapTest, ImageMapIsCorrect) {
- InitOmapData();
- ASSERT_LE(0u, omap_data.omap_from.size());
- ASSERT_LE(0u, omap_data.omap_to.size());
- ASSERT_LE(0u, omap_data.length_original);
-
- ImageMap image_map;
- BuildImageMap(omap_data, &image_map);
- EXPECT_LE(9u, image_map.mapping.size());
- EXPECT_LE(9u, image_map.endpoint_index_map.size());
-
- Mapping mapping;
- mapping.push_back(CreateMappedRange(0, 0, B.rva, 0, 0));
- // C is removed, and it originally comes immediately after B.
- mapping.push_back(CreateMappedRange(B.rva, Bt.rva, B.length, 0, C.length));
- // D is shortened by a length of 5.
- mapping.push_back(CreateMappedRange(D.rva, Dt.rva, Dt.length, 0, 5));
- // The injected content comes immediately after E in the transformed image.
- mapping.push_back(CreateMappedRange(E.rva, Et.rva, E.length, injected.length,
- 0));
- mapping.push_back(CreateMappedRange(F.rva, Ft.rva, F.length, 0, 0));
- // G is copied so creates two entries.
- mapping.push_back(CreateMappedRange(G.rva, G1t.rva, G.length, 0, 0));
- mapping.push_back(CreateMappedRange(G.rva, G2t.rva, G.length, 0, 0));
- // H is split, so create two entries.
- mapping.push_back(CreateMappedRange(H.rva, H1t.rva, H1t.length, 0, 0));
- mapping.push_back(CreateMappedRange(H.rva + H1t.length, H2t.rva, H2t.length,
- 0, 0));
- EXPECT_THAT(mapping,
- testing::ContainerEq(image_map.mapping));
-
- EndpointIndexMap endpoint_index_map;
- endpoint_index_map.push_back(CreateEndpointIndex(0, 0));
- endpoint_index_map.push_back(CreateEndpointIndex(B.rva, 1));
- endpoint_index_map.push_back(CreateEndpointIndex(D.rva, 2));
- endpoint_index_map.push_back(CreateEndpointIndex(E.rva, 3));
- endpoint_index_map.push_back(CreateEndpointIndex(F.rva, 4));
- // G is duplicated so 2 ranges map back to it, hence the skip from 5 to 7.
- endpoint_index_map.push_back(CreateEndpointIndex(G.rva, 5));
- // H is split so we expect 2 endpoints to show up attributed to it.
- endpoint_index_map.push_back(CreateEndpointIndex(H.rva, 7));
- endpoint_index_map.push_back(CreateEndpointIndex(H.rva + H1t.length, 8));
- endpoint_index_map.push_back(CreateEndpointIndex(H.end(), 9));
- EXPECT_THAT(endpoint_index_map,
- testing::ContainerEq(image_map.endpoint_index_map));
-}
-
-namespace {
-
-class MapAddressRangeTest : public BuildImageMapTest {
- public:
- typedef BuildImageMapTest Super;
- virtual void SetUp() {
- Super::SetUp();
- InitOmapData();
- BuildImageMap(omap_data, &image_map);
- }
-
- ImageMap image_map;
-
- private:
- using BuildImageMapTest::InitOmapData;
- using BuildImageMapTest::omap_data;
-};
-
-} // namespace
-
-TEST_F(MapAddressRangeTest, EmptyImageMapReturnsIdentity) {
- ImageMap im;
- AddressRangeVector mapped_ranges;
- AddressRange ar(0, 1024);
- MapAddressRange(im, ar, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_EQ(ar, mapped_ranges[0]);
-}
-
-TEST_F(MapAddressRangeTest, MapOutOfImage) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, AddressRange(H.end() + 10, 10), &mapped_ranges);
- EXPECT_EQ(0u, mapped_ranges.size());
-}
-
-TEST_F(MapAddressRangeTest, MapIdentity) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, B, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(B));
-}
-
-TEST_F(MapAddressRangeTest, MapReorderedContiguous) {
- AddressRangeVector mapped_ranges;
-
- AddressRange DEF(D.rva, F.end() - D.rva);
- MapAddressRange(image_map, DEF, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
-
- AddressRange DFEt(Dt.rva, Et.end() - Dt.rva);
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(DFEt));
-}
-
-TEST_F(MapAddressRangeTest, MapEmptySingle) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, AddressRange(D.rva, 0), &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(Dt.rva, 0)));
-}
-
-TEST_F(MapAddressRangeTest, MapEmptyCopied) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, AddressRange(G.rva, 0), &mapped_ranges);
- EXPECT_EQ(2u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(AddressRange(G1t.rva, 0),
- AddressRange(G2t.rva, 0)));
-}
-
-TEST_F(MapAddressRangeTest, MapCopiedContiguous) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, G, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(
- AddressRange(G1t.rva, G2t.end() - G1t.rva)));
-}
-
-TEST_F(MapAddressRangeTest, MapSplitDiscontiguous) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, H, &mapped_ranges);
- EXPECT_EQ(2u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(H1t, H2t));
-}
-
-TEST_F(MapAddressRangeTest, MapInjected) {
- AddressRangeVector mapped_ranges;
-
- AddressRange EFGH(E.rva, H.end() - E.rva);
- MapAddressRange(image_map, EFGH, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
-
- AddressRange FEHGGHt(Ft.rva, H2t.end() - Ft.rva);
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(FEHGGHt));
-}
-
-TEST_F(MapAddressRangeTest, MapRemovedEntirely) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, C, &mapped_ranges);
- EXPECT_EQ(0u, mapped_ranges.size());
-}
-
-TEST_F(MapAddressRangeTest, MapRemovedPartly) {
- AddressRangeVector mapped_ranges;
- MapAddressRange(image_map, D, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(Dt));
-}
-
-TEST_F(MapAddressRangeTest, MapFull) {
- AddressRangeVector mapped_ranges;
-
- AddressRange AH(0, H.end());
- MapAddressRange(image_map, AH, &mapped_ranges);
- EXPECT_EQ(1u, mapped_ranges.size());
-
- AddressRange AHt(0, H2t.end());
- EXPECT_THAT(mapped_ranges, testing::ElementsAre(AHt));
-}
-
-} // namespace google_breakpad
diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.cc deleted file mode 100644 index 01f4ce3b7..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.cc +++ /dev/null @@ -1,1369 +0,0 @@ -// 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/windows/pdb_source_line_writer.h" - -#include <windows.h> -#include <winnt.h> -#include <atlbase.h> -#include <dia2.h> -#include <diacreate.h> -#include <ImageHlp.h> -#include <stdio.h> - -#include <limits> -#include <set> - -#include "common/windows/dia_util.h" -#include "common/windows/guid_string.h" -#include "common/windows/string_utils-inl.h" - -// This constant may be missing from DbgHelp.h. See the documentation for -// IDiaSymbol::get_undecoratedNameEx. -#ifndef UNDNAME_NO_ECSU -#define UNDNAME_NO_ECSU 0x8000 // Suppresses enum/class/struct/union. -#endif // UNDNAME_NO_ECSU - -/* - * Not defined in WinNT.h for some reason. Definitions taken from: - * http://uninformed.org/index.cgi?v=4&a=1&p=13 - * - */ -typedef unsigned char UBYTE; - -#if !defined(_WIN64) -#define UNW_FLAG_EHANDLER 0x01 -#define UNW_FLAG_UHANDLER 0x02 -#define UNW_FLAG_CHAININFO 0x04 -#endif - -union UnwindCode { - struct { - UBYTE offset_in_prolog; - UBYTE unwind_operation_code : 4; - UBYTE operation_info : 4; - }; - USHORT frame_offset; -}; - -enum UnwindOperationCodes { - UWOP_PUSH_NONVOL = 0, /* info == register number */ - UWOP_ALLOC_LARGE, /* no info, alloc size in next 2 slots */ - UWOP_ALLOC_SMALL, /* info == size of allocation / 8 - 1 */ - UWOP_SET_FPREG, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */ - UWOP_SAVE_NONVOL, /* info == register number, offset in next slot */ - UWOP_SAVE_NONVOL_FAR, /* info == register number, offset in next 2 slots */ - // XXX: these are missing from MSDN! - // See: http://www.osronline.com/ddkx/kmarch/64bitamd_4rs7.htm - UWOP_SAVE_XMM, - UWOP_SAVE_XMM_FAR, - UWOP_SAVE_XMM128, /* info == XMM reg number, offset in next slot */ - UWOP_SAVE_XMM128_FAR, /* info == XMM reg number, offset in next 2 slots */ - UWOP_PUSH_MACHFRAME /* info == 0: no error-code, 1: error-code */ -}; - -// See: http://msdn.microsoft.com/en-us/library/ddssxxy8.aspx -// Note: some fields removed as we don't use them. -struct UnwindInfo { - UBYTE version : 3; - UBYTE flags : 5; - UBYTE size_of_prolog; - UBYTE count_of_codes; - UBYTE frame_register : 4; - UBYTE frame_offset : 4; - UnwindCode unwind_code[1]; -}; - -namespace google_breakpad { - -namespace { - -using std::vector; - -// A helper class to scope a PLOADED_IMAGE. -class AutoImage { - public: - explicit AutoImage(PLOADED_IMAGE img) : img_(img) {} - ~AutoImage() { - if (img_) - ImageUnload(img_); - } - - operator PLOADED_IMAGE() { return img_; } - PLOADED_IMAGE operator->() { return img_; } - - private: - PLOADED_IMAGE img_; -}; - -bool CreateDiaDataSourceInstance(CComPtr<IDiaDataSource> &data_source) { - if (SUCCEEDED(data_source.CoCreateInstance(CLSID_DiaSource))) { - return true; - } - - class DECLSPEC_UUID("B86AE24D-BF2F-4ac9-B5A2-34B14E4CE11D") DiaSource100; - class DECLSPEC_UUID("761D3BCD-1304-41D5-94E8-EAC54E4AC172") DiaSource110; - class DECLSPEC_UUID("3BFCEA48-620F-4B6B-81F7-B9AF75454C7D") DiaSource120; - class DECLSPEC_UUID("E6756135-1E65-4D17-8576-610761398C3C") DiaSource140; - - // If the CoCreateInstance call above failed, msdia*.dll is not registered. - // We can try loading the DLL corresponding to the #included DIA SDK, but - // the DIA headers don't provide a version. Lets try to figure out which DIA - // version we're compiling against by comparing CLSIDs. - const wchar_t *msdia_dll = nullptr; - if (CLSID_DiaSource == _uuidof(DiaSource100)) { - msdia_dll = L"msdia100.dll"; - } else if (CLSID_DiaSource == _uuidof(DiaSource110)) { - msdia_dll = L"msdia110.dll"; - } else if (CLSID_DiaSource == _uuidof(DiaSource120)) { - msdia_dll = L"msdia120.dll"; - } else if (CLSID_DiaSource == _uuidof(DiaSource140)) { - msdia_dll = L"msdia140.dll"; - } - - if (msdia_dll && - SUCCEEDED(NoRegCoCreate(msdia_dll, CLSID_DiaSource, IID_IDiaDataSource, - reinterpret_cast<void **>(&data_source)))) { - return true; - } - - return false; -} - -} // namespace - -PDBSourceLineWriter::PDBSourceLineWriter() : output_(NULL) { -} - -PDBSourceLineWriter::~PDBSourceLineWriter() { -} - -bool PDBSourceLineWriter::SetCodeFile(const wstring &exe_file) { - if (code_file_.empty()) { - code_file_ = exe_file; - return true; - } - // Setting a different code file path is an error. It is success only if the - // file paths are the same. - return exe_file == code_file_; -} - -bool PDBSourceLineWriter::Open(const wstring &file, FileFormat format) { - Close(); - code_file_.clear(); - - if (FAILED(CoInitialize(NULL))) { - fprintf(stderr, "CoInitialize failed\n"); - return false; - } - - CComPtr<IDiaDataSource> data_source; - if (!CreateDiaDataSourceInstance(data_source)) { - const int kGuidSize = 64; - wchar_t classid[kGuidSize] = {0}; - StringFromGUID2(CLSID_DiaSource, classid, kGuidSize); - fprintf(stderr, "CoCreateInstance CLSID_DiaSource %S failed " - "(msdia*.dll unregistered?)\n", classid); - return false; - } - - switch (format) { - case PDB_FILE: - if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { - fprintf(stderr, "loadDataFromPdb failed for %ws\n", file.c_str()); - return false; - } - break; - case EXE_FILE: - if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { - fprintf(stderr, "loadDataForExe failed for %ws\n", file.c_str()); - return false; - } - code_file_ = file; - break; - case ANY_FILE: - if (FAILED(data_source->loadDataFromPdb(file.c_str()))) { - if (FAILED(data_source->loadDataForExe(file.c_str(), NULL, NULL))) { - fprintf(stderr, "loadDataForPdb and loadDataFromExe failed for %ws\n", - file.c_str()); - return false; - } - code_file_ = file; - } - break; - default: - fprintf(stderr, "Unknown file format\n"); - return false; - } - - if (FAILED(data_source->openSession(&session_))) { - fprintf(stderr, "openSession failed\n"); - } - - return true; -} - -bool PDBSourceLineWriter::PrintLines(IDiaEnumLineNumbers *lines) { - // The line number format is: - // <rva> <line number> <source file id> - CComPtr<IDiaLineNumber> line; - ULONG count; - - while (SUCCEEDED(lines->Next(1, &line, &count)) && count == 1) { - DWORD rva; - if (FAILED(line->get_relativeVirtualAddress(&rva))) { - fprintf(stderr, "failed to get line rva\n"); - return false; - } - - DWORD length; - if (FAILED(line->get_length(&length))) { - fprintf(stderr, "failed to get line code length\n"); - return false; - } - - DWORD dia_source_id; - if (FAILED(line->get_sourceFileId(&dia_source_id))) { - fprintf(stderr, "failed to get line source file id\n"); - return false; - } - // duplicate file names are coalesced to share one ID - DWORD source_id = GetRealFileID(dia_source_id); - - DWORD line_num; - if (FAILED(line->get_lineNumber(&line_num))) { - fprintf(stderr, "failed to get line number\n"); - return false; - } - - AddressRangeVector ranges; - MapAddressRange(image_map_, AddressRange(rva, length), &ranges); - for (size_t i = 0; i < ranges.size(); ++i) { - fprintf(output_, "%x %x %d %d\n", ranges[i].rva, ranges[i].length, - line_num, source_id); - } - line.Release(); - } - return true; -} - -bool PDBSourceLineWriter::PrintFunction(IDiaSymbol *function, - IDiaSymbol *block) { - // The function format is: - // FUNC <address> <length> <param_stack_size> <function> - DWORD rva; - if (FAILED(block->get_relativeVirtualAddress(&rva))) { - fprintf(stderr, "couldn't get rva\n"); - return false; - } - - ULONGLONG length; - if (FAILED(block->get_length(&length))) { - fprintf(stderr, "failed to get function length\n"); - return false; - } - - if (length == 0) { - // Silently ignore zero-length functions, which can infrequently pop up. - return true; - } - - CComBSTR name; - int stack_param_size; - if (!GetSymbolFunctionName(function, &name, &stack_param_size)) { - return false; - } - - // If the decorated name didn't give the parameter size, try to - // calculate it. - if (stack_param_size < 0) { - stack_param_size = GetFunctionStackParamSize(function); - } - - AddressRangeVector ranges; - MapAddressRange(image_map_, AddressRange(rva, static_cast<DWORD>(length)), - &ranges); - for (size_t i = 0; i < ranges.size(); ++i) { - fprintf(output_, "FUNC %x %x %x %ws\n", - ranges[i].rva, ranges[i].length, stack_param_size, - name.m_str); - } - - CComPtr<IDiaEnumLineNumbers> lines; - if (FAILED(session_->findLinesByRVA(rva, DWORD(length), &lines))) { - return false; - } - - if (!PrintLines(lines)) { - return false; - } - return true; -} - -bool PDBSourceLineWriter::PrintSourceFiles() { - CComPtr<IDiaSymbol> global; - if (FAILED(session_->get_globalScope(&global))) { - fprintf(stderr, "get_globalScope failed\n"); - return false; - } - - CComPtr<IDiaEnumSymbols> compilands; - if (FAILED(global->findChildren(SymTagCompiland, NULL, - nsNone, &compilands))) { - fprintf(stderr, "findChildren failed\n"); - return false; - } - - CComPtr<IDiaSymbol> compiland; - ULONG count; - while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) { - CComPtr<IDiaEnumSourceFiles> source_files; - if (FAILED(session_->findFile(compiland, NULL, nsNone, &source_files))) { - return false; - } - CComPtr<IDiaSourceFile> file; - while (SUCCEEDED(source_files->Next(1, &file, &count)) && count == 1) { - DWORD file_id; - if (FAILED(file->get_uniqueId(&file_id))) { - return false; - } - - CComBSTR file_name; - if (FAILED(file->get_fileName(&file_name))) { - return false; - } - - wstring file_name_string(file_name); - if (!FileIDIsCached(file_name_string)) { - // this is a new file name, cache it and output a FILE line. - CacheFileID(file_name_string, file_id); - fwprintf(output_, L"FILE %d %ws\n", file_id, file_name_string.c_str()); - } else { - // this file name has already been seen, just save this - // ID for later lookup. - StoreDuplicateFileID(file_name_string, file_id); - } - file.Release(); - } - compiland.Release(); - } - return true; -} - -bool PDBSourceLineWriter::PrintFunctions() { - ULONG count = 0; - DWORD rva = 0; - CComPtr<IDiaSymbol> global; - HRESULT hr; - - if (FAILED(session_->get_globalScope(&global))) { - fprintf(stderr, "get_globalScope failed\n"); - return false; - } - - CComPtr<IDiaEnumSymbols> symbols = NULL; - - // Find all function symbols first. - std::set<DWORD> rvas; - hr = global->findChildren(SymTagFunction, NULL, nsNone, &symbols); - - if (SUCCEEDED(hr)) { - CComPtr<IDiaSymbol> symbol = NULL; - - while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) { - if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) { - // To maintain existing behavior of one symbol per address, place the - // rva onto a set here to uniquify them. - rvas.insert(rva); - } else { - fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n"); - return false; - } - - symbol.Release(); - } - - symbols.Release(); - } - - // Find all public symbols. Store public symbols that are not also private - // symbols for later. - std::set<DWORD> public_only_rvas; - hr = global->findChildren(SymTagPublicSymbol, NULL, nsNone, &symbols); - - if (SUCCEEDED(hr)) { - CComPtr<IDiaSymbol> symbol = NULL; - - while (SUCCEEDED(symbols->Next(1, &symbol, &count)) && count == 1) { - if (SUCCEEDED(symbol->get_relativeVirtualAddress(&rva))) { - if (rvas.count(rva) == 0) { - rvas.insert(rva); // Keep symbols in rva order. - public_only_rvas.insert(rva); - } - } else { - fprintf(stderr, "get_relativeVirtualAddress failed on the symbol\n"); - return false; - } - - symbol.Release(); - } - - symbols.Release(); - } - - std::set<DWORD>::iterator it; - - // For each rva, dump the first symbol DIA knows about at the address. - for (it = rvas.begin(); it != rvas.end(); ++it) { - CComPtr<IDiaSymbol> symbol = NULL; - // If the symbol is not in the public list, look for SymTagFunction. This is - // a workaround to a bug where DIA will hang if searching for a private - // symbol at an address where only a public symbol exists. - // See http://connect.microsoft.com/VisualStudio/feedback/details/722366 - if (public_only_rvas.count(*it) == 0) { - if (SUCCEEDED(session_->findSymbolByRVA(*it, SymTagFunction, &symbol))) { - // Sometimes findSymbolByRVA returns S_OK, but NULL. - if (symbol) { - if (!PrintFunction(symbol, symbol)) - return false; - symbol.Release(); - } - } else { - fprintf(stderr, "findSymbolByRVA SymTagFunction failed\n"); - return false; - } - } else if (SUCCEEDED(session_->findSymbolByRVA(*it, - SymTagPublicSymbol, - &symbol))) { - // Sometimes findSymbolByRVA returns S_OK, but NULL. - if (symbol) { - if (!PrintCodePublicSymbol(symbol)) - return false; - symbol.Release(); - } - } else { - fprintf(stderr, "findSymbolByRVA SymTagPublicSymbol failed\n"); - return false; - } - } - - // When building with PGO, the compiler can split functions into - // "hot" and "cold" blocks, and move the "cold" blocks out to separate - // pages, so the function can be noncontiguous. To find these blocks, - // we have to iterate over all the compilands, and then find blocks - // that are children of them. We can then find the lexical parents - // of those blocks and print out an extra FUNC line for blocks - // that are not contained in their parent functions. - CComPtr<IDiaEnumSymbols> compilands; - if (FAILED(global->findChildren(SymTagCompiland, NULL, - nsNone, &compilands))) { - fprintf(stderr, "findChildren failed on the global\n"); - return false; - } - - CComPtr<IDiaSymbol> compiland; - while (SUCCEEDED(compilands->Next(1, &compiland, &count)) && count == 1) { - CComPtr<IDiaEnumSymbols> blocks; - if (FAILED(compiland->findChildren(SymTagBlock, NULL, - nsNone, &blocks))) { - fprintf(stderr, "findChildren failed on a compiland\n"); - return false; - } - - CComPtr<IDiaSymbol> block; - while (SUCCEEDED(blocks->Next(1, &block, &count)) && count == 1) { - // find this block's lexical parent function - CComPtr<IDiaSymbol> parent; - DWORD tag; - if (SUCCEEDED(block->get_lexicalParent(&parent)) && - SUCCEEDED(parent->get_symTag(&tag)) && - tag == SymTagFunction) { - // now get the block's offset and the function's offset and size, - // and determine if the block is outside of the function - DWORD func_rva, block_rva; - ULONGLONG func_length; - if (SUCCEEDED(block->get_relativeVirtualAddress(&block_rva)) && - SUCCEEDED(parent->get_relativeVirtualAddress(&func_rva)) && - SUCCEEDED(parent->get_length(&func_length))) { - if (block_rva < func_rva || block_rva > (func_rva + func_length)) { - if (!PrintFunction(parent, block)) { - return false; - } - } - } - } - parent.Release(); - block.Release(); - } - blocks.Release(); - compiland.Release(); - } - - global.Release(); - return true; -} - -#undef max - -bool PDBSourceLineWriter::PrintFrameDataUsingPDB() { - // It would be nice if it were possible to output frame data alongside the - // associated function, as is done with line numbers, but the DIA API - // doesn't make it possible to get the frame data in that way. - - CComPtr<IDiaEnumFrameData> frame_data_enum; - if (!FindTable(session_, &frame_data_enum)) - return false; - - DWORD last_type = std::numeric_limits<DWORD>::max(); - DWORD last_rva = std::numeric_limits<DWORD>::max(); - DWORD last_code_size = 0; - DWORD last_prolog_size = std::numeric_limits<DWORD>::max(); - - CComPtr<IDiaFrameData> frame_data; - ULONG count = 0; - while (SUCCEEDED(frame_data_enum->Next(1, &frame_data, &count)) && - count == 1) { - DWORD type; - if (FAILED(frame_data->get_type(&type))) - return false; - - DWORD rva; - if (FAILED(frame_data->get_relativeVirtualAddress(&rva))) - return false; - - DWORD code_size; - if (FAILED(frame_data->get_lengthBlock(&code_size))) - return false; - - DWORD prolog_size; - if (FAILED(frame_data->get_lengthProlog(&prolog_size))) - return false; - - // parameter_size is the size of parameters passed on the stack. If any - // parameters are not passed on the stack (such as in registers), their - // sizes will not be included in parameter_size. - DWORD parameter_size; - if (FAILED(frame_data->get_lengthParams(¶meter_size))) - return false; - - DWORD saved_register_size; - if (FAILED(frame_data->get_lengthSavedRegisters(&saved_register_size))) - return false; - - DWORD local_size; - if (FAILED(frame_data->get_lengthLocals(&local_size))) - return false; - - // get_maxStack can return S_FALSE, just use 0 in that case. - DWORD max_stack_size = 0; - if (FAILED(frame_data->get_maxStack(&max_stack_size))) - return false; - - // get_programString can return S_FALSE, indicating that there is no - // program string. In that case, check whether %ebp is used. - HRESULT program_string_result; - CComBSTR program_string; - if (FAILED(program_string_result = frame_data->get_program( - &program_string))) { - return false; - } - - // get_allocatesBasePointer can return S_FALSE, treat that as though - // %ebp is not used. - BOOL allocates_base_pointer = FALSE; - if (program_string_result != S_OK) { - if (FAILED(frame_data->get_allocatesBasePointer( - &allocates_base_pointer))) { - return false; - } - } - - // Only print out a line if type, rva, code_size, or prolog_size have - // changed from the last line. It is surprisingly common (especially in - // system library PDBs) for DIA to return a series of identical - // IDiaFrameData objects. For kernel32.pdb from Windows XP SP2 on x86, - // this check reduces the size of the dumped symbol file by a third. - if (type != last_type || rva != last_rva || code_size != last_code_size || - prolog_size != last_prolog_size) { - // The prolog and the code portions of the frame have to be treated - // independently as they may have independently changed in size, or may - // even have been split. - // NOTE: If epilog size is ever non-zero, we have to do something - // similar with it. - - // Figure out where the prolog bytes have landed. - AddressRangeVector prolog_ranges; - if (prolog_size > 0) { - MapAddressRange(image_map_, AddressRange(rva, prolog_size), - &prolog_ranges); - } - - // And figure out where the code bytes have landed. - AddressRangeVector code_ranges; - MapAddressRange(image_map_, - AddressRange(rva + prolog_size, - code_size - prolog_size), - &code_ranges); - - struct FrameInfo { - DWORD rva; - DWORD code_size; - DWORD prolog_size; - }; - std::vector<FrameInfo> frame_infos; - - // Special case: The prolog and the code bytes remain contiguous. This is - // only done for compactness of the symbol file, and we could actually - // be outputting independent frame info for the prolog and code portions. - if (prolog_ranges.size() == 1 && code_ranges.size() == 1 && - prolog_ranges[0].end() == code_ranges[0].rva) { - FrameInfo fi = { prolog_ranges[0].rva, - prolog_ranges[0].length + code_ranges[0].length, - prolog_ranges[0].length }; - frame_infos.push_back(fi); - } else { - // Otherwise we output the prolog and code frame info independently. - for (size_t i = 0; i < prolog_ranges.size(); ++i) { - FrameInfo fi = { prolog_ranges[i].rva, - prolog_ranges[i].length, - prolog_ranges[i].length }; - frame_infos.push_back(fi); - } - for (size_t i = 0; i < code_ranges.size(); ++i) { - FrameInfo fi = { code_ranges[i].rva, code_ranges[i].length, 0 }; - frame_infos.push_back(fi); - } - } - - for (size_t i = 0; i < frame_infos.size(); ++i) { - const FrameInfo& fi(frame_infos[i]); - fprintf(output_, "STACK WIN %x %x %x %x %x %x %x %x %x %d ", - type, fi.rva, fi.code_size, fi.prolog_size, - 0 /* epilog_size */, parameter_size, saved_register_size, - local_size, max_stack_size, program_string_result == S_OK); - if (program_string_result == S_OK) { - fprintf(output_, "%ws\n", program_string.m_str); - } else { - fprintf(output_, "%d\n", allocates_base_pointer); - } - } - - last_type = type; - last_rva = rva; - last_code_size = code_size; - last_prolog_size = prolog_size; - } - - frame_data.Release(); - } - - return true; -} - -bool PDBSourceLineWriter::PrintFrameDataUsingEXE() { - if (code_file_.empty() && !FindPEFile()) { - fprintf(stderr, "Couldn't locate EXE or DLL file.\n"); - return false; - } - - // Convert wchar to native charset because ImageLoad only takes - // a PSTR as input. - string code_file; - if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) { - return false; - } - - AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL)); - if (!img) { - fprintf(stderr, "Failed to load %s\n", code_file.c_str()); - return false; - } - PIMAGE_OPTIONAL_HEADER64 optional_header = - &(reinterpret_cast<PIMAGE_NT_HEADERS64>(img->FileHeader))->OptionalHeader; - if (optional_header->Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - fprintf(stderr, "Not a PE32+ image\n"); - return false; - } - - // Read Exception Directory - DWORD exception_rva = optional_header-> - DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress; - DWORD exception_size = optional_header-> - DataDirectory[IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size; - PIMAGE_RUNTIME_FUNCTION_ENTRY funcs = - static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>( - ImageRvaToVa(img->FileHeader, - img->MappedAddress, - exception_rva, - &img->LastRvaSection)); - for (DWORD i = 0; i < exception_size / sizeof(*funcs); i++) { - DWORD unwind_rva = funcs[i].UnwindInfoAddress; - // handle chaining - while (unwind_rva & 0x1) { - unwind_rva ^= 0x1; - PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func = - static_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>( - ImageRvaToVa(img->FileHeader, - img->MappedAddress, - unwind_rva, - &img->LastRvaSection)); - unwind_rva = chained_func->UnwindInfoAddress; - } - - UnwindInfo *unwind_info = static_cast<UnwindInfo *>( - ImageRvaToVa(img->FileHeader, - img->MappedAddress, - unwind_rva, - &img->LastRvaSection)); - - DWORD stack_size = 8; // minimal stack size is 8 for RIP - DWORD rip_offset = 8; - do { - for (UBYTE c = 0; c < unwind_info->count_of_codes; c++) { - UnwindCode *unwind_code = &unwind_info->unwind_code[c]; - switch (unwind_code->unwind_operation_code) { - case UWOP_PUSH_NONVOL: { - stack_size += 8; - break; - } - case UWOP_ALLOC_LARGE: { - if (unwind_code->operation_info == 0) { - c++; - if (c < unwind_info->count_of_codes) - stack_size += (unwind_code + 1)->frame_offset * 8; - } else { - c += 2; - if (c < unwind_info->count_of_codes) - stack_size += (unwind_code + 1)->frame_offset | - ((unwind_code + 2)->frame_offset << 16); - } - break; - } - case UWOP_ALLOC_SMALL: { - stack_size += unwind_code->operation_info * 8 + 8; - break; - } - case UWOP_SET_FPREG: - case UWOP_SAVE_XMM: - case UWOP_SAVE_XMM_FAR: - break; - case UWOP_SAVE_NONVOL: - case UWOP_SAVE_XMM128: { - c++; // skip slot with offset - break; - } - case UWOP_SAVE_NONVOL_FAR: - case UWOP_SAVE_XMM128_FAR: { - c += 2; // skip 2 slots with offset - break; - } - case UWOP_PUSH_MACHFRAME: { - if (unwind_code->operation_info) { - stack_size += 88; - } else { - stack_size += 80; - } - rip_offset += 80; - break; - } - } - } - if (unwind_info->flags & UNW_FLAG_CHAININFO) { - PIMAGE_RUNTIME_FUNCTION_ENTRY chained_func = - reinterpret_cast<PIMAGE_RUNTIME_FUNCTION_ENTRY>( - (unwind_info->unwind_code + - ((unwind_info->count_of_codes + 1) & ~1))); - - unwind_info = static_cast<UnwindInfo *>( - ImageRvaToVa(img->FileHeader, - img->MappedAddress, - chained_func->UnwindInfoAddress, - &img->LastRvaSection)); - } else { - unwind_info = NULL; - } - } while (unwind_info); - fprintf(output_, "STACK CFI INIT %x %x .cfa: $rsp .ra: .cfa %d - ^\n", - funcs[i].BeginAddress, - funcs[i].EndAddress - funcs[i].BeginAddress, rip_offset); - fprintf(output_, "STACK CFI %x .cfa: $rsp %d +\n", - funcs[i].BeginAddress, stack_size); - } - - return true; -} - -bool PDBSourceLineWriter::PrintFrameData() { - PDBModuleInfo info; - if (GetModuleInfo(&info) && info.cpu == L"x86_64") { - return PrintFrameDataUsingEXE(); - } else { - return PrintFrameDataUsingPDB(); - } - return false; -} - -bool PDBSourceLineWriter::PrintCodePublicSymbol(IDiaSymbol *symbol) { - BOOL is_code; - if (FAILED(symbol->get_code(&is_code))) { - return false; - } - if (!is_code) { - return true; - } - - DWORD rva; - if (FAILED(symbol->get_relativeVirtualAddress(&rva))) { - return false; - } - - CComBSTR name; - int stack_param_size; - if (!GetSymbolFunctionName(symbol, &name, &stack_param_size)) { - return false; - } - - AddressRangeVector ranges; - MapAddressRange(image_map_, AddressRange(rva, 1), &ranges); - for (size_t i = 0; i < ranges.size(); ++i) { - fprintf(output_, "PUBLIC %x %x %ws\n", ranges[i].rva, - stack_param_size > 0 ? stack_param_size : 0, - name.m_str); - } - return true; -} - -bool PDBSourceLineWriter::PrintPDBInfo() { - PDBModuleInfo info; - if (!GetModuleInfo(&info)) { - return false; - } - - // Hard-code "windows" for the OS because that's the only thing that makes - // sense for PDB files. (This might not be strictly correct for Windows CE - // support, but we don't care about that at the moment.) - fprintf(output_, "MODULE windows %ws %ws %ws\n", - info.cpu.c_str(), info.debug_identifier.c_str(), - info.debug_file.c_str()); - - return true; -} - -bool PDBSourceLineWriter::PrintPEInfo() { - PEModuleInfo info; - if (!GetPEInfo(&info)) { - return false; - } - - fprintf(output_, "INFO CODE_ID %ws %ws\n", - info.code_identifier.c_str(), - info.code_file.c_str()); - return true; -} - -// wcstol_positive_strict is sort of like wcstol, but much stricter. string -// should be a buffer pointing to a null-terminated string containing only -// decimal digits. If the entire string can be converted to an integer -// without overflowing, and there are no non-digit characters before the -// result is set to the value and this function returns true. Otherwise, -// this function returns false. This is an alternative to the strtol, atoi, -// and scanf families, which are not as strict about input and in some cases -// don't provide a good way for the caller to determine if a conversion was -// successful. -static bool wcstol_positive_strict(wchar_t *string, int *result) { - int value = 0; - for (wchar_t *c = string; *c != '\0'; ++c) { - int last_value = value; - value *= 10; - // Detect overflow. - if (value / 10 != last_value || value < 0) { - return false; - } - if (*c < '0' || *c > '9') { - return false; - } - unsigned int c_value = *c - '0'; - last_value = value; - value += c_value; - // Detect overflow. - if (value < last_value) { - return false; - } - // Forbid leading zeroes unless the string is just "0". - if (value == 0 && *(c+1) != '\0') { - return false; - } - } - *result = value; - return true; -} - -bool PDBSourceLineWriter::FindPEFile() { - CComPtr<IDiaSymbol> global; - if (FAILED(session_->get_globalScope(&global))) { - fprintf(stderr, "get_globalScope failed\n"); - return false; - } - - CComBSTR symbols_file; - if (SUCCEEDED(global->get_symbolsFileName(&symbols_file))) { - wstring file(symbols_file); - - // Look for an EXE or DLL file. - const wchar_t *extensions[] = { L"exe", L"dll" }; - for (int i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++) { - size_t dot_pos = file.find_last_of(L"."); - if (dot_pos != wstring::npos) { - file.replace(dot_pos + 1, wstring::npos, extensions[i]); - // Check if this file exists. - if (GetFileAttributesW(file.c_str()) != INVALID_FILE_ATTRIBUTES) { - code_file_ = file; - return true; - } - } - } - } - - return false; -} - -// static -bool PDBSourceLineWriter::GetSymbolFunctionName(IDiaSymbol *function, - BSTR *name, - int *stack_param_size) { - *stack_param_size = -1; - const DWORD undecorate_options = UNDNAME_NO_MS_KEYWORDS | - UNDNAME_NO_FUNCTION_RETURNS | - UNDNAME_NO_ALLOCATION_MODEL | - UNDNAME_NO_ALLOCATION_LANGUAGE | - UNDNAME_NO_THISTYPE | - UNDNAME_NO_ACCESS_SPECIFIERS | - UNDNAME_NO_THROW_SIGNATURES | - UNDNAME_NO_MEMBER_TYPE | - UNDNAME_NO_RETURN_UDT_MODEL | - UNDNAME_NO_ECSU; - - // Use get_undecoratedNameEx to get readable C++ names with arguments. - if (function->get_undecoratedNameEx(undecorate_options, name) != S_OK) { - if (function->get_name(name) != S_OK) { - fprintf(stderr, "failed to get function name\n"); - return false; - } - - // It's possible for get_name to return an empty string, so - // special-case that. - if (wcscmp(*name, L"") == 0) { - SysFreeString(*name); - // dwarf_cu_to_module.cc uses "<name omitted>", so match that. - *name = SysAllocString(L"<name omitted>"); - return true; - } - - // If a name comes from get_name because no undecorated form existed, - // it's already formatted properly to be used as output. Don't do any - // additional processing. - // - // MSVC7's DIA seems to not undecorate names in as many cases as MSVC8's. - // This will result in calling get_name for some C++ symbols, so - // all of the parameter and return type information may not be included in - // the name string. - } else { - // C++ uses a bogus "void" argument for functions and methods that don't - // take any parameters. Take it out of the undecorated name because it's - // ugly and unnecessary. - const wchar_t *replace_string = L"(void)"; - const size_t replace_length = wcslen(replace_string); - const wchar_t *replacement_string = L"()"; - size_t length = wcslen(*name); - if (length >= replace_length) { - wchar_t *name_end = *name + length - replace_length; - if (wcscmp(name_end, replace_string) == 0) { - WindowsStringUtils::safe_wcscpy(name_end, replace_length, - replacement_string); - length = wcslen(*name); - } - } - - // Undecorate names used for stdcall and fastcall. These names prefix - // the identifier with '_' (stdcall) or '@' (fastcall) and suffix it - // with '@' followed by the number of bytes of parameters, in decimal. - // If such a name is found, take note of the size and undecorate it. - // Only do this for names that aren't C++, which is determined based on - // whether the undecorated name contains any ':' or '(' characters. - if (!wcschr(*name, ':') && !wcschr(*name, '(') && - (*name[0] == '_' || *name[0] == '@')) { - wchar_t *last_at = wcsrchr(*name + 1, '@'); - if (last_at && wcstol_positive_strict(last_at + 1, stack_param_size)) { - // If this function adheres to the fastcall convention, it accepts up - // to the first 8 bytes of parameters in registers (%ecx and %edx). - // We're only interested in the stack space used for parameters, so - // so subtract 8 and don't let the size go below 0. - if (*name[0] == '@') { - if (*stack_param_size > 8) { - *stack_param_size -= 8; - } else { - *stack_param_size = 0; - } - } - - // Undecorate the name by moving it one character to the left in its - // buffer, and terminating it where the last '@' had been. - WindowsStringUtils::safe_wcsncpy(*name, length, - *name + 1, last_at - *name - 1); - } else if (*name[0] == '_') { - // This symbol's name is encoded according to the cdecl rules. The - // name doesn't end in a '@' character followed by a decimal positive - // integer, so it's not a stdcall name. Strip off the leading - // underscore. - WindowsStringUtils::safe_wcsncpy(*name, length, *name + 1, length); - } - } - } - - return true; -} - -// static -int PDBSourceLineWriter::GetFunctionStackParamSize(IDiaSymbol *function) { - // This implementation is highly x86-specific. - - // Gather the symbols corresponding to data. - CComPtr<IDiaEnumSymbols> data_children; - if (FAILED(function->findChildren(SymTagData, NULL, nsNone, - &data_children))) { - return 0; - } - - // lowest_base is the lowest %ebp-relative byte offset used for a parameter. - // highest_end is one greater than the highest offset (i.e. base + length). - // Stack parameters are assumed to be contiguous, because in reality, they - // are. - int lowest_base = INT_MAX; - int highest_end = INT_MIN; - - CComPtr<IDiaSymbol> child; - DWORD count; - while (SUCCEEDED(data_children->Next(1, &child, &count)) && count == 1) { - // If any operation fails at this point, just proceed to the next child. - // Use the next_child label instead of continue because child needs to - // be released before it's reused. Declare constructable/destructable - // types early to avoid gotos that cross initializations. - CComPtr<IDiaSymbol> child_type; - - // DataIsObjectPtr is only used for |this|. Because |this| can be passed - // as a stack parameter, look for it in addition to traditional - // parameters. - DWORD child_kind; - if (FAILED(child->get_dataKind(&child_kind)) || - (child_kind != DataIsParam && child_kind != DataIsObjectPtr)) { - goto next_child; - } - - // Only concentrate on register-relative parameters. Parameters may also - // be enregistered (passed directly in a register), but those don't - // consume any stack space, so they're not of interest. - DWORD child_location_type; - if (FAILED(child->get_locationType(&child_location_type)) || - child_location_type != LocIsRegRel) { - goto next_child; - } - - // Of register-relative parameters, the only ones that make any sense are - // %ebp- or %esp-relative. Note that MSVC's debugging information always - // gives parameters as %ebp-relative even when a function doesn't use a - // traditional frame pointer and stack parameters are accessed relative to - // %esp, so just look for %ebp-relative parameters. If you wanted to - // access parameters, you'd probably want to treat these %ebp-relative - // offsets as if they were relative to %esp before a function's prolog - // executed. - DWORD child_register; - if (FAILED(child->get_registerId(&child_register)) || - child_register != CV_REG_EBP) { - goto next_child; - } - - LONG child_register_offset; - if (FAILED(child->get_offset(&child_register_offset))) { - goto next_child; - } - - // IDiaSymbol::get_type can succeed but still pass back a NULL value. - if (FAILED(child->get_type(&child_type)) || !child_type) { - goto next_child; - } - - ULONGLONG child_length; - if (FAILED(child_type->get_length(&child_length))) { - goto next_child; - } - - int child_end = child_register_offset + static_cast<ULONG>(child_length); - if (child_register_offset < lowest_base) { - lowest_base = child_register_offset; - } - if (child_end > highest_end) { - highest_end = child_end; - } - -next_child: - child.Release(); - } - - int param_size = 0; - // Make sure lowest_base isn't less than 4, because [%esp+4] is the lowest - // possible address to find a stack parameter before executing a function's - // prolog (see above). Some optimizations cause parameter offsets to be - // lower than 4, but we're not concerned with those because we're only - // looking for parameters contained in addresses higher than where the - // return address is stored. - if (lowest_base < 4) { - lowest_base = 4; - } - if (highest_end > lowest_base) { - // All stack parameters are pushed as at least 4-byte quantities. If the - // last type was narrower than 4 bytes, promote it. This assumes that all - // parameters' offsets are 4-byte-aligned, which is always the case. Only - // worry about the last type, because we're not summing the type sizes, - // just looking at the lowest and highest offsets. - int remainder = highest_end % 4; - if (remainder) { - highest_end += 4 - remainder; - } - - param_size = highest_end - lowest_base; - } - - return param_size; -} - -bool PDBSourceLineWriter::WriteMap(FILE *map_file) { - output_ = map_file; - - // Load the OMAP information, and disable auto-translation of addresses in - // preference of doing it ourselves. - OmapData omap_data; - if (!GetOmapDataAndDisableTranslation(session_, &omap_data)) - return false; - BuildImageMap(omap_data, &image_map_); - - bool ret = PrintPDBInfo(); - // This is not a critical piece of the symbol file. - PrintPEInfo(); - ret = ret && - PrintSourceFiles() && - PrintFunctions() && - PrintFrameData(); - - output_ = NULL; - return ret; -} - -void PDBSourceLineWriter::Close() { - session_.Release(); -} - -bool PDBSourceLineWriter::GetModuleInfo(PDBModuleInfo *info) { - if (!info) { - return false; - } - - info->debug_file.clear(); - info->debug_identifier.clear(); - info->cpu.clear(); - - CComPtr<IDiaSymbol> global; - if (FAILED(session_->get_globalScope(&global))) { - return false; - } - - DWORD machine_type; - // get_machineType can return S_FALSE. - if (global->get_machineType(&machine_type) == S_OK) { - // The documentation claims that get_machineType returns a value from - // the CV_CPU_TYPE_e enumeration, but that's not the case. - // Instead, it returns one of the IMAGE_FILE_MACHINE values as - // defined here: - // http://msdn.microsoft.com/en-us/library/ms680313%28VS.85%29.aspx - switch (machine_type) { - case IMAGE_FILE_MACHINE_I386: - info->cpu = L"x86"; - break; - case IMAGE_FILE_MACHINE_AMD64: - info->cpu = L"x86_64"; - break; - default: - info->cpu = L"unknown"; - break; - } - } else { - // Unexpected, but handle gracefully. - info->cpu = L"unknown"; - } - - // DWORD* and int* are not compatible. This is clean and avoids a cast. - DWORD age; - if (FAILED(global->get_age(&age))) { - return false; - } - - bool uses_guid; - if (!UsesGUID(&uses_guid)) { - return false; - } - - if (uses_guid) { - GUID guid; - if (FAILED(global->get_guid(&guid))) { - return false; - } - - // Use the same format that the MS symbol server uses in filesystem - // hierarchies. - wchar_t age_string[9]; - swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]), - L"%x", age); - - // remove when VC++7.1 is no longer supported - age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0'; - - info->debug_identifier = GUIDString::GUIDToSymbolServerWString(&guid); - info->debug_identifier.append(age_string); - } else { - DWORD signature; - if (FAILED(global->get_signature(&signature))) { - return false; - } - - // Use the same format that the MS symbol server uses in filesystem - // hierarchies. - wchar_t identifier_string[17]; - swprintf(identifier_string, - sizeof(identifier_string) / sizeof(identifier_string[0]), - L"%08X%x", signature, age); - - // remove when VC++7.1 is no longer supported - identifier_string[sizeof(identifier_string) / - sizeof(identifier_string[0]) - 1] = L'\0'; - - info->debug_identifier = identifier_string; - } - - CComBSTR debug_file_string; - if (FAILED(global->get_symbolsFileName(&debug_file_string))) { - return false; - } - info->debug_file = - WindowsStringUtils::GetBaseName(wstring(debug_file_string)); - - return true; -} - -bool PDBSourceLineWriter::GetPEInfo(PEModuleInfo *info) { - if (!info) { - return false; - } - - if (code_file_.empty() && !FindPEFile()) { - fprintf(stderr, "Couldn't locate EXE or DLL file.\n"); - return false; - } - - // Convert wchar to native charset because ImageLoad only takes - // a PSTR as input. - string code_file; - if (!WindowsStringUtils::safe_wcstombs(code_file_, &code_file)) { - return false; - } - - AutoImage img(ImageLoad((PSTR)code_file.c_str(), NULL)); - if (!img) { - fprintf(stderr, "Failed to open PE file: %s\n", code_file.c_str()); - return false; - } - - info->code_file = WindowsStringUtils::GetBaseName(code_file_); - - // The date and time that the file was created by the linker. - DWORD TimeDateStamp = img->FileHeader->FileHeader.TimeDateStamp; - // The size of the file in bytes, including all headers. - DWORD SizeOfImage = 0; - PIMAGE_OPTIONAL_HEADER64 opt = - &((PIMAGE_NT_HEADERS64)img->FileHeader)->OptionalHeader; - if (opt->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC) { - // 64-bit PE file. - SizeOfImage = opt->SizeOfImage; - } else { - // 32-bit PE file. - SizeOfImage = img->FileHeader->OptionalHeader.SizeOfImage; - } - wchar_t code_identifier[32]; - swprintf(code_identifier, - sizeof(code_identifier) / sizeof(code_identifier[0]), - L"%08X%X", TimeDateStamp, SizeOfImage); - info->code_identifier = code_identifier; - - return true; -} - -bool PDBSourceLineWriter::UsesGUID(bool *uses_guid) { - if (!uses_guid) - return false; - - CComPtr<IDiaSymbol> global; - if (FAILED(session_->get_globalScope(&global))) - return false; - - GUID guid; - if (FAILED(global->get_guid(&guid))) - return false; - - DWORD signature; - if (FAILED(global->get_signature(&signature))) - return false; - - // There are two possibilities for guid: either it's a real 128-bit GUID - // as identified in a code module by a new-style CodeView record, or it's - // a 32-bit signature (timestamp) as identified by an old-style record. - // See MDCVInfoPDB70 and MDCVInfoPDB20 in minidump_format.h. - // - // Because DIA doesn't provide a way to directly determine whether a module - // uses a GUID or a 32-bit signature, this code checks whether the first 32 - // bits of guid are the same as the signature, and if the rest of guid is - // zero. If so, then with a pretty high degree of certainty, there's an - // old-style CodeView record in use. This method will only falsely find an - // an old-style CodeView record if a real 128-bit GUID has its first 32 - // bits set the same as the module's signature (timestamp) and the rest of - // the GUID is set to 0. This is highly unlikely. - - GUID signature_guid = {signature}; // 0-initializes other members - *uses_guid = !IsEqualGUID(guid, signature_guid); - return true; -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.h b/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.h deleted file mode 100644 index e9e89bb27..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/pdb_source_line_writer.h +++ /dev/null @@ -1,257 +0,0 @@ -// 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. - -// PDBSourceLineWriter uses a pdb file produced by Visual C++ to output -// a line/address map for use with BasicSourceLineResolver. - -#ifndef COMMON_WINDOWS_PDB_SOURCE_LINE_WRITER_H_ -#define COMMON_WINDOWS_PDB_SOURCE_LINE_WRITER_H_ - -#include <atlcomcli.h> - -#include <unordered_map> -#include <string> - -#include "common/windows/omap.h" - -struct IDiaEnumLineNumbers; -struct IDiaSession; -struct IDiaSymbol; - -namespace google_breakpad { - -using std::wstring; -using std::unordered_map; - -// A structure that carries information that identifies a pdb file. -struct PDBModuleInfo { - public: - // The basename of the pdb file from which information was loaded. - wstring debug_file; - - // The pdb's identifier. For recent pdb files, the identifier consists - // of the pdb's guid, in uppercase hexadecimal form without any dashes - // or separators, followed immediately by the pdb's age, also in - // uppercase hexadecimal form. For older pdb files which have no guid, - // the identifier is the pdb's 32-bit signature value, in zero-padded - // hexadecimal form, followed immediately by the pdb's age, in lowercase - // hexadecimal form. - wstring debug_identifier; - - // A string identifying the cpu that the pdb is associated with. - // Currently, this may be "x86" or "unknown". - wstring cpu; -}; - -// A structure that carries information that identifies a PE file, -// either an EXE or a DLL. -struct PEModuleInfo { - // The basename of the PE file. - wstring code_file; - - // The PE file's code identifier, which consists of its timestamp - // and file size concatenated together into a single hex string. - // (The fields IMAGE_OPTIONAL_HEADER::SizeOfImage and - // IMAGE_FILE_HEADER::TimeDateStamp, as defined in the ImageHlp - // documentation.) This is not well documented, if it's documented - // at all, but it's what symstore does and what DbgHelp supports. - wstring code_identifier; -}; - -class PDBSourceLineWriter { - public: - enum FileFormat { - PDB_FILE, // a .pdb file containing debug symbols - EXE_FILE, // a .exe or .dll file - ANY_FILE // try PDB_FILE and then EXE_FILE - }; - - explicit PDBSourceLineWriter(); - ~PDBSourceLineWriter(); - - // Opens the given file. For executable files, the corresponding pdb - // file must be available; Open will be if it is not. - // If there is already a pdb file open, it is automatically closed. - // Returns true on success. - bool Open(const wstring &file, FileFormat format); - - // Sets the code file full path. This is optional for 32-bit modules. It is - // also optional for 64-bit modules when there is an executable file stored - // in the same directory as the PDB file. It is only required for 64-bit - // modules when the executable file is not in the same location as the PDB - // file and it must be called after Open() and before WriteMap(). - // If Open() was called for an executable file, then it is an error to call - // SetCodeFile() with a different file path and it will return false. - bool SetCodeFile(const wstring &exe_file); - - // Writes a map file from the current pdb file to the given file stream. - // Returns true on success. - bool WriteMap(FILE *map_file); - - // Closes the current pdb file and its associated resources. - void Close(); - - // Retrieves information about the module's debugging file. Returns - // true on success and false on failure. - bool GetModuleInfo(PDBModuleInfo *info); - - // Retrieves information about the module's PE file. Returns - // true on success and false on failure. - bool GetPEInfo(PEModuleInfo *info); - - // Sets uses_guid to true if the opened file uses a new-style CodeView - // record with a 128-bit GUID, or false if the opened file uses an old-style - // CodeView record. When no GUID is available, a 32-bit signature should be - // used to identify the module instead. If the information cannot be - // determined, this method returns false. - bool UsesGUID(bool *uses_guid); - - private: - // Outputs the line/address pairs for each line in the enumerator. - // Returns true on success. - bool PrintLines(IDiaEnumLineNumbers *lines); - - // Outputs a function address and name, followed by its source line list. - // block can be the same object as function, or it can be a reference - // to a code block that is lexically part of this function, but - // resides at a separate address. - // Returns true on success. - bool PrintFunction(IDiaSymbol *function, IDiaSymbol *block); - - // Outputs all functions as described above. Returns true on success. - bool PrintFunctions(); - - // Outputs all of the source files in the session's pdb file. - // Returns true on success. - bool PrintSourceFiles(); - - // Outputs all of the frame information necessary to construct stack - // backtraces in the absence of frame pointers. For x86 data stored in - // .pdb files. Returns true on success. - bool PrintFrameDataUsingPDB(); - - // Outputs all of the frame information necessary to construct stack - // backtraces in the absence of frame pointers. For x64 data stored in - // .exe, .dll files. Returns true on success. - bool PrintFrameDataUsingEXE(); - - // Outputs all of the frame information necessary to construct stack - // backtraces in the absence of frame pointers. Returns true on success. - bool PrintFrameData(); - - // Outputs a single public symbol address and name, if the symbol corresponds - // to a code address. Returns true on success. If symbol is does not - // correspond to code, returns true without outputting anything. - bool PrintCodePublicSymbol(IDiaSymbol *symbol); - - // Outputs a line identifying the PDB file that is being dumped, along with - // its uuid and age. - bool PrintPDBInfo(); - - // Outputs a line identifying the PE file corresponding to the PDB - // file that is being dumped, along with its code identifier, - // which consists of its timestamp and file size. - bool PrintPEInfo(); - - // Returns true if this filename has already been seen, - // and an ID is stored for it, or false if it has not. - bool FileIDIsCached(const wstring &file) { - return unique_files_.find(file) != unique_files_.end(); - } - - // Cache this filename and ID for later reuse. - void CacheFileID(const wstring &file, DWORD id) { - unique_files_[file] = id; - } - - // Store this ID in the cache as a duplicate for this filename. - void StoreDuplicateFileID(const wstring &file, DWORD id) { - unordered_map<wstring, DWORD>::iterator iter = unique_files_.find(file); - if (iter != unique_files_.end()) { - // map this id to the previously seen one - file_ids_[id] = iter->second; - } - } - - // Given a file's unique ID, return the ID that should be used to - // reference it. There may be multiple files with identical filenames - // but different unique IDs. The cache attempts to coalesce these into - // one ID per unique filename. - DWORD GetRealFileID(DWORD id) { - unordered_map<DWORD, DWORD>::iterator iter = file_ids_.find(id); - if (iter == file_ids_.end()) - return id; - return iter->second; - } - - // Find the PE file corresponding to the loaded PDB file, and - // set the code_file_ member. Returns false on failure. - bool FindPEFile(); - - // Returns the function name for a symbol. If possible, the name is - // undecorated. If the symbol's decorated form indicates the size of - // parameters on the stack, this information is returned in stack_param_size. - // Returns true on success. If the symbol doesn't encode parameter size - // information, stack_param_size is set to -1. - static bool GetSymbolFunctionName(IDiaSymbol *function, BSTR *name, - int *stack_param_size); - - // Returns the number of bytes of stack space used for a function's - // parameters. function must have the tag SymTagFunction. In the event of - // a failure, returns 0, which is also a valid number of bytes. - static int GetFunctionStackParamSize(IDiaSymbol *function); - - // The filename of the PE file corresponding to the currently-open - // pdb file. - wstring code_file_; - - // The session for the currently-open pdb file. - CComPtr<IDiaSession> session_; - - // The current output file for this WriteMap invocation. - FILE *output_; - - // There may be many duplicate filenames with different IDs. - // This maps from the DIA "unique ID" to a single ID per unique - // filename. - unordered_map<DWORD, DWORD> file_ids_; - // This maps unique filenames to file IDs. - unordered_map<wstring, DWORD> unique_files_; - - // This is used for calculating post-transform symbol addresses and lengths. - ImageMap image_map_; - - // Disallow copy ctor and operator= - PDBSourceLineWriter(const PDBSourceLineWriter&); - void operator=(const PDBSourceLineWriter&); -}; - -} // namespace google_breakpad - -#endif // COMMON_WINDOWS_PDB_SOURCE_LINE_WRITER_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils-inl.h b/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils-inl.h deleted file mode 100644 index 9b6360726..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils-inl.h +++ /dev/null @@ -1,142 +0,0 @@ -// 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. - -// string_utils-inl.h: Safer string manipulation on Windows, supporting -// pre-MSVC8 environments. - -#ifndef COMMON_WINDOWS_STRING_UTILS_INL_H_ -#define COMMON_WINDOWS_STRING_UTILS_INL_H_ - -#include <stdarg.h> -#include <wchar.h> - -#include <string> - -// The "ll" printf format size specifier corresponding to |long long| was -// intrudced in MSVC8. Earlier versions did not provide this size specifier, -// but "I64" can be used to print 64-bit types. Don't use "I64" where "ll" -// is available, in the event of oddball systems where |long long| is not -// 64 bits wide. -#if _MSC_VER >= 1400 // MSVC 2005/8 -#define WIN_STRING_FORMAT_LL "ll" -#else // MSC_VER >= 1400 -#define WIN_STRING_FORMAT_LL "I64" -#endif // MSC_VER >= 1400 - -// A nonconforming version of swprintf, without the length argument, was -// included with the CRT prior to MSVC8. Although a conforming version was -// also available via an overload, it is not reliably chosen. _snwprintf -// behaves as a standards-confirming swprintf should, so force the use of -// _snwprintf when using older CRTs. -#if _MSC_VER < 1400 // MSVC 2005/8 -#define swprintf _snwprintf -#else -// For MSVC8 and newer, swprintf_s is the recommended method. Conveniently, -// it takes the same argument list as swprintf. -#define swprintf swprintf_s -#endif // MSC_VER < 1400 - -namespace google_breakpad { - -using std::string; -using std::wstring; - -class WindowsStringUtils { - public: - // Roughly equivalent to MSVC8's wcscpy_s, except pre-MSVC8, this does - // not fail if source is longer than destination_size. The destination - // buffer is always 0-terminated. - static void safe_wcscpy(wchar_t *destination, size_t destination_size, - const wchar_t *source); - - // Roughly equivalent to MSVC8's wcsncpy_s, except that _TRUNCATE cannot - // be passed directly, and pre-MSVC8, this will not fail if source or count - // are longer than destination_size. The destination buffer is always - // 0-terminated. - static void safe_wcsncpy(wchar_t *destination, size_t destination_size, - const wchar_t *source, size_t count); - - // Performs multi-byte to wide character conversion on C++ strings, using - // mbstowcs_s (MSVC8) or mbstowcs (pre-MSVC8). Returns false on failure, - // without setting wcs. - static bool safe_mbstowcs(const string &mbs, wstring *wcs); - - // The inverse of safe_mbstowcs. - static bool safe_wcstombs(const wstring &wcs, string *mbs); - - // Returns the base name of a file, e.g. strips off the path. - static wstring GetBaseName(const wstring &filename); - - private: - // Disallow instantiation and other object-based operations. - WindowsStringUtils(); - WindowsStringUtils(const WindowsStringUtils&); - ~WindowsStringUtils(); - void operator=(const WindowsStringUtils&); -}; - -// static -inline void WindowsStringUtils::safe_wcscpy(wchar_t *destination, - size_t destination_size, - const wchar_t *source) { -#if _MSC_VER >= 1400 // MSVC 2005/8 - wcscpy_s(destination, destination_size, source); -#else // _MSC_VER >= 1400 - // Pre-MSVC 2005/8 doesn't have wcscpy_s. Simulate it with wcsncpy. - // wcsncpy doesn't 0-terminate the destination buffer if the source string - // is longer than size. Ensure that the destination is 0-terminated. - wcsncpy(destination, source, destination_size); - if (destination && destination_size) - destination[destination_size - 1] = 0; -#endif // _MSC_VER >= 1400 -} - -// static -inline void WindowsStringUtils::safe_wcsncpy(wchar_t *destination, - size_t destination_size, - const wchar_t *source, - size_t count) { -#if _MSC_VER >= 1400 // MSVC 2005/8 - wcsncpy_s(destination, destination_size, source, count); -#else // _MSC_VER >= 1400 - // Pre-MSVC 2005/8 doesn't have wcsncpy_s. Simulate it with wcsncpy. - // wcsncpy doesn't 0-terminate the destination buffer if the source string - // is longer than size. Ensure that the destination is 0-terminated. - if (destination_size < count) - count = destination_size; - - wcsncpy(destination, source, count); - if (destination && count) - destination[count - 1] = 0; -#endif // _MSC_VER >= 1400 -} - -} // namespace google_breakpad - -#endif // COMMON_WINDOWS_STRING_UTILS_INL_H_ diff --git a/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils.cc b/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils.cc deleted file mode 100644 index 272800035..000000000 --- a/toolkit/crashreporter/google-breakpad/src/common/windows/string_utils.cc +++ /dev/null @@ -1,133 +0,0 @@ -// 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 <cassert> -#include <vector> - -#include "common/windows/string_utils-inl.h" - -namespace google_breakpad { - -// static -wstring WindowsStringUtils::GetBaseName(const wstring &filename) { - wstring base_name(filename); - size_t slash_pos = base_name.find_last_of(L"/\\"); - if (slash_pos != wstring::npos) { - base_name.erase(0, slash_pos + 1); - } - return base_name; -} - -// static -bool WindowsStringUtils::safe_mbstowcs(const string &mbs, wstring *wcs) { - assert(wcs); - - // First, determine the length of the destination buffer. - size_t wcs_length; - -#if _MSC_VER >= 1400 // MSVC 2005/8 - errno_t err; - if ((err = mbstowcs_s(&wcs_length, NULL, 0, mbs.c_str(), _TRUNCATE)) != 0) { - return false; - } - assert(wcs_length > 0); -#else // _MSC_VER >= 1400 - if ((wcs_length = mbstowcs(NULL, mbs.c_str(), mbs.length())) == (size_t)-1) { - return false; - } - - // Leave space for the 0-terminator. - ++wcs_length; -#endif // _MSC_VER >= 1400 - - std::vector<wchar_t> wcs_v(wcs_length); - - // Now, convert. -#if _MSC_VER >= 1400 // MSVC 2005/8 - if ((err = mbstowcs_s(NULL, &wcs_v[0], wcs_length, mbs.c_str(), - _TRUNCATE)) != 0) { - return false; - } -#else // _MSC_VER >= 1400 - if (mbstowcs(&wcs_v[0], mbs.c_str(), mbs.length()) == (size_t)-1) { - return false; - } - - // Ensure presence of 0-terminator. - wcs_v[wcs_length - 1] = '\0'; -#endif // _MSC_VER >= 1400 - - *wcs = &wcs_v[0]; - return true; -} - -// static -bool WindowsStringUtils::safe_wcstombs(const wstring &wcs, string *mbs) { - assert(mbs); - - // First, determine the length of the destination buffer. - size_t mbs_length; - -#if _MSC_VER >= 1400 // MSVC 2005/8 - errno_t err; - if ((err = wcstombs_s(&mbs_length, NULL, 0, wcs.c_str(), _TRUNCATE)) != 0) { - return false; - } - assert(mbs_length > 0); -#else // _MSC_VER >= 1400 - if ((mbs_length = wcstombs(NULL, wcs.c_str(), wcs.length())) == (size_t)-1) { - return false; - } - - // Leave space for the 0-terminator. - ++mbs_length; -#endif // _MSC_VER >= 1400 - - std::vector<char> mbs_v(mbs_length); - - // Now, convert. -#if _MSC_VER >= 1400 // MSVC 2005/8 - if ((err = wcstombs_s(NULL, &mbs_v[0], mbs_length, wcs.c_str(), - _TRUNCATE)) != 0) { - return false; - } -#else // _MSC_VER >= 1400 - if (wcstombs(&mbs_v[0], wcs.c_str(), wcs.length()) == (size_t)-1) { - return false; - } - - // Ensure presence of 0-terminator. - mbs_v[mbs_length - 1] = '\0'; -#endif // _MSC_VER >= 1400 - - *mbs = &mbs_v[0]; - return true; -} - -} // namespace google_breakpad |