mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-11 08:34:34 +02:00
Update breakpad to make it work with MinGW
This commit is contained in:
224
thirdparty/breakpad/common/android/breakpad_getcontext.S
vendored
Normal file
224
thirdparty/breakpad/common/android/breakpad_getcontext.S
vendored
Normal file
@@ -0,0 +1,224 @@
|
||||
// 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) */
|
||||
|
||||
#ifdef __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 explicitely. */
|
||||
/* - 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 accross 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(__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__)
|
||||
|
||||
#if _MIPS_SIM != _ABIO32
|
||||
#error "Unsupported mips ISA. Only mips o32 is supported."
|
||||
#endif
|
||||
|
||||
// This implementation is inspired by implementation of getcontext in glibc.
|
||||
#include <asm/asm.h>
|
||||
#include <asm/regdef.h>
|
||||
#include <asm/fpregdef.h>
|
||||
#include <asm/unistd.h> // for __NR_rt_sigprocmask
|
||||
|
||||
#define _NSIG8 128 / 8
|
||||
#define SIG_BLOCK 1
|
||||
|
||||
|
||||
.text
|
||||
LOCALS_NUM = 2 // save gp and ra on stack
|
||||
FRAME_SIZE = ((LOCALS_NUM * SZREG) + ALSZ) & ALMASK
|
||||
RA_FRAME_OFFSET = FRAME_SIZE - (1 * SZREG)
|
||||
GP_FRAME_OFFSET = FRAME_SIZE - (2 * SZREG)
|
||||
MCONTEXT_REG_SIZE = 8
|
||||
|
||||
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
|
||||
sw ra, RA_FRAME_OFFSET(sp)
|
||||
sw gp, GP_FRAME_OFFSET(sp)
|
||||
|
||||
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
|
||||
|
||||
lw ra, RA_FRAME_OFFSET(sp)
|
||||
lw gp, GP_FRAME_OFFSET(sp)
|
||||
addiu sp, FRAME_SIZE
|
||||
jr ra
|
||||
|
||||
END (breakpad_getcontext)
|
||||
|
||||
|
||||
#else
|
||||
#error "This file has not been ported for your CPU!"
|
||||
#endif
|
94
thirdparty/breakpad/common/android/breakpad_getcontext_unittest.cc
vendored
Normal file
94
thirdparty/breakpad/common/android/breakpad_getcontext_unittest.cc
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
// 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 <sys/ucontext.h>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/android/ucontext_constants.h"
|
||||
|
||||
TEST(AndroidUContext, GRegsOffset) {
|
||||
#ifdef __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(__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));
|
||||
#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));
|
||||
}
|
163
thirdparty/breakpad/common/android/include/elf.h
vendored
Normal file
163
thirdparty/breakpad/common/android/include/elf.h
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
// 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.
|
||||
// All Android platforms are 32-bit for now.
|
||||
#ifndef __WORDSIZE
|
||||
#define __WORDSIZE 32
|
||||
#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
|
67
thirdparty/breakpad/common/android/include/link.h
vendored
Normal file
67
thirdparty/breakpad/common/android/include/link.h
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
// 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 <link.h>. Provide custom version here */
|
||||
#include <elf.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#define ElfW(type) _ElfW (Elf, ELFSIZE, type)
|
||||
#define _ElfW(e,w,t) _ElfW_1 (e, w, _##t)
|
||||
#define _ElfW_1(e,w,t) e##w##t
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_ANDROID_INCLUDE_LINK_H */
|
51
thirdparty/breakpad/common/android/include/sgidefs.h
vendored
Normal file
51
thirdparty/breakpad/common/android/include/sgidefs.h
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
// 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__
|
||||
|
||||
#define _MIPS_SIM_ABI32 1
|
||||
#define _MIPS_SIM_NABI32 2
|
||||
#define _MIPS_SIM_ABI64 3
|
||||
|
||||
// The following should always be defined by the compiler,
|
||||
// Verified for Android with GCC 4.6 and Clang 3.1.
|
||||
#ifndef _MIPS_SIM
|
||||
#error "Toolchain should define _MIPS_SIM"
|
||||
#endif
|
||||
|
||||
#ifndef _MIPS_SZPTR
|
||||
#error "Toolchain should define _MIPS_PTR"
|
||||
#endif
|
||||
|
||||
#endif // __mips__
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_ANDROID_INCLUDE_SGIDEFS_H
|
100
thirdparty/breakpad/common/android/include/stab.h
vendored
Normal file
100
thirdparty/breakpad/common/android/include/stab.h
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
// 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
|
113
thirdparty/breakpad/common/android/include/sys/procfs.h
vendored
Normal file
113
thirdparty/breakpad/common/android/include/sys/procfs.h
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// 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 <sys/cdefs.h>
|
||||
#include <sys/user.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#ifdef __x86_64__
|
||||
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))
|
||||
#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;
|
||||
#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
|
35
thirdparty/breakpad/common/android/include/sys/signal.h
vendored
Normal file
35
thirdparty/breakpad/common/android/include/sys/signal.h
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
// 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
|
39
thirdparty/breakpad/common/android/include/sys/stat.h
vendored
Normal file
39
thirdparty/breakpad/common/android/include/sys/stat.h
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// 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_STAT_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_STAT_H
|
||||
|
||||
#include_next <sys/stat.h>
|
||||
|
||||
#ifndef S_IRWXU
|
||||
#define S_IRWXU 00700
|
||||
#endif
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_STAT_H
|
174
thirdparty/breakpad/common/android/include/sys/ucontext.h
vendored
Normal file
174
thirdparty/breakpad/common/android/include/sys/ucontext.h
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
// 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_UCONTEXT_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_UCONTEXT_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#ifndef __BIONIC_HAVE_UCONTEXT_T
|
||||
|
||||
// Ensure that 'stack_t' is defined.
|
||||
#include <asm/signal.h>
|
||||
|
||||
// This version of the Android C library headers do not provide ucontext_t.
|
||||
// Provide custom definitions for Google Breakpad.
|
||||
#if defined(__arm__)
|
||||
|
||||
// Ensure that 'struct sigcontext' is defined.
|
||||
#include <asm/sigcontext.h>
|
||||
typedef struct sigcontext mcontext_t;
|
||||
|
||||
// The ARM kernel uses a 64-bit signal mask.
|
||||
typedef uint32_t kernel_sigmask_t[2];
|
||||
|
||||
typedef struct ucontext {
|
||||
uint32_t uc_flags;
|
||||
struct ucontext* uc_link;
|
||||
stack_t uc_stack;
|
||||
mcontext_t uc_mcontext;
|
||||
kernel_sigmask_t uc_sigmask;
|
||||
// Other fields are not used by Google Breakpad. Don't define them.
|
||||
} ucontext_t;
|
||||
|
||||
#elif defined(__i386__)
|
||||
|
||||
/* 80-bit floating-point register */
|
||||
struct _libc_fpreg {
|
||||
unsigned short significand[4];
|
||||
unsigned short exponent;
|
||||
};
|
||||
|
||||
/* Simple floating-point state, see FNSTENV instruction */
|
||||
struct _libc_fpstate {
|
||||
unsigned long cw;
|
||||
unsigned long sw;
|
||||
unsigned long tag;
|
||||
unsigned long ipoff;
|
||||
unsigned long cssel;
|
||||
unsigned long dataoff;
|
||||
unsigned long datasel;
|
||||
struct _libc_fpreg _st[8];
|
||||
unsigned long status;
|
||||
};
|
||||
|
||||
typedef uint32_t greg_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t gregs[19];
|
||||
struct _libc_fpstate* fpregs;
|
||||
uint32_t oldmask;
|
||||
uint32_t cr2;
|
||||
} mcontext_t;
|
||||
|
||||
enum {
|
||||
REG_GS = 0,
|
||||
REG_FS,
|
||||
REG_ES,
|
||||
REG_DS,
|
||||
REG_EDI,
|
||||
REG_ESI,
|
||||
REG_EBP,
|
||||
REG_ESP,
|
||||
REG_EBX,
|
||||
REG_EDX,
|
||||
REG_ECX,
|
||||
REG_EAX,
|
||||
REG_TRAPNO,
|
||||
REG_ERR,
|
||||
REG_EIP,
|
||||
REG_CS,
|
||||
REG_EFL,
|
||||
REG_UESP,
|
||||
REG_SS,
|
||||
};
|
||||
|
||||
// The i386 kernel uses a 64-bit signal mask.
|
||||
typedef uint32_t kernel_sigmask_t[2];
|
||||
|
||||
typedef struct ucontext {
|
||||
uint32_t uc_flags;
|
||||
struct ucontext* uc_link;
|
||||
stack_t uc_stack;
|
||||
mcontext_t uc_mcontext;
|
||||
kernel_sigmask_t uc_sigmask;
|
||||
struct _libc_fpstate __fpregs_mem;
|
||||
} ucontext_t;
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
typedef struct {
|
||||
uint32_t regmask;
|
||||
uint32_t status;
|
||||
uint64_t pc;
|
||||
uint64_t gregs[32];
|
||||
uint64_t fpregs[32];
|
||||
uint32_t acx;
|
||||
uint32_t fpc_csr;
|
||||
uint32_t fpc_eir;
|
||||
uint32_t used_math;
|
||||
uint32_t dsp;
|
||||
uint64_t mdhi;
|
||||
uint64_t mdlo;
|
||||
uint32_t hi1;
|
||||
uint32_t lo1;
|
||||
uint32_t hi2;
|
||||
uint32_t lo2;
|
||||
uint32_t hi3;
|
||||
uint32_t lo3;
|
||||
} mcontext_t;
|
||||
|
||||
// The MIPS kernel uses a 128-bit signal mask.
|
||||
typedef uint32_t kernel_sigmask_t[4];
|
||||
|
||||
typedef struct ucontext {
|
||||
uint32_t uc_flags;
|
||||
struct ucontext* uc_link;
|
||||
stack_t uc_stack;
|
||||
mcontext_t uc_mcontext;
|
||||
kernel_sigmask_t uc_sigmask;
|
||||
// Other fields are not used by Google Breakpad. Don't define them.
|
||||
} ucontext_t;
|
||||
|
||||
#else
|
||||
# error "Unsupported Android CPU ABI!"
|
||||
#endif
|
||||
|
||||
#endif // __BIONIC_HAVE_UCONTEXT_T
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_UCONTEXT_H
|
149
thirdparty/breakpad/common/android/include/sys/user.h
vendored
Normal file
149
thirdparty/breakpad/common/android/include/sys/user.h
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// 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
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// These types are used with ptrace(), more specifically with
|
||||
// PTRACE_GETREGS, PTRACE_GETFPREGS and PTRACE_GETVFPREGS respectively.
|
||||
//
|
||||
// They are also defined, sometimes with different names, in <asm/user.h>
|
||||
//
|
||||
|
||||
#if defined(__arm__)
|
||||
|
||||
#define _ARM_USER_H 1 // Prevent <asm/user.h> conflicts
|
||||
|
||||
// Note: on ARM, GLibc uses user_regs instead of user_regs_struct.
|
||||
struct user_regs {
|
||||
// Note: Entries 0-15 match r0..r15
|
||||
// Entry 16 is used to store the CPSR register.
|
||||
// Entry 17 is used to store the "orig_r0" value.
|
||||
unsigned long int uregs[18];
|
||||
};
|
||||
|
||||
// Same here: user_fpregs instead of user_fpregs_struct.
|
||||
struct user_fpregs {
|
||||
struct fp_reg {
|
||||
unsigned int sign1:1;
|
||||
unsigned int unused:15;
|
||||
unsigned int sign2:1;
|
||||
unsigned int exponent:14;
|
||||
unsigned int j:1;
|
||||
unsigned int mantissa1:31;
|
||||
unsigned int mantissa0:32;
|
||||
} fpregs[8];
|
||||
unsigned int fpsr:32;
|
||||
unsigned int fpcr:32;
|
||||
unsigned char ftype[8];
|
||||
unsigned int init_flag;
|
||||
};
|
||||
|
||||
// GLibc doesn't define this one in <sys/user.h> though.
|
||||
struct user_vfpregs {
|
||||
unsigned long long fpregs[32];
|
||||
unsigned long fpscr;
|
||||
};
|
||||
|
||||
#elif defined(__i386__)
|
||||
|
||||
#define _I386_USER_H 1 // Prevent <asm/user.h> conflicts
|
||||
|
||||
// GLibc-compatible definitions
|
||||
struct user_regs_struct {
|
||||
long ebx, ecx, edx, esi, edi, ebp, eax;
|
||||
long xds, xes, xfs, xgs, orig_eax;
|
||||
long eip, xcs, eflags, esp, xss;
|
||||
};
|
||||
|
||||
struct user_fpregs_struct {
|
||||
long cwd, swd, twd, fip, fcs, foo, fos;
|
||||
long st_space[20];
|
||||
};
|
||||
|
||||
struct user_fpxregs_struct {
|
||||
unsigned short cwd, swd, twd, fop;
|
||||
long fip, fcs, foo, fos, mxcsr, reserved;
|
||||
long st_space[32];
|
||||
long xmm_space[32];
|
||||
long padding[56];
|
||||
};
|
||||
|
||||
struct user {
|
||||
struct user_regs_struct regs;
|
||||
int u_fpvalid;
|
||||
struct user_fpregs_struct i387;
|
||||
unsigned long u_tsize;
|
||||
unsigned long u_dsize;
|
||||
unsigned long u_ssize;
|
||||
unsigned long start_code;
|
||||
unsigned long start_stack;
|
||||
long signal;
|
||||
int reserved;
|
||||
struct user_regs_struct* u_ar0;
|
||||
struct user_fpregs_struct* u_fpstate;
|
||||
unsigned long magic;
|
||||
char u_comm [32];
|
||||
int u_debugreg [8];
|
||||
};
|
||||
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
#define _ASM_USER_H 1 // Prevent <asm/user.h> conflicts
|
||||
|
||||
struct user_regs_struct {
|
||||
unsigned long long regs[32];
|
||||
unsigned long long lo;
|
||||
unsigned long long hi;
|
||||
unsigned long long epc;
|
||||
unsigned long long badvaddr;
|
||||
unsigned long long status;
|
||||
unsigned long long cause;
|
||||
};
|
||||
|
||||
struct user_fpregs_struct {
|
||||
unsigned long long regs[32];
|
||||
unsigned int fpcsr;
|
||||
unsigned int fir;
|
||||
};
|
||||
|
||||
#else
|
||||
# error "Unsupported Android CPU ABI"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H
|
56
thirdparty/breakpad/common/android/include/ucontext.h
vendored
Normal file
56
thirdparty/breakpad/common/android/include/ucontext.h
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2012, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_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
|
72
thirdparty/breakpad/common/android/testing/include/wchar.h
vendored
Normal file
72
thirdparty/breakpad/common/android/testing/include/wchar.h
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
// 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>
|
||||
|
||||
// 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 // GOOGLEBREAKPAD_COMMON_ANDROID_INCLUDE_WCHAR_H
|
110
thirdparty/breakpad/common/android/testing/mkdtemp.h
vendored
Normal file
110
thirdparty/breakpad/common/android/testing/mkdtemp.h
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
// 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
|
99
thirdparty/breakpad/common/android/testing/pthread_fixes.h
vendored
Normal file
99
thirdparty/breakpad/common/android/testing/pthread_fixes.h
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
// 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
|
88
thirdparty/breakpad/common/android/ucontext_constants.h
vendored
Normal file
88
thirdparty/breakpad/common/android/ucontext_constants.h
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
// 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(__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__)
|
||||
|
||||
#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
|
||||
#error "This header has not been ported for your CPU"
|
||||
#endif
|
||||
|
||||
#endif // GOOGLEBREAKPAD_COMMON_ANDROID_UCONTEXT_CONSTANTS_H
|
19
thirdparty/breakpad/common/basictypes.h
vendored
19
thirdparty/breakpad/common/basictypes.h
vendored
@@ -32,8 +32,27 @@
|
||||
|
||||
// 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_
|
||||
|
6
thirdparty/breakpad/common/byte_cursor.h
vendored
6
thirdparty/breakpad/common/byte_cursor.h
vendored
@@ -45,6 +45,8 @@
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A buffer holding a series of bytes.
|
||||
@@ -164,7 +166,7 @@ class ByteCursor {
|
||||
// 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(std::string *str) {
|
||||
ByteCursor &CString(string *str) {
|
||||
const uint8_t *end
|
||||
= static_cast<const uint8_t *>(memchr(here_, '\0', Available()));
|
||||
if (end) {
|
||||
@@ -191,7 +193,7 @@ class ByteCursor {
|
||||
//
|
||||
// - Otherwise, set *STR to a copy of those LIMIT bytes, and advance the
|
||||
// cursor by LIMIT bytes.
|
||||
ByteCursor &CString(std::string *str, size_t limit) {
|
||||
ByteCursor &CString(string *str, size_t limit) {
|
||||
if (CheckAvailable(limit)) {
|
||||
const uint8_t *end
|
||||
= static_cast<const uint8_t *>(memchr(here_, '\0', limit));
|
||||
|
@@ -36,12 +36,12 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "common/byte_cursor.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;
|
||||
using std::string;
|
||||
|
||||
TEST(Buffer, SizeOfNothing) {
|
||||
uint8_t data[1];
|
||||
|
5
thirdparty/breakpad/common/convert_UTF.c
vendored
5
thirdparty/breakpad/common/convert_UTF.c
vendored
@@ -53,8 +53,13 @@ static const UTF32 halfMask = 0x3FFUL;
|
||||
#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
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
|
5
thirdparty/breakpad/common/convert_UTF.h
vendored
5
thirdparty/breakpad/common/convert_UTF.h
vendored
@@ -20,6 +20,9 @@
|
||||
* remains attached.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_CONVERT_UTF_H_
|
||||
#define COMMON_CONVERT_UTF_H_
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Header file.
|
||||
@@ -141,3 +144,5 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
#endif
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#endif // COMMON_CONVERT_UTF_H_
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#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;
|
||||
@@ -47,7 +48,6 @@ 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 std::string;
|
||||
using testing::Test;
|
||||
|
||||
struct ReaderFixture {
|
||||
|
@@ -41,10 +41,10 @@ namespace google_breakpad {
|
||||
|
||||
using dwarf2reader::DwarfPointerEncoding;
|
||||
|
||||
CFISection &CFISection::CIEHeader(u_int64_t code_alignment_factor,
|
||||
CFISection &CFISection::CIEHeader(uint64_t code_alignment_factor,
|
||||
int data_alignment_factor,
|
||||
unsigned return_address_register,
|
||||
u_int8_t version,
|
||||
uint8_t version,
|
||||
const string &augmentation,
|
||||
bool dwarf64) {
|
||||
assert(!entry_length_);
|
||||
@@ -73,8 +73,8 @@ CFISection &CFISection::CIEHeader(u_int64_t code_alignment_factor,
|
||||
}
|
||||
|
||||
CFISection &CFISection::FDEHeader(Label cie_pointer,
|
||||
u_int64_t initial_location,
|
||||
u_int64_t address_range,
|
||||
uint64_t initial_location,
|
||||
uint64_t address_range,
|
||||
bool dwarf64) {
|
||||
assert(!entry_length_);
|
||||
entry_length_ = new PendingLength();
|
||||
@@ -117,7 +117,7 @@ CFISection &CFISection::FinishEntry() {
|
||||
return *this;
|
||||
}
|
||||
|
||||
CFISection &CFISection::EncodedPointer(u_int64_t address,
|
||||
CFISection &CFISection::EncodedPointer(uint64_t address,
|
||||
DwarfPointerEncoding encoding,
|
||||
const EncodedPointerBases &bases) {
|
||||
// Omitted data is extremely easy to emit.
|
||||
@@ -131,7 +131,7 @@ CFISection &CFISection::EncodedPointer(u_int64_t address,
|
||||
|
||||
// Find the base address to which this pointer is relative. The upper
|
||||
// nybble of the encoding specifies this.
|
||||
u_int64_t base;
|
||||
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;
|
||||
@@ -189,10 +189,10 @@ CFISection &CFISection::EncodedPointer(u_int64_t address,
|
||||
return *this;
|
||||
};
|
||||
|
||||
const u_int32_t CFISection::kDwarf64InitialLengthMarker;
|
||||
const u_int32_t CFISection::kDwarf32CIEIdentifier;
|
||||
const u_int64_t CFISection::kDwarf64CIEIdentifier;
|
||||
const u_int32_t CFISection::kEHFrame32CIEIdentifier;
|
||||
const u_int64_t CFISection::kEHFrame64CIEIdentifier;
|
||||
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
|
||||
|
46
thirdparty/breakpad/common/dwarf/cfi_assembler.h
vendored
46
thirdparty/breakpad/common/dwarf/cfi_assembler.h
vendored
@@ -41,6 +41,7 @@
|
||||
|
||||
#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 {
|
||||
@@ -49,7 +50,6 @@ using dwarf2reader::DwarfPointerEncoding;
|
||||
using google_breakpad::test_assembler::Endianness;
|
||||
using google_breakpad::test_assembler::Label;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
using std::string;
|
||||
|
||||
class CFISection: public Section {
|
||||
public:
|
||||
@@ -80,14 +80,14 @@ class CFISection: public Section {
|
||||
// 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.
|
||||
u_int64_t cfi;
|
||||
uint64_t cfi;
|
||||
|
||||
// The starting address of this file's .text section, for DW_EH_PE_textrel.
|
||||
u_int64_t text;
|
||||
uint64_t text;
|
||||
|
||||
// The starting address of this file's .got or .eh_frame_hdr section,
|
||||
// for DW_EH_PE_datarel.
|
||||
u_int64_t data;
|
||||
uint64_t data;
|
||||
};
|
||||
|
||||
// Create a CFISection whose endianness is ENDIANNESS, and where
|
||||
@@ -133,10 +133,10 @@ class CFISection: public Section {
|
||||
// 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(u_int64_t code_alignment_factor,
|
||||
CFISection &CIEHeader(uint64_t code_alignment_factor,
|
||||
int data_alignment_factor,
|
||||
unsigned return_address_register,
|
||||
u_int8_t version = 3,
|
||||
uint8_t version = 3,
|
||||
const string &augmentation = "",
|
||||
bool dwarf64 = false);
|
||||
|
||||
@@ -151,8 +151,8 @@ class CFISection: public Section {
|
||||
// value.) Nor does it support .debug_frame sections longer than
|
||||
// 0xffffff00 bytes.
|
||||
CFISection &FDEHeader(Label cie_pointer,
|
||||
u_int64_t initial_location,
|
||||
u_int64_t address_range,
|
||||
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
|
||||
@@ -171,7 +171,7 @@ class CFISection: public Section {
|
||||
|
||||
// Append ADDRESS to this section, in the appropriate size and
|
||||
// endianness. Return a reference to this section.
|
||||
CFISection &Address(u_int64_t address) {
|
||||
CFISection &Address(uint64_t address) {
|
||||
Section::Append(endianness(), address_size_, address);
|
||||
return *this;
|
||||
}
|
||||
@@ -189,26 +189,26 @@ class CFISection: public 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(u_int64_t address) {
|
||||
CFISection &EncodedPointer(uint64_t address) {
|
||||
return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_);
|
||||
}
|
||||
CFISection &EncodedPointer(u_int64_t address, DwarfPointerEncoding encoding) {
|
||||
CFISection &EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) {
|
||||
return EncodedPointer(address, encoding, encoded_pointer_bases_);
|
||||
}
|
||||
CFISection &EncodedPointer(u_int64_t address, DwarfPointerEncoding encoding,
|
||||
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(u_int8_t v) { Section::D8(v); return *this; }
|
||||
CFISection &D16(u_int16_t v) { Section::D16(v); 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(u_int32_t v) { Section::D32(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(u_int64_t v) { Section::D64(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(u_int64_t v) { Section::ULEB128(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
|
||||
@@ -224,13 +224,13 @@ class CFISection: public Section {
|
||||
// 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 u_int32_t kDwarf64InitialLengthMarker = 0xffffffffU;
|
||||
static const uint32_t kDwarf64InitialLengthMarker = 0xffffffffU;
|
||||
|
||||
// The CIE identifier for 32- and 64-bit DWARF CFI and .eh_frame data.
|
||||
static const u_int32_t kDwarf32CIEIdentifier = ~(u_int32_t)0;
|
||||
static const u_int64_t kDwarf64CIEIdentifier = ~(u_int64_t)0;
|
||||
static const u_int32_t kEHFrame32CIEIdentifier = 0;
|
||||
static const u_int64_t kEHFrame64CIEIdentifier = 0;
|
||||
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_;
|
||||
@@ -261,7 +261,7 @@ class CFISection: public Section {
|
||||
|
||||
// If in_fde_ is true, this is its starting address. We use this for
|
||||
// emitting DW_EH_PE_funcrel pointers.
|
||||
u_int64_t fde_start_address_;
|
||||
uint64_t fde_start_address_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
@@ -31,10 +31,13 @@
|
||||
// dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class.
|
||||
// See dwarf2diehandler.h for details.
|
||||
|
||||
#include "common/dwarf/dwarf2diehandler.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/dwarf/dwarf2diehandler.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace dwarf2reader {
|
||||
|
||||
DIEDispatcher::~DIEDispatcher() {
|
||||
@@ -54,8 +57,7 @@ bool DIEDispatcher::StartCompilationUnit(uint64 offset, uint8 address_size,
|
||||
dwarf_version);
|
||||
}
|
||||
|
||||
bool DIEDispatcher::StartDIE(uint64 offset, enum DwarfTag tag,
|
||||
const AttributeList& attrs) {
|
||||
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();
|
||||
|
||||
@@ -79,7 +81,7 @@ bool DIEDispatcher::StartDIE(uint64 offset, enum DwarfTag tag,
|
||||
if (parent) {
|
||||
if (parent->handler_)
|
||||
// Ask the parent to find a handler.
|
||||
handler = parent->handler_->FindChildHandler(offset, tag, attrs);
|
||||
handler = parent->handler_->FindChildHandler(offset, tag);
|
||||
else
|
||||
// No parent handler means we're not interested in any of our
|
||||
// children.
|
||||
@@ -89,7 +91,7 @@ bool DIEDispatcher::StartDIE(uint64 offset, enum DwarfTag tag,
|
||||
// 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, attrs))
|
||||
if (root_handler_->StartRootDIE(offset, tag))
|
||||
handler = root_handler_;
|
||||
else
|
||||
handler = NULL;
|
||||
@@ -176,7 +178,7 @@ void DIEDispatcher::ProcessAttributeBuffer(uint64 offset,
|
||||
void DIEDispatcher::ProcessAttributeString(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const std::string& data) {
|
||||
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_);
|
||||
|
@@ -157,10 +157,12 @@
|
||||
#define COMMON_DWARF_DWARF2DIEHANDLER_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 {
|
||||
|
||||
@@ -208,7 +210,7 @@ class DIEHandler {
|
||||
uint64 len) { }
|
||||
virtual void ProcessAttributeString(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const std::string& data) { }
|
||||
const string& data) { }
|
||||
virtual void ProcessAttributeSignature(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64 signture) { }
|
||||
@@ -237,12 +239,10 @@ class DIEHandler {
|
||||
// that child DIE (and all its descendants).
|
||||
//
|
||||
// OFFSET is the offset of the child; TAG indicates what kind of DIE
|
||||
// it is; and ATTRS is the list of attributes the DIE will have, and
|
||||
// their forms (their values are not provided).
|
||||
// it is.
|
||||
//
|
||||
// The default definition skips all children.
|
||||
virtual DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag,
|
||||
const AttributeList &attrs) {
|
||||
virtual DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -278,8 +278,7 @@ class RootDIEHandler: public DIEHandler {
|
||||
// unit.
|
||||
//
|
||||
// The default definition elects to visit the root DIE.
|
||||
virtual bool StartRootDIE(uint64 offset, enum DwarfTag tag,
|
||||
const AttributeList& attrs) { return true; }
|
||||
virtual bool StartRootDIE(uint64 offset, enum DwarfTag tag) { return true; }
|
||||
};
|
||||
|
||||
class DIEDispatcher: public Dwarf2Handler {
|
||||
@@ -294,8 +293,7 @@ class DIEDispatcher: public Dwarf2Handler {
|
||||
bool StartCompilationUnit(uint64 offset, uint8 address_size,
|
||||
uint8 offset_size, uint64 cu_length,
|
||||
uint8 dwarf_version);
|
||||
bool StartDIE(uint64 offset, enum DwarfTag tag,
|
||||
const AttributeList &attrs);
|
||||
bool StartDIE(uint64 offset, enum DwarfTag tag);
|
||||
void ProcessAttributeUnsigned(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
@@ -316,7 +314,7 @@ class DIEDispatcher: public Dwarf2Handler {
|
||||
void ProcessAttributeString(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const std::string &data);
|
||||
const string &data);
|
||||
void ProcessAttributeSignature(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
|
@@ -38,9 +38,9 @@
|
||||
#include "breakpad_googletest_includes.h"
|
||||
|
||||
#include "common/dwarf/dwarf2diehandler.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using std::make_pair;
|
||||
using std::string;
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::ContainerEq;
|
||||
@@ -51,7 +51,6 @@ using ::testing::Return;
|
||||
using ::testing::Sequence;
|
||||
using ::testing::StrEq;
|
||||
|
||||
using dwarf2reader::AttributeList;
|
||||
using dwarf2reader::DIEDispatcher;
|
||||
using dwarf2reader::DIEHandler;
|
||||
using dwarf2reader::DwarfAttribute;
|
||||
@@ -74,8 +73,7 @@ class MockDIEHandler: public DIEHandler {
|
||||
MOCK_METHOD3(ProcessAttributeSignature,
|
||||
void(DwarfAttribute, DwarfForm, uint64));
|
||||
MOCK_METHOD0(EndAttributes, bool());
|
||||
MOCK_METHOD3(FindChildHandler, DIEHandler *(uint64, DwarfTag,
|
||||
const AttributeList &));
|
||||
MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag));
|
||||
MOCK_METHOD0(Finish, void());
|
||||
};
|
||||
|
||||
@@ -94,11 +92,10 @@ class MockRootDIEHandler: public RootDIEHandler {
|
||||
MOCK_METHOD3(ProcessAttributeSignature,
|
||||
void(DwarfAttribute, DwarfForm, uint64));
|
||||
MOCK_METHOD0(EndAttributes, bool());
|
||||
MOCK_METHOD3(FindChildHandler, DIEHandler *(uint64, DwarfTag,
|
||||
const AttributeList &));
|
||||
MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64, DwarfTag));
|
||||
MOCK_METHOD0(Finish, void());
|
||||
MOCK_METHOD5(StartCompilationUnit, bool(uint64, uint8, uint8, uint64, uint8));
|
||||
MOCK_METHOD3(StartRootDIE, bool(uint64, DwarfTag, const AttributeList &));
|
||||
MOCK_METHOD2(StartRootDIE, bool(uint64, DwarfTag));
|
||||
};
|
||||
|
||||
// If the handler elects to skip the compilation unit, the dispatcher
|
||||
@@ -129,18 +126,13 @@ TEST(Dwarf2DIEHandler, SkipRootDIE) {
|
||||
MockRootDIEHandler mock_root_handler;
|
||||
DIEDispatcher die_dispatcher(&mock_root_handler);
|
||||
|
||||
AttributeList mock_attribute_list;
|
||||
mock_attribute_list.push_back(make_pair(dwarf2reader::DW_AT_name,
|
||||
dwarf2reader::DW_FORM_string));
|
||||
|
||||
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,
|
||||
ContainerEq(mock_attribute_list)))
|
||||
StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return(false));
|
||||
|
||||
@@ -148,8 +140,7 @@ TEST(Dwarf2DIEHandler, SkipRootDIE) {
|
||||
0xf4, 0x02,
|
||||
0xb00febffa76e2b2bLL, 0x5c));
|
||||
EXPECT_FALSE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL,
|
||||
(DwarfTag) 0xb4f98da6,
|
||||
mock_attribute_list));
|
||||
(DwarfTag) 0xb4f98da6));
|
||||
die_dispatcher.EndDIE(0x7d08242b4b510cf2LL);
|
||||
}
|
||||
|
||||
@@ -160,8 +151,6 @@ TEST(Dwarf2DIEHandler, SkipRootDIEChildren) {
|
||||
MockRootDIEHandler mock_root_handler;
|
||||
DIEDispatcher die_dispatcher(&mock_root_handler);
|
||||
|
||||
AttributeList mock_attribute_list;
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
@@ -170,8 +159,7 @@ TEST(Dwarf2DIEHandler, SkipRootDIEChildren) {
|
||||
0x09f8bf0767f91675LL, 0xdb))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6,
|
||||
ContainerEq(mock_attribute_list)))
|
||||
StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6))
|
||||
.WillOnce(Return(true));
|
||||
// Please don't tell me about my children.
|
||||
EXPECT_CALL(mock_root_handler, EndAttributes())
|
||||
@@ -184,11 +172,9 @@ TEST(Dwarf2DIEHandler, SkipRootDIEChildren) {
|
||||
0x26, 0xa0,
|
||||
0x09f8bf0767f91675LL, 0xdb));
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL,
|
||||
(DwarfTag) 0xb4f98da6,
|
||||
mock_attribute_list));
|
||||
(DwarfTag) 0xb4f98da6));
|
||||
EXPECT_FALSE(die_dispatcher.StartDIE(0x435150ceedccda18LL,
|
||||
(DwarfTag) 0xc3a17bba,
|
||||
mock_attribute_list));
|
||||
(DwarfTag) 0xc3a17bba));
|
||||
die_dispatcher.EndDIE(0x435150ceedccda18LL);
|
||||
die_dispatcher.EndDIE(0x7d08242b4b510cf2LL);
|
||||
}
|
||||
@@ -199,9 +185,6 @@ TEST(Dwarf2DIEHandler, PassAttributeValues) {
|
||||
MockRootDIEHandler mock_root_handler;
|
||||
DIEDispatcher die_dispatcher(&mock_root_handler);
|
||||
|
||||
AttributeList mock_attribute_list;
|
||||
mock_attribute_list.push_back(make_pair(dwarf2reader::DW_AT_name,
|
||||
dwarf2reader::DW_FORM_string));
|
||||
const char buffer[10] = { 0x24, 0x24, 0x35, 0x9a, 0xca,
|
||||
0xcf, 0xa8, 0x84, 0xa7, 0x18 };
|
||||
string str = "\xc8\x26\x2e\x0d\xa4\x9c\x37\xd6\xfb\x1d";
|
||||
@@ -218,8 +201,7 @@ TEST(Dwarf2DIEHandler, PassAttributeValues) {
|
||||
|
||||
// We'll like the root DIE.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartRootDIE(0xe2222da01e29f2a9LL, (DwarfTag) 0x9829445c,
|
||||
ContainerEq(mock_attribute_list)))
|
||||
StartRootDIE(0xe2222da01e29f2a9LL, (DwarfTag) 0x9829445c))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// Expect some attribute values.
|
||||
@@ -255,7 +237,7 @@ TEST(Dwarf2DIEHandler, PassAttributeValues) {
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(mock_root_handler, EndAttributes())
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_root_handler, FindChildHandler(_, _, _))
|
||||
EXPECT_CALL(mock_root_handler, FindChildHandler(_, _))
|
||||
.Times(0);
|
||||
EXPECT_CALL(mock_root_handler, Finish())
|
||||
.WillOnce(Return());
|
||||
@@ -270,8 +252,7 @@ TEST(Dwarf2DIEHandler, PassAttributeValues) {
|
||||
0x66));
|
||||
// Report the root DIE.
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0xe2222da01e29f2a9LL,
|
||||
(DwarfTag) 0x9829445c,
|
||||
mock_attribute_list));
|
||||
(DwarfTag) 0x9829445c));
|
||||
|
||||
// Report some attribute values.
|
||||
die_dispatcher.ProcessAttributeUnsigned(0xe2222da01e29f2a9LL,
|
||||
@@ -309,25 +290,6 @@ TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
|
||||
MockDIEHandler *mock_child3_handler = new(MockDIEHandler);
|
||||
DIEDispatcher die_dispatcher(&mock_root_handler);
|
||||
|
||||
AttributeList root_attribute_list;
|
||||
root_attribute_list.push_back(make_pair((DwarfAttribute) 0xb01185df,
|
||||
(DwarfForm) 0xbc97cee8));
|
||||
AttributeList child1_attribute_list;
|
||||
child1_attribute_list.push_back(make_pair((DwarfAttribute) 0x41014e43,
|
||||
(DwarfForm) 0x63155f4c));
|
||||
AttributeList grandchild1_attribute_list;
|
||||
grandchild1_attribute_list.push_back(make_pair((DwarfAttribute) 0xf72f823c,
|
||||
(DwarfForm) 0x0ff6a201));
|
||||
AttributeList greatgrandchild1_attribute_list;
|
||||
greatgrandchild1_attribute_list
|
||||
.push_back(make_pair((DwarfAttribute) 0xbe66e5f0, (DwarfForm) 0xb4b24ff7));
|
||||
AttributeList child2_attribute_list;
|
||||
child1_attribute_list.push_back(make_pair((DwarfAttribute) 0xf22df14c,
|
||||
(DwarfForm) 0x20676e7d));
|
||||
AttributeList child3_attribute_list;
|
||||
child3_attribute_list.push_back(make_pair((DwarfAttribute) 0xe8bf1201,
|
||||
(DwarfForm) 0x53a5b7a8));
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
@@ -340,8 +302,7 @@ TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
|
||||
// Root DIE.
|
||||
{
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartRootDIE(0x15f0e06bdfe3c372LL, (DwarfTag) 0xf5d60c59,
|
||||
ContainerEq(root_attribute_list)))
|
||||
StartRootDIE(0x15f0e06bdfe3c372LL, (DwarfTag) 0xf5d60c59))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
ProcessAttributeSigned((DwarfAttribute) 0xf779a642,
|
||||
@@ -354,8 +315,7 @@ TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
|
||||
// First child DIE.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
FindChildHandler(0x149f644f8116fe8cLL,
|
||||
(DwarfTag) 0xac2cbd8c,
|
||||
ContainerEq(child1_attribute_list)))
|
||||
(DwarfTag) 0xac2cbd8c))
|
||||
.WillOnce(Return(mock_child1_handler));
|
||||
{
|
||||
EXPECT_CALL(*mock_child1_handler,
|
||||
@@ -374,15 +334,13 @@ TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
|
||||
// for this child.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
FindChildHandler(0x97412be24875de9dLL,
|
||||
(DwarfTag) 0x505a068b,
|
||||
ContainerEq(child2_attribute_list)))
|
||||
(DwarfTag) 0x505a068b))
|
||||
.WillOnce(Return((DIEHandler *) NULL));
|
||||
|
||||
// Third child DIE.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
FindChildHandler(0x753c964c8ab538aeLL,
|
||||
(DwarfTag) 0x8c22970e,
|
||||
ContainerEq(child3_attribute_list)))
|
||||
(DwarfTag) 0x8c22970e))
|
||||
.WillOnce(Return(mock_child3_handler));
|
||||
{
|
||||
EXPECT_CALL(*mock_child3_handler,
|
||||
@@ -411,8 +369,7 @@ TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
|
||||
// Report the root DIE.
|
||||
{
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0x15f0e06bdfe3c372LL,
|
||||
(DwarfTag) 0xf5d60c59,
|
||||
root_attribute_list));
|
||||
(DwarfTag) 0xf5d60c59));
|
||||
die_dispatcher.ProcessAttributeSigned(0x15f0e06bdfe3c372LL,
|
||||
(DwarfAttribute) 0xf779a642,
|
||||
(DwarfForm) 0x2cb63027,
|
||||
@@ -421,8 +378,7 @@ TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
|
||||
// First child DIE.
|
||||
{
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0x149f644f8116fe8cLL,
|
||||
(DwarfTag) 0xac2cbd8c,
|
||||
child1_attribute_list));
|
||||
(DwarfTag) 0xac2cbd8c));
|
||||
die_dispatcher.ProcessAttributeSigned(0x149f644f8116fe8cLL,
|
||||
(DwarfAttribute) 0xa6fd6f65,
|
||||
(DwarfForm) 0xe4f64c41,
|
||||
@@ -431,15 +387,13 @@ TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
|
||||
// First grandchild DIE. Will be skipped.
|
||||
{
|
||||
EXPECT_FALSE(die_dispatcher.StartDIE(0xd68de1ee0bd29419LL,
|
||||
(DwarfTag) 0x22f05a15,
|
||||
grandchild1_attribute_list));
|
||||
(DwarfTag) 0x22f05a15));
|
||||
// First great-grandchild DIE. Will be skipped without being
|
||||
// mentioned to any handler.
|
||||
{
|
||||
EXPECT_FALSE(die_dispatcher
|
||||
.StartDIE(0xb3076285d25cac25LL,
|
||||
(DwarfTag) 0xcff4061b,
|
||||
greatgrandchild1_attribute_list));
|
||||
(DwarfTag) 0xcff4061b));
|
||||
die_dispatcher.EndDIE(0xb3076285d25cac25LL);
|
||||
}
|
||||
die_dispatcher.EndDIE(0xd68de1ee0bd29419LL);
|
||||
@@ -450,16 +404,14 @@ TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
|
||||
// Second child DIE. Root handler will decline to find a handler for it.
|
||||
{
|
||||
EXPECT_FALSE(die_dispatcher.StartDIE(0x97412be24875de9dLL,
|
||||
(DwarfTag) 0x505a068b,
|
||||
child2_attribute_list));
|
||||
(DwarfTag) 0x505a068b));
|
||||
die_dispatcher.EndDIE(0x97412be24875de9dLL);
|
||||
}
|
||||
|
||||
// Third child DIE.
|
||||
{
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0x753c964c8ab538aeLL,
|
||||
(DwarfTag) 0x8c22970e,
|
||||
child3_attribute_list));
|
||||
(DwarfTag) 0x8c22970e));
|
||||
die_dispatcher.ProcessAttributeSigned(0x753c964c8ab538aeLL,
|
||||
(DwarfAttribute) 0x4e2b7cfb,
|
||||
(DwarfForm) 0x610b7ae1,
|
||||
@@ -478,7 +430,6 @@ TEST(Dwarf2DIEHandler, FreeHandlersOnStack) {
|
||||
MockRootDIEHandler mock_root_handler;
|
||||
MockDIEHandler *mock_child_handler = new(MockDIEHandler);
|
||||
MockDIEHandler *mock_grandchild_handler = new(MockDIEHandler);
|
||||
AttributeList empty_attribute_list;
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
@@ -492,8 +443,7 @@ TEST(Dwarf2DIEHandler, FreeHandlersOnStack) {
|
||||
// Root DIE.
|
||||
{
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartRootDIE(0xbf13b761691ddc91LL, (DwarfTag) 0x98980361,
|
||||
ContainerEq(empty_attribute_list)))
|
||||
StartRootDIE(0xbf13b761691ddc91LL, (DwarfTag) 0x98980361))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_root_handler, EndAttributes())
|
||||
.WillOnce(Return(true));
|
||||
@@ -501,8 +451,7 @@ TEST(Dwarf2DIEHandler, FreeHandlersOnStack) {
|
||||
// Child DIE.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
FindChildHandler(0x058f09240c5fc8c9LL,
|
||||
(DwarfTag) 0x898bf0d0,
|
||||
ContainerEq(empty_attribute_list)))
|
||||
(DwarfTag) 0x898bf0d0))
|
||||
.WillOnce(Return(mock_child_handler));
|
||||
{
|
||||
EXPECT_CALL(*mock_child_handler, EndAttributes())
|
||||
@@ -511,8 +460,7 @@ TEST(Dwarf2DIEHandler, FreeHandlersOnStack) {
|
||||
// Grandchild DIE.
|
||||
EXPECT_CALL(*mock_child_handler,
|
||||
FindChildHandler(0x32dc00c9945dc0c8LL,
|
||||
(DwarfTag) 0x2802d007,
|
||||
ContainerEq(empty_attribute_list)))
|
||||
(DwarfTag) 0x2802d007))
|
||||
.WillOnce(Return(mock_grandchild_handler));
|
||||
{
|
||||
EXPECT_CALL(*mock_grandchild_handler,
|
||||
@@ -548,20 +496,17 @@ TEST(Dwarf2DIEHandler, FreeHandlersOnStack) {
|
||||
// Report the root DIE.
|
||||
{
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0xbf13b761691ddc91LL,
|
||||
(DwarfTag) 0x98980361,
|
||||
empty_attribute_list));
|
||||
(DwarfTag) 0x98980361));
|
||||
|
||||
// Child DIE.
|
||||
{
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0x058f09240c5fc8c9LL,
|
||||
(DwarfTag) 0x898bf0d0,
|
||||
empty_attribute_list));
|
||||
(DwarfTag) 0x898bf0d0));
|
||||
|
||||
// Grandchild DIE.
|
||||
{
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0x32dc00c9945dc0c8LL,
|
||||
(DwarfTag) 0x2802d007,
|
||||
empty_attribute_list));
|
||||
(DwarfTag) 0x2802d007));
|
||||
die_dispatcher.ProcessAttributeSigned(0x32dc00c9945dc0c8LL,
|
||||
(DwarfAttribute) 0x4e2b7cfb,
|
||||
(DwarfForm) 0x610b7ae1,
|
||||
|
35
thirdparty/breakpad/common/dwarf/dwarf2reader.cc
vendored
35
thirdparty/breakpad/common/dwarf/dwarf2reader.cc
vendored
@@ -41,11 +41,13 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#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 {
|
||||
|
||||
@@ -498,7 +500,7 @@ void CompilationUnit::ProcessDIEs() {
|
||||
|
||||
const Abbrev& abbrev = abbrevs_->at(static_cast<size_t>(abbrev_num));
|
||||
const enum DwarfTag tag = abbrev.tag;
|
||||
if (!handler_->StartDIE(absolute_offset, tag, abbrev.attributes)) {
|
||||
if (!handler_->StartDIE(absolute_offset, tag)) {
|
||||
dieptr = SkipDIE(dieptr, abbrev);
|
||||
} else {
|
||||
dieptr = ProcessDIE(absolute_offset, dieptr, abbrev);
|
||||
@@ -1004,7 +1006,7 @@ class CallFrameInfo::RegisterRule: public CallFrameInfo::Rule {
|
||||
// Rule: EXPRESSION evaluates to the address at which the register is saved.
|
||||
class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule {
|
||||
public:
|
||||
explicit ExpressionRule(const std::string &expression)
|
||||
explicit ExpressionRule(const string &expression)
|
||||
: expression_(expression) { }
|
||||
~ExpressionRule() { }
|
||||
bool Handle(Handler *handler, uint64 address, int reg) const {
|
||||
@@ -1018,13 +1020,13 @@ class CallFrameInfo::ExpressionRule: public CallFrameInfo::Rule {
|
||||
}
|
||||
Rule *Copy() const { return new ExpressionRule(*this); }
|
||||
private:
|
||||
std::string expression_;
|
||||
string expression_;
|
||||
};
|
||||
|
||||
// Rule: EXPRESSION evaluates to the address at which the register is saved.
|
||||
class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule {
|
||||
public:
|
||||
explicit ValExpressionRule(const std::string &expression)
|
||||
explicit ValExpressionRule(const string &expression)
|
||||
: expression_(expression) { }
|
||||
~ValExpressionRule() { }
|
||||
bool Handle(Handler *handler, uint64 address, int reg) const {
|
||||
@@ -1039,7 +1041,7 @@ class CallFrameInfo::ValExpressionRule: public CallFrameInfo::Rule {
|
||||
}
|
||||
Rule *Copy() const { return new ValExpressionRule(*this); }
|
||||
private:
|
||||
std::string expression_;
|
||||
string expression_;
|
||||
};
|
||||
|
||||
// A map from register numbers to rules.
|
||||
@@ -1220,7 +1222,7 @@ class CallFrameInfo::State {
|
||||
unsigned register_number; // A register number.
|
||||
uint64 offset; // An offset or address.
|
||||
long signed_offset; // A signed offset.
|
||||
std::string expression; // A DWARF expression.
|
||||
string expression; // A DWARF expression.
|
||||
};
|
||||
|
||||
// Parse CFI instruction operands from STATE's instruction stream as
|
||||
@@ -1407,7 +1409,7 @@ bool CallFrameInfo::State::ParseOperands(const char *format,
|
||||
if (len > bytes_left || expression_length > bytes_left - len)
|
||||
return ReportIncomplete();
|
||||
cursor_ += len;
|
||||
operands->expression = std::string(cursor_, expression_length);
|
||||
operands->expression = string(cursor_, expression_length);
|
||||
cursor_ += expression_length;
|
||||
break;
|
||||
}
|
||||
@@ -1510,16 +1512,19 @@ bool CallFrameInfo::State::DoInstruction() {
|
||||
|
||||
// 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) {
|
||||
reporter_->NoCFARule(entry_->offset, entry_->kind, CursorOffset());
|
||||
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;
|
||||
}
|
||||
if (!ParseOperands("r", &ops)) return false;
|
||||
cfa_rule->SetBaseRegister(ops.register_number);
|
||||
if (!cfa_rule->Handle(handler_, address_,
|
||||
Handler::kCFARegister))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1872,7 +1877,7 @@ bool CallFrameInfo::ReadCIEFields(CIE *cie) {
|
||||
memchr(augmentation_start, '\0', cie->end - augmentation_start);
|
||||
if (! augmentation_end) return ReportIncomplete(cie);
|
||||
cursor = static_cast<const char *>(augmentation_end);
|
||||
cie->augmentation = std::string(augmentation_start,
|
||||
cie->augmentation = string(augmentation_start,
|
||||
cursor - augmentation_start);
|
||||
// Skip the terminating '\0'.
|
||||
cursor++;
|
||||
@@ -2260,7 +2265,7 @@ void CallFrameInfo::Reporter::UnrecognizedVersion(uint64 offset, int version) {
|
||||
}
|
||||
|
||||
void CallFrameInfo::Reporter::UnrecognizedAugmentation(uint64 offset,
|
||||
const std::string &aug) {
|
||||
const string &aug) {
|
||||
fprintf(stderr,
|
||||
"%s: CFI frame description entry at offset 0x%llx in '%s':"
|
||||
" CIE specifies unrecognized augmentation: '%s'\n",
|
||||
|
30
thirdparty/breakpad/common/dwarf/dwarf2reader.h
vendored
30
thirdparty/breakpad/common/dwarf/dwarf2reader.h
vendored
@@ -49,6 +49,7 @@
|
||||
#include "common/dwarf/bytereader.h"
|
||||
#include "common/dwarf/dwarf2enums.h"
|
||||
#include "common/dwarf/types.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace dwarf2reader {
|
||||
struct LineStateMachine;
|
||||
@@ -57,7 +58,7 @@ class LineInfoHandler;
|
||||
|
||||
// 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<std::string, std::pair<const char*, uint64> > SectionMap;
|
||||
typedef std::map<string, std::pair<const char*, uint64> > SectionMap;
|
||||
typedef std::list<std::pair<enum DwarfAttribute, enum DwarfForm> >
|
||||
AttributeList;
|
||||
typedef AttributeList::iterator AttributeIterator;
|
||||
@@ -156,7 +157,7 @@ class LineInfoHandler {
|
||||
|
||||
// Called when we define a directory. NAME is the directory name,
|
||||
// DIR_NUM is the directory number
|
||||
virtual void DefineDir(const std::string& name, uint32 dir_num) { }
|
||||
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
|
||||
@@ -165,7 +166,7 @@ class LineInfoHandler {
|
||||
// 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 std::string& name, int32 file_num,
|
||||
virtual void DefineFile(const string& name, int32 file_num,
|
||||
uint32 dir_num, uint64 mod_time,
|
||||
uint64 length) { }
|
||||
|
||||
@@ -341,8 +342,7 @@ class Dwarf2Handler {
|
||||
|
||||
// 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,
|
||||
const AttributeList& attrs) { return false; }
|
||||
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
|
||||
@@ -391,7 +391,7 @@ class Dwarf2Handler {
|
||||
virtual void ProcessAttributeString(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const std::string& data) { }
|
||||
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
|
||||
@@ -699,7 +699,7 @@ class CallFrameInfo {
|
||||
// A common information entry (CIE).
|
||||
struct CIE: public Entry {
|
||||
uint8 version; // CFI data version number
|
||||
std::string augmentation; // vendor format extension markers
|
||||
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
|
||||
@@ -833,7 +833,7 @@ class CallFrameInfo::Handler {
|
||||
// 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 std::string &augmentation,
|
||||
uint8 version, const string &augmentation,
|
||||
unsigned return_address) = 0;
|
||||
|
||||
// When the Entry function returns true, the parser calls these
|
||||
@@ -882,13 +882,13 @@ class CallFrameInfo::Handler {
|
||||
// At ADDRESS, the DWARF expression EXPRESSION yields the address at
|
||||
// which REG was saved.
|
||||
virtual bool ExpressionRule(uint64 address, int reg,
|
||||
const std::string &expression) = 0;
|
||||
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 std::string &expression) = 0;
|
||||
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
|
||||
@@ -965,8 +965,8 @@ class CallFrameInfo::Reporter {
|
||||
// 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 std::string &filename,
|
||||
const std::string §ion = ".debug_frame")
|
||||
Reporter(const string &filename,
|
||||
const string §ion = ".debug_frame")
|
||||
: filename_(filename), section_(section) { }
|
||||
virtual ~Reporter() { }
|
||||
|
||||
@@ -998,7 +998,7 @@ class CallFrameInfo::Reporter {
|
||||
// which we don't recognize. We cannot parse DWARF CFI if it uses
|
||||
// augmentations we don't recognize.
|
||||
virtual void UnrecognizedAugmentation(uint64 offset,
|
||||
const std::string &augmentation);
|
||||
const string &augmentation);
|
||||
|
||||
// The pointer encoding ENCODING, specified by the CIE at OFFSET, is not
|
||||
// a valid encoding.
|
||||
@@ -1039,10 +1039,10 @@ class CallFrameInfo::Reporter {
|
||||
|
||||
protected:
|
||||
// The name of the file whose CFI we're reading.
|
||||
std::string filename_;
|
||||
string filename_;
|
||||
|
||||
// The name of the CFI section in that file.
|
||||
std::string section_;
|
||||
string section_;
|
||||
};
|
||||
|
||||
} // namespace dwarf2reader
|
||||
|
@@ -62,6 +62,7 @@ extern "C" {
|
||||
#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;
|
||||
@@ -76,7 +77,6 @@ using dwarf2reader::ENDIANNESS_LITTLE;
|
||||
using dwarf2reader::ByteReader;
|
||||
using dwarf2reader::CallFrameInfo;
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using testing::InSequence;
|
||||
using testing::Return;
|
||||
@@ -2326,14 +2326,14 @@ struct ELFSectionHeader {
|
||||
alignment(1), entry_size(0) { }
|
||||
Label name;
|
||||
unsigned int type;
|
||||
u_int64_t flags;
|
||||
u_int64_t address;
|
||||
uint64_t flags;
|
||||
uint64_t address;
|
||||
Label file_offset;
|
||||
Label file_size;
|
||||
unsigned int link;
|
||||
unsigned int info;
|
||||
u_int64_t alignment;
|
||||
u_int64_t entry_size;
|
||||
uint64_t alignment;
|
||||
uint64_t entry_size;
|
||||
};
|
||||
|
||||
void AppendSectionHeader(CFISection *table, const ELFSectionHeader &header) {
|
||||
|
@@ -41,6 +41,7 @@
|
||||
#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;
|
||||
@@ -49,7 +50,6 @@ using google_breakpad::test_assembler::Section;
|
||||
using google_breakpad::test_assembler::kBigEndian;
|
||||
using google_breakpad::test_assembler::kLittleEndian;
|
||||
|
||||
using dwarf2reader::AttributeList;
|
||||
using dwarf2reader::ByteReader;
|
||||
using dwarf2reader::CompilationUnit;
|
||||
using dwarf2reader::Dwarf2Handler;
|
||||
@@ -61,7 +61,6 @@ using dwarf2reader::ENDIANNESS_BIG;
|
||||
using dwarf2reader::ENDIANNESS_LITTLE;
|
||||
using dwarf2reader::SectionMap;
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
using testing::InSequence;
|
||||
using testing::Pointee;
|
||||
@@ -76,8 +75,7 @@ class MockDwarf2Handler: public Dwarf2Handler {
|
||||
MOCK_METHOD5(StartCompilationUnit, bool(uint64 offset, uint8 address_size,
|
||||
uint8 offset_size, uint64 cu_length,
|
||||
uint8 dwarf_version));
|
||||
MOCK_METHOD3(StartDIE, bool(uint64 offset, enum DwarfTag tag,
|
||||
const AttributeList& attrs));
|
||||
MOCK_METHOD2(StartDIE, bool(uint64 offset, enum DwarfTag tag));
|
||||
MOCK_METHOD4(ProcessAttributeUnsigned, void(uint64 offset,
|
||||
DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
@@ -98,7 +96,7 @@ class MockDwarf2Handler: public Dwarf2Handler {
|
||||
MOCK_METHOD4(ProcessAttributeString, void(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const std::string& data));
|
||||
const string& data));
|
||||
MOCK_METHOD4(ProcessAttributeSignature, void(uint64 offset,
|
||||
DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
@@ -115,7 +113,7 @@ struct DIEFixture {
|
||||
|
||||
// Default expectations for the data handler.
|
||||
EXPECT_CALL(handler, StartCompilationUnit(_, _, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, StartDIE(_, _, _)).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);
|
||||
@@ -186,7 +184,7 @@ TEST_P(DwarfHeader, Header) {
|
||||
GetParam().format_size, _,
|
||||
GetParam().version))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit, _))
|
||||
EXPECT_CALL(handler, StartDIE(_, dwarf2reader::DW_TAG_compile_unit))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(handler, ProcessAttributeString(_, dwarf2reader::DW_AT_name,
|
||||
dwarf2reader::DW_FORM_string,
|
||||
@@ -262,7 +260,7 @@ struct DwarfFormsFixture: public DIEFixture {
|
||||
params.version))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(handler, StartDIE(_, tag, _))
|
||||
EXPECT_CALL(handler, StartDIE(_, tag))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
@@ -291,7 +289,7 @@ TEST_P(DwarfForms, addr) {
|
||||
StartSingleAttributeDIE(GetParam(), dwarf2reader::DW_TAG_compile_unit,
|
||||
dwarf2reader::DW_AT_low_pc,
|
||||
dwarf2reader::DW_FORM_addr);
|
||||
u_int64_t value;
|
||||
uint64_t value;
|
||||
if (GetParam().address_size == 4) {
|
||||
value = 0xc8e9ffcc;
|
||||
info.D32(value);
|
||||
@@ -374,7 +372,7 @@ TEST_P(DwarfForms, sec_offset) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689,
|
||||
(DwarfAttribute) 0xa060bfd1,
|
||||
dwarf2reader::DW_FORM_sec_offset);
|
||||
u_int64_t value;
|
||||
uint64_t value;
|
||||
if (GetParam().format_size == 4) {
|
||||
value = 0xacc9c388;
|
||||
info.D32(value);
|
||||
|
@@ -97,7 +97,7 @@ class TestCompilationUnit: public google_breakpad::test_assembler::Section {
|
||||
|
||||
// The offset of the point in the compilation unit header immediately
|
||||
// after the initial length field.
|
||||
u_int64_t post_length_offset_;
|
||||
uint64_t post_length_offset_;
|
||||
|
||||
// The length of the compilation unit, not including the initial length field.
|
||||
Label length_;
|
||||
|
36
thirdparty/breakpad/common/dwarf/functioninfo.cc
vendored
36
thirdparty/breakpad/common/dwarf/functioninfo.cc
vendored
@@ -36,17 +36,18 @@
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#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<std::string>* dirs,
|
||||
std::vector<string>* dirs,
|
||||
LineMap* linemap):linemap_(linemap),
|
||||
files_(files),
|
||||
dirs_(dirs) {
|
||||
@@ -61,13 +62,13 @@ CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files,
|
||||
files->push_back(s);
|
||||
}
|
||||
|
||||
void CULineInfoHandler::DefineDir(const std::string& name, uint32 dir_num) {
|
||||
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 std::string& name,
|
||||
void CULineInfoHandler::DefineFile(const string& name,
|
||||
int32 file_num, uint32 dir_num,
|
||||
uint64 mod_time, uint64 length) {
|
||||
assert(dir_num >= 0);
|
||||
@@ -75,7 +76,7 @@ void CULineInfoHandler::DefineFile(const std::string& name,
|
||||
|
||||
// These should never come out of order, actually.
|
||||
if (file_num == (int32)files_->size() || file_num == -1) {
|
||||
std::string dir = dirs_->at(dir_num);
|
||||
string dir = dirs_->at(dir_num);
|
||||
|
||||
SourceFileInfo s;
|
||||
s.lowpc = ULLONG_MAX;
|
||||
@@ -100,11 +101,11 @@ void CULineInfoHandler::AddLine(uint64 address, uint64 length, uint32 file_num,
|
||||
std::make_pair(files_->at(file_num).name.c_str(),
|
||||
line_num)));
|
||||
|
||||
if(address < files_->at(file_num).lowpc) {
|
||||
if (address < files_->at(file_num).lowpc) {
|
||||
files_->at(file_num).lowpc = address;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr,"error in AddLine");
|
||||
fprintf(stderr, "error in AddLine");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,8 +123,7 @@ bool CUFunctionInfoHandler::StartCompilationUnit(uint64 offset,
|
||||
// subroutines. For line info, the DW_AT_stmt_list lives in the
|
||||
// compile unit tag.
|
||||
|
||||
bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag,
|
||||
const AttributeList& attrs) {
|
||||
bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag) {
|
||||
switch (tag) {
|
||||
case DW_TAG_subprogram:
|
||||
case DW_TAG_inlined_subroutine: {
|
||||
@@ -149,11 +149,11 @@ bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag,
|
||||
void CUFunctionInfoHandler::ProcessAttributeString(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const std::string &data) {
|
||||
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)
|
||||
else if (attr == DW_AT_MIPS_linkage_name)
|
||||
current_function_info_->mangled_name = data;
|
||||
}
|
||||
}
|
||||
@@ -166,10 +166,9 @@ void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset,
|
||||
SectionMap::const_iterator iter = sections_.find("__debug_line");
|
||||
assert(iter != sections_.end());
|
||||
|
||||
// this should be a scoped_ptr but we dont' use boost :-(
|
||||
std::auto_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data,
|
||||
iter->second.second - data,
|
||||
reader_, linehandler_));
|
||||
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) {
|
||||
@@ -210,7 +209,10 @@ void CUFunctionInfoHandler::ProcessAttributeReference(uint64 offset,
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
28
thirdparty/breakpad/common/dwarf/functioninfo.h
vendored
28
thirdparty/breakpad/common/dwarf/functioninfo.h
vendored
@@ -40,17 +40,18 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
|
||||
namespace dwarf2reader {
|
||||
|
||||
struct FunctionInfo {
|
||||
// Name of the function
|
||||
std::string name;
|
||||
string name;
|
||||
// Mangled name of the function
|
||||
std::string mangled_name;
|
||||
string mangled_name;
|
||||
// File containing this function
|
||||
std::string file;
|
||||
string file;
|
||||
// Line number for start of function.
|
||||
uint32 line;
|
||||
// Beginning address for this function
|
||||
@@ -61,13 +62,13 @@ struct FunctionInfo {
|
||||
|
||||
struct SourceFileInfo {
|
||||
// Name of the source file name
|
||||
std::string name;
|
||||
string name;
|
||||
// Low address of source file name
|
||||
uint64 lowpc;
|
||||
};
|
||||
|
||||
typedef std::map<uint64, FunctionInfo*> FunctionMap;
|
||||
typedef std::map<uint64, std::pair<std::string, uint32> > LineMap;
|
||||
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
|
||||
@@ -77,17 +78,17 @@ class CULineInfoHandler: public LineInfoHandler {
|
||||
|
||||
//
|
||||
CULineInfoHandler(std::vector<SourceFileInfo>* files,
|
||||
std::vector<std::string>* dirs,
|
||||
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 std::string& name, uint32 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 std::string& name, int32 file_num,
|
||||
virtual void DefineFile(const string& name, int32 file_num,
|
||||
uint32 dir_num, uint64 mod_time, uint64 length);
|
||||
|
||||
|
||||
@@ -103,13 +104,13 @@ class CULineInfoHandler: public LineInfoHandler {
|
||||
private:
|
||||
LineMap* linemap_;
|
||||
std::vector<SourceFileInfo>* files_;
|
||||
std::vector<std::string>* dirs_;
|
||||
std::vector<string>* dirs_;
|
||||
};
|
||||
|
||||
class CUFunctionInfoHandler: public Dwarf2Handler {
|
||||
public:
|
||||
CUFunctionInfoHandler(std::vector<SourceFileInfo>* files,
|
||||
std::vector<std::string>* dirs,
|
||||
std::vector<string>* dirs,
|
||||
LineMap* linemap,
|
||||
FunctionMap* offset_to_funcinfo,
|
||||
FunctionMap* address_to_funcinfo,
|
||||
@@ -134,8 +135,7 @@ class CUFunctionInfoHandler: public Dwarf2Handler {
|
||||
|
||||
// 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,
|
||||
const AttributeList& attrs);
|
||||
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
|
||||
@@ -163,7 +163,7 @@ class CUFunctionInfoHandler: public Dwarf2Handler {
|
||||
virtual void ProcessAttributeString(uint64 offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const std::string& data);
|
||||
const string& data);
|
||||
|
||||
// Called when finished processing the DIE at OFFSET.
|
||||
// Because DWARF2/3 specifies a tree of DIEs, you may get starts
|
||||
@@ -173,7 +173,7 @@ class CUFunctionInfoHandler: public Dwarf2Handler {
|
||||
|
||||
private:
|
||||
std::vector<SourceFileInfo>* files_;
|
||||
std::vector<std::string>* dirs_;
|
||||
std::vector<string>* dirs_;
|
||||
LineMap* linemap_;
|
||||
FunctionMap* offset_to_funcinfo_;
|
||||
FunctionMap* address_to_funcinfo_;
|
||||
|
@@ -84,17 +84,44 @@ vector<string> DwarfCFIToModule::RegisterNames::X86_64() {
|
||||
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"
|
||||
"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]));
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -132,7 +159,8 @@ string DwarfCFIToModule::RegisterName(int i) {
|
||||
if (reg == return_address_)
|
||||
return ra_name_;
|
||||
|
||||
if (reg < register_names_.size())
|
||||
// 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);
|
||||
|
@@ -48,13 +48,13 @@
|
||||
|
||||
#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::string;
|
||||
using std::vector;
|
||||
|
||||
// A class that accepts parsed call frame information from the DWARF
|
||||
@@ -108,6 +108,9 @@ class DwarfCFIToModule: public CallFrameInfo::Handler {
|
||||
|
||||
// ARM.
|
||||
static vector<string> ARM();
|
||||
|
||||
// MIPS.
|
||||
static vector<string> MIPS();
|
||||
|
||||
private:
|
||||
// Given STRINGS, an array of C strings with SIZE elements, return an
|
||||
|
@@ -36,8 +36,8 @@
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/dwarf_cfi_to_module.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
using google_breakpad::Module;
|
||||
@@ -69,6 +69,7 @@ struct DwarfCFIToModuleFixture {
|
||||
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);
|
||||
@@ -140,6 +141,17 @@ TEST_F(Rule, UndefinedRule) {
|
||||
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));
|
||||
@@ -178,17 +190,17 @@ TEST_F(Rule, OffsetRuleNegative) {
|
||||
|
||||
TEST_F(Rule, ValOffsetRule) {
|
||||
// Use an unnamed register number, to exercise that branch of RegisterName.
|
||||
EXPECT_CALL(reporter, UnnamedRegister(_, 10));
|
||||
EXPECT_CALL(reporter, UnnamedRegister(_, 11));
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7,
|
||||
DwarfCFIToModule::kCFARegister,
|
||||
10, 61812979));
|
||||
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_register10 61812979 +";
|
||||
"unnamed_register11 61812979 +";
|
||||
EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
|
||||
}
|
||||
|
||||
|
274
thirdparty/breakpad/common/dwarf_cu_to_module.cc
vendored
274
thirdparty/breakpad/common/dwarf_cu_to_module.cc
vendored
@@ -39,6 +39,9 @@
|
||||
#include "common/dwarf_cu_to_module.h"
|
||||
|
||||
#include <assert.h>
|
||||
#if !defined(__ANDROID__)
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -53,10 +56,11 @@ namespace google_breakpad {
|
||||
using std::map;
|
||||
using std::pair;
|
||||
using std::set;
|
||||
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
|
||||
@@ -73,6 +77,9 @@ using std::vector;
|
||||
// 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;
|
||||
|
||||
@@ -84,7 +91,7 @@ struct DwarfCUToModule::Specification {
|
||||
// An abstract origin -- base definition of an inline function.
|
||||
struct AbstractOrigin {
|
||||
AbstractOrigin() : name() {}
|
||||
AbstractOrigin(const string& name) : name(name) {}
|
||||
explicit AbstractOrigin(const string& name) : name(name) {}
|
||||
|
||||
string name;
|
||||
};
|
||||
@@ -97,12 +104,20 @@ 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.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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.
|
||||
set<string> common_strings;
|
||||
|
||||
// A map from offsets of DIEs within the .debug_info section to
|
||||
@@ -113,14 +128,42 @@ struct DwarfCUToModule::FilePrivate {
|
||||
AbstractOriginByOffset origins;
|
||||
};
|
||||
|
||||
DwarfCUToModule::FileContext::FileContext(const string &filename_arg,
|
||||
Module *module_arg)
|
||||
: filename(filename_arg), module(module_arg) {
|
||||
file_private = new FilePrivate();
|
||||
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() {
|
||||
delete file_private;
|
||||
}
|
||||
|
||||
void DwarfCUToModule::FileContext::AddSectionToSectionMap(
|
||||
const string& name, const char* 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
|
||||
@@ -130,11 +173,13 @@ struct DwarfCUToModule::CUContext {
|
||||
CUContext(FileContext *file_context_arg, WarningReporter *reporter_arg)
|
||||
: file_context(file_context_arg),
|
||||
reporter(reporter_arg),
|
||||
language(Language::CPlusPlus) { }
|
||||
language(Language::CPlusPlus) {}
|
||||
|
||||
~CUContext() {
|
||||
for (vector<Module::Function *>::iterator it = functions.begin();
|
||||
it != functions.end(); it++)
|
||||
it != functions.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
};
|
||||
|
||||
// The DWARF-bearing file into which this CU was incorporated.
|
||||
@@ -218,6 +263,14 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
|
||||
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_;
|
||||
@@ -230,6 +283,11 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
|
||||
// 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(
|
||||
@@ -248,14 +306,19 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
|
||||
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.
|
||||
FileContext *file_context = cu_context_->file_context;
|
||||
SpecificationByOffset *specifications
|
||||
= &file_context->file_private->specifications;
|
||||
SpecificationByOffset *specifications =
|
||||
&file_context->file_private_->specifications;
|
||||
SpecificationByOffset::iterator spec = specifications->find(data);
|
||||
if (spec != specifications->end()) {
|
||||
specification_ = &spec->second;
|
||||
@@ -273,20 +336,29 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
|
||||
}
|
||||
}
|
||||
|
||||
string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) {
|
||||
pair<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: {
|
||||
// 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 strings whenever possible.
|
||||
pair<set<string>::iterator, bool> result =
|
||||
cu_context_->file_context->file_private->common_strings.insert(data);
|
||||
name_attribute_ = *result.first;
|
||||
case dwarf2reader::DW_AT_name:
|
||||
name_attribute_ = AddStringToPool(data);
|
||||
break;
|
||||
case dwarf2reader::DW_AT_MIPS_linkage_name: {
|
||||
char* demangled = NULL;
|
||||
#if !defined(__ANDROID__)
|
||||
demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, NULL);
|
||||
#endif
|
||||
if (demangled) {
|
||||
demangled_name_ = AddStringToPool(demangled);
|
||||
free(reinterpret_cast<void*>(demangled));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
@@ -294,33 +366,53 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
|
||||
}
|
||||
|
||||
string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
|
||||
// Find our unqualified name. If the DIE has its own DW_AT_name
|
||||
// attribute, then use that; otherwise, check our specification.
|
||||
const string *unqualified_name;
|
||||
if (name_attribute_.empty() && specification_)
|
||||
unqualified_name = &specification_->unqualified_name;
|
||||
else
|
||||
unqualified_name = &name_attribute_;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Find the name of our enclosing context. If we have a
|
||||
// specification, it's the specification's enclosing context that
|
||||
// counts; otherwise, use this DIE's context.
|
||||
const string *unqualified_name;
|
||||
const string *enclosing_name;
|
||||
if (specification_)
|
||||
enclosing_name = &specification_->enclosing_name;
|
||||
else
|
||||
enclosing_name = &parent_context_->name;
|
||||
if (!qualified_name) {
|
||||
// Find our unqualified name. If the DIE has its own DW_AT_name
|
||||
// attribute, then use that; otherwise, check our specification.
|
||||
if (name_attribute_.empty() && specification_)
|
||||
unqualified_name = &specification_->unqualified_name;
|
||||
else
|
||||
unqualified_name = &name_attribute_;
|
||||
|
||||
// Find the name of our enclosing context. If we have 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;
|
||||
}
|
||||
|
||||
// If this DIE was marked as a declaration, record its names in the
|
||||
// specification table.
|
||||
if (declaration_) {
|
||||
FileContext *file_context = cu_context_->file_context;
|
||||
Specification spec;
|
||||
spec.enclosing_name = *enclosing_name;
|
||||
spec.unqualified_name = *unqualified_name;
|
||||
file_context->file_private->specifications[offset_] = 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;
|
||||
}
|
||||
|
||||
if (qualified_name)
|
||||
return *qualified_name;
|
||||
|
||||
// Combine the enclosing name and unqualified name to produce our
|
||||
// own fully-qualified name.
|
||||
return cu_context_->language->MakeQualifiedName(*enclosing_name,
|
||||
@@ -333,7 +425,8 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler {
|
||||
FuncHandler(CUContext *cu_context, DIEContext *parent_context,
|
||||
uint64 offset)
|
||||
: GenericDIEHandler(cu_context, parent_context, offset),
|
||||
low_pc_(0), high_pc_(0), abstract_origin_(NULL), inline_(false) { }
|
||||
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);
|
||||
@@ -352,6 +445,7 @@ class DwarfCUToModule::FuncHandler: public GenericDIEHandler {
|
||||
// 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_;
|
||||
};
|
||||
@@ -367,7 +461,11 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeUnsigned(
|
||||
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_ = data; break;
|
||||
case dwarf2reader::DW_AT_high_pc:
|
||||
high_pc_form_ = form;
|
||||
high_pc_ = data;
|
||||
break;
|
||||
|
||||
default:
|
||||
GenericDIEHandler::ProcessAttributeUnsigned(attr, form, data);
|
||||
break;
|
||||
@@ -393,10 +491,10 @@ void DwarfCUToModule::FuncHandler::ProcessAttributeReference(
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64 data) {
|
||||
switch(attr) {
|
||||
switch (attr) {
|
||||
case dwarf2reader::DW_AT_abstract_origin: {
|
||||
const AbstractOriginByOffset& origins =
|
||||
cu_context_->file_context->file_private->origins;
|
||||
cu_context_->file_context->file_private_->origins;
|
||||
AbstractOriginByOffset::const_iterator origin = origins.find(data);
|
||||
if (origin != origins.end()) {
|
||||
abstract_origin_ = &(origin->second);
|
||||
@@ -421,6 +519,11 @@ bool DwarfCUToModule::FuncHandler::EndAttributes() {
|
||||
}
|
||||
|
||||
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
|
||||
@@ -447,7 +550,7 @@ void DwarfCUToModule::FuncHandler::Finish() {
|
||||
}
|
||||
} else if (inline_) {
|
||||
AbstractOrigin origin(name_);
|
||||
cu_context_->file_context->file_private->origins[offset_] = origin;
|
||||
cu_context_->file_context->file_private_->origins[offset_] = origin;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,8 +562,7 @@ class DwarfCUToModule::NamedScopeHandler: public GenericDIEHandler {
|
||||
uint64 offset)
|
||||
: GenericDIEHandler(cu_context, parent_context, offset) { }
|
||||
bool EndAttributes();
|
||||
DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag,
|
||||
const AttributeList &attrs);
|
||||
DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag);
|
||||
|
||||
private:
|
||||
DIEContext child_context_; // A context for our children.
|
||||
@@ -473,8 +575,7 @@ bool DwarfCUToModule::NamedScopeHandler::EndAttributes() {
|
||||
|
||||
dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler(
|
||||
uint64 offset,
|
||||
enum DwarfTag tag,
|
||||
const AttributeList &attrs) {
|
||||
enum DwarfTag tag) {
|
||||
switch (tag) {
|
||||
case dwarf2reader::DW_TAG_subprogram:
|
||||
return new FuncHandler(cu_context_, &child_context_, offset);
|
||||
@@ -561,17 +662,25 @@ void DwarfCUToModule::WarningReporter::UnnamedFunction(uint64 offset) {
|
||||
filename_.c_str(), offset);
|
||||
}
|
||||
|
||||
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,
|
||||
LineToModuleFunctor *line_reader,
|
||||
LineToModuleHandler *line_reader,
|
||||
WarningReporter *reporter)
|
||||
: line_reader_(line_reader), has_source_line_info_(false) {
|
||||
cu_context_ = new CUContext(file_context, reporter);
|
||||
child_context_ = new DIEContext();
|
||||
: line_reader_(line_reader),
|
||||
cu_context_(new CUContext(file_context, reporter)),
|
||||
child_context_(new DIEContext()),
|
||||
has_source_line_info_(false) {
|
||||
}
|
||||
|
||||
DwarfCUToModule::~DwarfCUToModule() {
|
||||
delete cu_context_;
|
||||
delete child_context_;
|
||||
}
|
||||
|
||||
void DwarfCUToModule::ProcessAttributeSigned(enum DwarfAttribute attr,
|
||||
@@ -605,8 +714,16 @@ void DwarfCUToModule::ProcessAttributeUnsigned(enum DwarfAttribute attr,
|
||||
void DwarfCUToModule::ProcessAttributeString(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string &data) {
|
||||
if (attr == dwarf2reader::DW_AT_name)
|
||||
cu_context_->reporter->SetCUName(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() {
|
||||
@@ -615,16 +732,16 @@ bool DwarfCUToModule::EndAttributes() {
|
||||
|
||||
dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler(
|
||||
uint64 offset,
|
||||
enum DwarfTag tag,
|
||||
const AttributeList &attrs) {
|
||||
enum DwarfTag tag) {
|
||||
switch (tag) {
|
||||
case dwarf2reader::DW_TAG_subprogram:
|
||||
return new FuncHandler(cu_context_, child_context_, offset);
|
||||
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_, child_context_, offset);
|
||||
return new NamedScopeHandler(cu_context_.get(), child_context_.get(),
|
||||
offset);
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
@@ -649,7 +766,7 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
|
||||
// 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.
|
||||
@@ -667,7 +784,7 @@ void DwarfCUToModule::SetLanguage(DwarfLanguage language) {
|
||||
|
||||
void DwarfCUToModule::ReadSourceLines(uint64 offset) {
|
||||
const dwarf2reader::SectionMap §ion_map
|
||||
= cu_context_->file_context->section_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 "__"
|
||||
@@ -684,8 +801,8 @@ void DwarfCUToModule::ReadSourceLines(uint64 offset) {
|
||||
cu_context_->reporter->BadLineInfoOffset(offset);
|
||||
return;
|
||||
}
|
||||
(*line_reader_)(section_start + offset, section_length - offset,
|
||||
cu_context_->file_context->module, &lines_);
|
||||
line_reader_->ReadProgram(section_start + offset, section_length - offset,
|
||||
cu_context_->file_context->module_, &lines_);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@@ -715,9 +832,9 @@ void DwarfCUToModule::AssignLinesToFunctions() {
|
||||
// complexity from here on out is linear.
|
||||
|
||||
// Put both our functions and lines in order by address.
|
||||
sort(functions->begin(), functions->end(),
|
||||
Module::Function::CompareByAddress);
|
||||
sort(lines_.begin(), lines_.end(), Module::Line::CompareByAddress);
|
||||
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.
|
||||
@@ -852,7 +969,7 @@ void DwarfCUToModule::AssignLinesToFunctions() {
|
||||
// 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);
|
||||
assert(func || line);
|
||||
if (func && line)
|
||||
next_transition = std::min(func->address, line->address);
|
||||
else if (func)
|
||||
@@ -910,12 +1027,14 @@ void DwarfCUToModule::Finish() {
|
||||
|
||||
// Add our functions, which now have source lines assigned to them,
|
||||
// to module_.
|
||||
cu_context_->file_context->module->AddFunctions(functions->begin(),
|
||||
functions->end());
|
||||
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,
|
||||
@@ -926,8 +1045,7 @@ bool DwarfCUToModule::StartCompilationUnit(uint64 offset,
|
||||
return dwarf_version >= 2;
|
||||
}
|
||||
|
||||
bool DwarfCUToModule::StartRootDIE(uint64 offset, enum DwarfTag tag,
|
||||
const AttributeList& attrs) {
|
||||
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;
|
||||
|
101
thirdparty/breakpad/common/dwarf_cu_to_module.h
vendored
101
thirdparty/breakpad/common/dwarf_cu_to_module.h
vendored
@@ -46,10 +46,11 @@
|
||||
#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::AttributeList;
|
||||
using dwarf2reader::DwarfAttribute;
|
||||
using dwarf2reader::DwarfForm;
|
||||
using dwarf2reader::DwarfLanguage;
|
||||
@@ -65,7 +66,6 @@ using dwarf2reader::DwarfTag;
|
||||
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
|
||||
@@ -73,40 +73,75 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||
// 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.
|
||||
struct FileContext {
|
||||
FileContext(const string &filename_arg, Module *module_arg);
|
||||
// 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 char* 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.
|
||||
string filename;
|
||||
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;
|
||||
dwarf2reader::SectionMap section_map_;
|
||||
|
||||
// The Module to which we're contributing definitions.
|
||||
Module *module;
|
||||
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.
|
||||
FilePrivate *file_private;
|
||||
scoped_ptr<FilePrivate> file_private_;
|
||||
};
|
||||
|
||||
// An abstract base class for functors that handle DWARF line data
|
||||
// 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 LineToModuleFunctor {
|
||||
class LineToModuleHandler {
|
||||
public:
|
||||
LineToModuleFunctor() { }
|
||||
virtual ~LineToModuleFunctor() { }
|
||||
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 operator()(const char *program, uint64 length,
|
||||
Module *module, vector<Module::Line> *lines) = 0;
|
||||
virtual void ReadProgram(const char *program, uint64 length,
|
||||
Module *module, vector<Module::Line> *lines) = 0;
|
||||
};
|
||||
|
||||
// The interface DwarfCUToModule uses to report warnings. The member
|
||||
@@ -164,9 +199,17 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||
// link.
|
||||
virtual void UnnamedFunction(uint64 offset);
|
||||
|
||||
// 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:
|
||||
string filename_;
|
||||
uint64 cu_offset_;
|
||||
const string filename_;
|
||||
const uint64 cu_offset_;
|
||||
string cu_name_;
|
||||
bool printed_cu_header_;
|
||||
bool printed_unpaired_header_;
|
||||
@@ -186,7 +229,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||
// unit's line number data. Use REPORTER to report problems with the
|
||||
// data we find.
|
||||
DwarfCUToModule(FileContext *file_context,
|
||||
LineToModuleFunctor *line_reader,
|
||||
LineToModuleHandler *line_reader,
|
||||
WarningReporter *reporter);
|
||||
~DwarfCUToModule();
|
||||
|
||||
@@ -200,8 +243,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||
enum DwarfForm form,
|
||||
const string &data);
|
||||
bool EndAttributes();
|
||||
DIEHandler *FindChildHandler(uint64 offset, enum DwarfTag tag,
|
||||
const AttributeList &attrs);
|
||||
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_.
|
||||
@@ -210,17 +252,14 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||
bool StartCompilationUnit(uint64 offset, uint8 address_size,
|
||||
uint8 offset_size, uint64 cu_length,
|
||||
uint8 dwarf_version);
|
||||
bool StartRootDIE(uint64 offset, enum DwarfTag tag,
|
||||
const AttributeList& attrs);
|
||||
bool StartRootDIE(uint64 offset, enum DwarfTag tag);
|
||||
|
||||
private:
|
||||
|
||||
// Used internally by the handler. Full definitions are in
|
||||
// dwarf_cu_to_module.cc.
|
||||
struct FilePrivate;
|
||||
struct Specification;
|
||||
struct CUContext;
|
||||
struct DIEContext;
|
||||
struct Specification;
|
||||
class GenericDIEHandler;
|
||||
class FuncHandler;
|
||||
class NamedScopeHandler;
|
||||
@@ -230,7 +269,7 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||
|
||||
// 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
|
||||
@@ -249,14 +288,14 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||
// owned by this DwarfCUToModule: the constructor sets them, and the
|
||||
// destructor deletes them.
|
||||
|
||||
// The functor to use to handle line number data.
|
||||
LineToModuleFunctor *line_reader_;
|
||||
// The handler to use to handle line number data.
|
||||
LineToModuleHandler *line_reader_;
|
||||
|
||||
// This compilation unit's context.
|
||||
CUContext *cu_context_;
|
||||
scoped_ptr<CUContext> cu_context_;
|
||||
|
||||
// A context for our children.
|
||||
DIEContext *child_context_;
|
||||
scoped_ptr<DIEContext> child_context_;
|
||||
|
||||
// True if this compilation unit has source line information.
|
||||
bool has_source_line_info_;
|
||||
@@ -271,6 +310,6 @@ class DwarfCUToModule: public dwarf2reader::RootDIEHandler {
|
||||
vector<Module::Line> lines_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_DWARF_CU_TO_MODULE_H__
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -32,38 +32,45 @@
|
||||
// dwarf_line_to_module.cc: Implementation of DwarfLineToModule class.
|
||||
// See dwarf_line_to_module.h for details.
|
||||
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
|
||||
#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 std::string &path) {
|
||||
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 std::string ExpandPath(const std::string &path,
|
||||
const std::string &base) {
|
||||
if (PathIsAbsolute(path))
|
||||
static string ExpandPath(const string &path,
|
||||
const string &base) {
|
||||
if (PathIsAbsolute(path) || base.empty())
|
||||
return path;
|
||||
return base + "/" + path;
|
||||
return base + (HasTrailingSlash(base) ? "" : "/") + path;
|
||||
}
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
void DwarfLineToModule::DefineDir(const std::string &name, uint32 dir_num) {
|
||||
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] = name;
|
||||
directories_[dir_num] = ExpandPath(name, compilation_dir_);
|
||||
}
|
||||
|
||||
void DwarfLineToModule::DefineFile(const std::string &name, int32 file_num,
|
||||
void DwarfLineToModule::DefineFile(const string &name, int32 file_num,
|
||||
uint32 dir_num, uint64 mod_time,
|
||||
uint64 length) {
|
||||
if (file_num == -1)
|
||||
@@ -71,25 +78,26 @@ void DwarfLineToModule::DefineFile(const std::string &name, int32 file_num,
|
||||
else if (file_num > highest_file_number_)
|
||||
highest_file_number_ = file_num;
|
||||
|
||||
std::string full_name;
|
||||
if (dir_num != 0) {
|
||||
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()) {
|
||||
full_name = ExpandPath(name, directory_it->second);
|
||||
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;
|
||||
}
|
||||
full_name = name; // just treat name as relative
|
||||
}
|
||||
} else {
|
||||
// Directory number zero is the compilation directory; we just report
|
||||
// relative paths in that case.
|
||||
full_name = name;
|
||||
}
|
||||
|
||||
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);
|
||||
|
@@ -38,8 +38,11 @@
|
||||
#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 {
|
||||
|
||||
@@ -117,8 +120,10 @@ class DwarfLineToModule: public dwarf2reader::LineInfoHandler {
|
||||
// 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, vector<Module::Line> *lines)
|
||||
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),
|
||||
@@ -127,8 +132,8 @@ class DwarfLineToModule: public dwarf2reader::LineInfoHandler {
|
||||
|
||||
~DwarfLineToModule() { }
|
||||
|
||||
void DefineDir(const std::string &name, uint32 dir_num);
|
||||
void DefineFile(const std::string &name, int32 file_num,
|
||||
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,
|
||||
@@ -136,13 +141,17 @@ class DwarfLineToModule: public dwarf2reader::LineInfoHandler {
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<uint32, std::string> DirectoryTable;
|
||||
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
|
||||
|
@@ -45,7 +45,7 @@ using google_breakpad::Module;
|
||||
TEST(SimpleModule, One) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineFile("file1", 0x30bf0f27, 0, 0, 0);
|
||||
h.AddLine(0x6fd126fbf74f2680LL, 0x63c9a14cf556712bLL, 0x30bf0f27,
|
||||
@@ -54,7 +54,7 @@ TEST(SimpleModule, One) {
|
||||
vector<Module::File *> files;
|
||||
m.GetFiles(&files);
|
||||
EXPECT_EQ(1U, files.size());
|
||||
EXPECT_STREQ("file1", files[0]->name.c_str());
|
||||
EXPECT_STREQ("/file1", files[0]->name.c_str());
|
||||
|
||||
EXPECT_EQ(1U, lines.size());
|
||||
EXPECT_EQ(0x6fd126fbf74f2680ULL, lines[0].address);
|
||||
@@ -66,7 +66,7 @@ TEST(SimpleModule, One) {
|
||||
TEST(SimpleModule, Many) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineDir("directory1", 0x838299ab);
|
||||
h.DefineDir("directory2", 0xf85de023);
|
||||
@@ -89,11 +89,11 @@ TEST(SimpleModule, Many) {
|
||||
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());
|
||||
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());
|
||||
|
||||
@@ -126,7 +126,7 @@ TEST(SimpleModule, Many) {
|
||||
TEST(Filenames, Absolute) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineDir("directory1", 1);
|
||||
h.DefineFile("/absolute", 1, 1, 0, 0);
|
||||
@@ -144,7 +144,7 @@ TEST(Filenames, Absolute) {
|
||||
TEST(Filenames, Relative) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineDir("directory1", 1);
|
||||
h.DefineFile("relative", 1, 1, 0, 0);
|
||||
@@ -154,7 +154,7 @@ TEST(Filenames, Relative) {
|
||||
vector<Module::File *> files;
|
||||
m.GetFiles(&files);
|
||||
ASSERT_EQ(1U, files.size());
|
||||
EXPECT_STREQ("directory1/relative", files[0]->name.c_str());
|
||||
EXPECT_STREQ("/directory1/relative", files[0]->name.c_str());
|
||||
ASSERT_EQ(1U, lines.size());
|
||||
EXPECT_TRUE(lines[0].file == files[0]);
|
||||
}
|
||||
@@ -162,20 +162,20 @@ TEST(Filenames, Relative) {
|
||||
TEST(Filenames, StrangeFile) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &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());
|
||||
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);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineDir("", 1);
|
||||
h.DefineFile("file1", 1, 1, 0, 0);
|
||||
@@ -188,7 +188,7 @@ TEST(Filenames, StrangeDirectory) {
|
||||
TEST(Filenames, StrangeDirectoryAndFile) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineDir("", 1);
|
||||
h.DefineFile("", 1, 1, 0, 0);
|
||||
@@ -198,12 +198,60 @@ TEST(Filenames, StrangeDirectoryAndFile) {
|
||||
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);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineDir("directory0", 0); // should be ignored
|
||||
h.DefineFile("relative", 1, 0, 0, 0);
|
||||
@@ -211,7 +259,7 @@ TEST(ModuleErrors, DirectoryZero) {
|
||||
h.AddLine(1, 1, 1, 0, 0);
|
||||
|
||||
ASSERT_EQ(1U, lines.size());
|
||||
EXPECT_STREQ("relative", lines[0].file->name.c_str());
|
||||
EXPECT_STREQ("/relative", lines[0].file->name.c_str());
|
||||
}
|
||||
|
||||
// We should refuse to add lines with bogus file numbers. We should
|
||||
@@ -219,7 +267,7 @@ TEST(ModuleErrors, DirectoryZero) {
|
||||
TEST(ModuleErrors, BadFileNumber) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineFile("relative", 1, 0, 0, 0);
|
||||
h.AddLine(1, 1, 2, 0, 0); // bad file number
|
||||
@@ -233,7 +281,7 @@ TEST(ModuleErrors, BadFileNumber) {
|
||||
TEST(ModuleErrors, BadDirectoryNumber) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineDir("directory1", 1);
|
||||
h.DefineFile("baddirnumber1", 1, 2, 0, 0); // bad directory number
|
||||
@@ -248,7 +296,7 @@ TEST(ModuleErrors, BadDirectoryNumber) {
|
||||
TEST(ModuleErrors, EmptyLine) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineFile("filename1", 1, 0, 0, 0);
|
||||
h.AddLine(1, 0, 1, 0, 0);
|
||||
@@ -261,7 +309,7 @@ TEST(ModuleErrors, EmptyLine) {
|
||||
TEST(ModuleErrors, BigLine) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineFile("filename1", 1, 0, 0, 0);
|
||||
h.AddLine(0xffffffffffffffffULL, 2, 1, 0, 0);
|
||||
@@ -278,7 +326,7 @@ TEST(ModuleErrors, BigLine) {
|
||||
TEST(Omitted, DroppedThenGood) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineFile("filename1", 1, 0, 0, 0);
|
||||
h.AddLine(0, 10, 1, 83816211, 0); // should be omitted
|
||||
@@ -291,7 +339,7 @@ TEST(Omitted, DroppedThenGood) {
|
||||
TEST(Omitted, GoodThenDropped) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineFile("filename1", 1, 0, 0, 0);
|
||||
h.AddLine(0x9dd6a372, 10, 1, 41454594, 0); // should be recorded
|
||||
@@ -304,7 +352,7 @@ TEST(Omitted, GoodThenDropped) {
|
||||
TEST(Omitted, Mix1) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineFile("filename1", 1, 0, 0, 0);
|
||||
h.AddLine(0x679ed72f, 10, 1, 58932642, 0); // should be recorded
|
||||
@@ -325,7 +373,7 @@ TEST(Omitted, Mix1) {
|
||||
TEST(Omitted, Mix2) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
DwarfLineToModule h(&m, &lines);
|
||||
DwarfLineToModule h(&m, "/", &lines);
|
||||
|
||||
h.DefineFile("filename1", 1, 0, 0, 0);
|
||||
h.AddLine(0, 0xf2, 1, 58802211, 0); // should be omitted
|
||||
|
@@ -27,10 +27,9 @@
|
||||
// (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 "common/http_upload.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
#include "third_party/curl/curl.h"
|
||||
|
||||
namespace {
|
||||
@@ -41,7 +40,7 @@ static size_t WriteCallback(void *ptr, size_t size,
|
||||
if (!userp)
|
||||
return 0;
|
||||
|
||||
std::string *response = reinterpret_cast<std::string *>(userp);
|
||||
string *response = reinterpret_cast<string *>(userp);
|
||||
size_t real_size = size * nmemb;
|
||||
response->append(reinterpret_cast<char *>(ptr), real_size);
|
||||
return real_size;
|
||||
@@ -70,40 +69,13 @@ bool HTTPUpload::SendRequest(const string &url,
|
||||
if (!CheckParameters(parameters))
|
||||
return false;
|
||||
|
||||
void *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)();
|
||||
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);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, kUserAgent);
|
||||
// Set proxy information if necessary.
|
||||
if (!proxy.empty())
|
||||
(*curl_easy_setopt)(curl, CURLOPT_PROXY, proxy.c_str());
|
||||
@@ -116,73 +88,57 @@ bool HTTPUpload::SendRequest(const string &url,
|
||||
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,
|
||||
curl_formadd(&formpost, &lastptr,
|
||||
CURLFORM_COPYNAME, iter->first.c_str(),
|
||||
CURLFORM_COPYCONTENTS, iter->second.c_str(),
|
||||
CURLFORM_END);
|
||||
|
||||
// Add form file.
|
||||
(*curl_formadd)(&formpost, &lastptr,
|
||||
curl_formadd(&formpost, &lastptr,
|
||||
CURLFORM_COPYNAME, file_part_name.c_str(),
|
||||
CURLFORM_FILE, upload_file.c_str(),
|
||||
CURLFORM_END);
|
||||
|
||||
(*curl_easy_setopt)(curl, CURLOPT_HTTPPOST, formpost);
|
||||
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);
|
||||
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,
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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));
|
||||
curl_easy_strerror(err_code));
|
||||
#endif
|
||||
if (error_description != NULL)
|
||||
*error_description = (*curl_easy_strerror)(err_code);
|
||||
*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);
|
||||
curl_easy_cleanup(curl);
|
||||
if (formpost != NULL) {
|
||||
void (*curl_formfree)(struct curl_httppost *);
|
||||
*(void**) (&curl_formfree) = dlsym(curl_lib, "curl_formfree");
|
||||
(*curl_formfree)(formpost);
|
||||
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);
|
||||
curl_slist_free_all(headerlist);
|
||||
}
|
||||
dlclose(curl_lib);
|
||||
|
||||
return err_code == CURLE_OK;
|
||||
}
|
||||
|
@@ -37,9 +37,10 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::string;
|
||||
using std::map;
|
||||
|
||||
class HTTPUpload {
|
8
thirdparty/breakpad/common/language.h
vendored
8
thirdparty/breakpad/common/language.h
vendored
@@ -40,9 +40,9 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace google_breakpad {
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using std::string;
|
||||
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.
|
||||
@@ -50,6 +50,10 @@ using std::string;
|
||||
// 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
|
||||
|
705
thirdparty/breakpad/common/linux/dump_symbols.cc
vendored
705
thirdparty/breakpad/common/linux/dump_symbols.cc
vendored
File diff suppressed because it is too large
Load Diff
34
thirdparty/breakpad/common/linux/dump_symbols.h
vendored
34
thirdparty/breakpad/common/linux/dump_symbols.h
vendored
@@ -37,20 +37,44 @@
|
||||
|
||||
#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_DIR.
|
||||
// If CFI is set to false, then omit the CFI section.
|
||||
bool WriteSymbolFile(const std::string &obj_file,
|
||||
const std::string &debug_dir,
|
||||
bool cfi,
|
||||
// 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);
|
||||
|
||||
// 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__
|
||||
|
@@ -37,27 +37,27 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.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 WriteSymbolFileInternal(uint8_t* obj_file,
|
||||
const std::string &obj_filename,
|
||||
const std::string &debug_dir,
|
||||
bool cfi,
|
||||
std::ostream &sym_stream);
|
||||
}
|
||||
|
||||
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::StringTable;
|
||||
using google_breakpad::synth_elf::SymbolTable;
|
||||
using google_breakpad::test_assembler::kLittleEndian;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
using google_breakpad::WriteSymbolFileInternal;
|
||||
using std::string;
|
||||
using std::stringstream;
|
||||
using std::vector;
|
||||
using ::testing::Test;
|
||||
@@ -67,7 +67,7 @@ class DumpSymbols : public Test {
|
||||
void GetElfContents(ELF& elf) {
|
||||
string contents;
|
||||
ASSERT_TRUE(elf.GetContents(&contents));
|
||||
ASSERT_LT(0, contents.size());
|
||||
ASSERT_LT(0U, contents.size());
|
||||
|
||||
elfdata_v.clear();
|
||||
elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end());
|
||||
@@ -81,17 +81,15 @@ class DumpSymbols : public Test {
|
||||
TEST_F(DumpSymbols, Invalid) {
|
||||
Elf32_Ehdr header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
stringstream s;
|
||||
EXPECT_FALSE(WriteSymbolFileInternal(reinterpret_cast<uint8_t*>(&header),
|
||||
"foo",
|
||||
"",
|
||||
true,
|
||||
s));
|
||||
Module* module;
|
||||
DumpOptions options(ALL_SYMBOL_DATA, true);
|
||||
EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header),
|
||||
"foo",
|
||||
vector<string>(),
|
||||
options,
|
||||
&module));
|
||||
}
|
||||
|
||||
// TODO(ted): Fix the dump_symbols code to deal with cross-word-size
|
||||
// ELF files.
|
||||
#if __ELF_NATIVE_CLASS == 32
|
||||
TEST_F(DumpSymbols, SimplePublic32) {
|
||||
ELF elf(EM_386, ELFCLASS32, kLittleEndian);
|
||||
// Zero out text section for simplicity.
|
||||
@@ -116,19 +114,22 @@ TEST_F(DumpSymbols, SimplePublic32) {
|
||||
elf.Finish();
|
||||
GetElfContents(elf);
|
||||
|
||||
Module* module;
|
||||
DumpOptions options(ALL_SYMBOL_DATA, true);
|
||||
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
|
||||
"foo",
|
||||
vector<string>(),
|
||||
options,
|
||||
&module));
|
||||
|
||||
stringstream s;
|
||||
ASSERT_TRUE(WriteSymbolFileInternal(elfdata,
|
||||
"foo",
|
||||
"",
|
||||
true,
|
||||
s));
|
||||
module->Write(s, ALL_SYMBOL_DATA);
|
||||
EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n"
|
||||
"PUBLIC 1000 0 superfunc\n",
|
||||
s.str());
|
||||
delete module;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if __ELF_NATIVE_CLASS == 64
|
||||
TEST_F(DumpSymbols, SimplePublic64) {
|
||||
ELF elf(EM_X86_64, ELFCLASS64, kLittleEndian);
|
||||
// Zero out text section for simplicity.
|
||||
@@ -153,14 +154,19 @@ TEST_F(DumpSymbols, SimplePublic64) {
|
||||
elf.Finish();
|
||||
GetElfContents(elf);
|
||||
|
||||
Module* module;
|
||||
DumpOptions options(ALL_SYMBOL_DATA, true);
|
||||
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
|
||||
"foo",
|
||||
vector<string>(),
|
||||
options,
|
||||
&module));
|
||||
|
||||
stringstream s;
|
||||
ASSERT_TRUE(WriteSymbolFileInternal(elfdata,
|
||||
"foo",
|
||||
"",
|
||||
true,
|
||||
s));
|
||||
module->Write(s, ALL_SYMBOL_DATA);
|
||||
EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n"
|
||||
"PUBLIC 1000 0 superfunc\n",
|
||||
s.str());
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
21
thirdparty/breakpad/common/linux/eintr_wrapper.h
vendored
21
thirdparty/breakpad/common/linux/eintr_wrapper.h
vendored
@@ -37,11 +37,22 @@
|
||||
//
|
||||
|
||||
#define HANDLE_EINTR(x) ({ \
|
||||
typeof(x) __eintr_result__; \
|
||||
typeof(x) eintr_wrapper_result; \
|
||||
do { \
|
||||
__eintr_result__ = x; \
|
||||
} while (__eintr_result__ == -1 && errno == EINTR); \
|
||||
__eintr_result__;\
|
||||
eintr_wrapper_result = (x); \
|
||||
} while (eintr_wrapper_result == -1 && errno == EINTR); \
|
||||
eintr_wrapper_result; \
|
||||
})
|
||||
|
||||
#endif // ifndef COMMON_LINUX_EINTR_WRAPPER_H_
|
||||
#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_
|
||||
|
@@ -34,15 +34,10 @@
|
||||
#define COMMON_LINUX_ELF_CORE_DUMP_H_
|
||||
|
||||
#include <elf.h>
|
||||
#if !defined(__ANDROID__)
|
||||
#include <link.h>
|
||||
#endif
|
||||
#include <stddef.h>
|
||||
|
||||
#include "common/memory_range.h"
|
||||
#if defined(__ANDROID__)
|
||||
#include "common/linux/android_link.h"
|
||||
#endif
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#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;
|
||||
@@ -47,13 +48,12 @@ using google_breakpad::MemoryMappedFile;
|
||||
using google_breakpad::MemoryRange;
|
||||
using google_breakpad::WriteFile;
|
||||
using std::set;
|
||||
using std::string;
|
||||
|
||||
TEST(ElfCoreDumpTest, DefaultConstructor) {
|
||||
ElfCoreDump core;
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
EXPECT_EQ(NULL, core.GetHeader());
|
||||
EXPECT_EQ(0, core.GetProgramHeaderCount());
|
||||
EXPECT_EQ(0U, core.GetProgramHeaderCount());
|
||||
EXPECT_EQ(NULL, core.GetProgramHeader(0));
|
||||
EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD));
|
||||
EXPECT_FALSE(core.GetFirstNote().IsValid());
|
||||
@@ -74,7 +74,7 @@ TEST(ElfCoreDumpTest, TestElfHeader) {
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
EXPECT_EQ(NULL, core.GetHeader());
|
||||
EXPECT_EQ(0, core.GetProgramHeaderCount());
|
||||
EXPECT_EQ(0U, core.GetProgramHeaderCount());
|
||||
EXPECT_EQ(NULL, core.GetProgramHeader(0));
|
||||
EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD));
|
||||
EXPECT_FALSE(core.GetFirstNote().IsValid());
|
||||
@@ -182,8 +182,12 @@ TEST(ElfCoreDumpTest, ValidCoreFile) {
|
||||
|
||||
size_t num_nt_prpsinfo = 0;
|
||||
size_t num_nt_prstatus = 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()) {
|
||||
@@ -211,7 +215,7 @@ TEST(ElfCoreDumpTest, ValidCoreFile) {
|
||||
++num_nt_prstatus;
|
||||
break;
|
||||
}
|
||||
#if defined(__i386) || defined(__x86_64)
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
case NT_FPREGSET: {
|
||||
EXPECT_TRUE(description.data() != NULL);
|
||||
EXPECT_EQ(sizeof(user_fpregs_struct), description.length());
|
||||
@@ -219,7 +223,7 @@ TEST(ElfCoreDumpTest, ValidCoreFile) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(__i386)
|
||||
#if defined(__i386__)
|
||||
case NT_PRXFPREG: {
|
||||
EXPECT_TRUE(description.data() != NULL);
|
||||
EXPECT_EQ(sizeof(user_fpxregs_struct), description.length());
|
||||
@@ -234,12 +238,12 @@ TEST(ElfCoreDumpTest, ValidCoreFile) {
|
||||
}
|
||||
|
||||
EXPECT_TRUE(expected_thread_ids == actual_thread_ids);
|
||||
EXPECT_EQ(1, num_nt_prpsinfo);
|
||||
EXPECT_EQ(1U, num_nt_prpsinfo);
|
||||
EXPECT_EQ(kNumOfThreads, num_nt_prstatus);
|
||||
#if defined(__i386) || defined(__x86_64)
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
EXPECT_EQ(kNumOfThreads, num_nt_fpregset);
|
||||
#endif
|
||||
#if defined(__i386)
|
||||
#if defined(__i386__)
|
||||
EXPECT_EQ(kNumOfThreads, num_nt_prxfpreg);
|
||||
#endif
|
||||
}
|
||||
|
46
thirdparty/breakpad/common/linux/elf_gnu_compat.h
vendored
Normal file
46
thirdparty/breakpad/common/linux/elf_gnu_compat.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// -*- 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_
|
@@ -42,6 +42,7 @@
|
||||
#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;
|
||||
@@ -52,7 +53,6 @@ using google_breakpad::test_assembler::Label;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
using ::testing::Test;
|
||||
using ::testing::TestWithParam;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
class ELFSymbolsToModuleTestFixture {
|
||||
|
74
thirdparty/breakpad/common/linux/elfutils-inl.h
vendored
Normal file
74
thirdparty/breakpad/common/linux/elfutils-inl.h
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright (c) 2012, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef COMMON_LINUX_ELFUTILS_INL_H__
|
||||
#define COMMON_LINUX_ELFUTILS_INL_H__
|
||||
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "elfutils.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
template<typename ElfClass, typename T>
|
||||
const T* GetOffset(const typename ElfClass::Ehdr* elf_header,
|
||||
typename ElfClass::Off offset) {
|
||||
return reinterpret_cast<const T*>(reinterpret_cast<uintptr_t>(elf_header) +
|
||||
offset);
|
||||
}
|
||||
|
||||
template<typename ElfClass>
|
||||
const typename ElfClass::Shdr* FindElfSectionByName(
|
||||
const char* name,
|
||||
typename ElfClass::Word section_type,
|
||||
const typename ElfClass::Shdr* sections,
|
||||
const char* section_names,
|
||||
const char* names_end,
|
||||
int nsection) {
|
||||
assert(name != NULL);
|
||||
assert(sections != NULL);
|
||||
assert(nsection > 0);
|
||||
|
||||
int name_len = my_strlen(name);
|
||||
if (name_len == 0)
|
||||
return NULL;
|
||||
|
||||
for (int i = 0; i < nsection; ++i) {
|
||||
const char* section_name = section_names + sections[i].sh_name;
|
||||
if (sections[i].sh_type == section_type &&
|
||||
names_end - section_name >= name_len + 1 &&
|
||||
my_strcmp(name, section_name) == 0) {
|
||||
return sections + i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_ELFUTILS_INL_H__
|
194
thirdparty/breakpad/common/linux/elfutils.cc
vendored
Normal file
194
thirdparty/breakpad/common/linux/elfutils.cc
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
// 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,
|
||||
int *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,
|
||||
int *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,
|
||||
int *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,
|
||||
int *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
|
118
thirdparty/breakpad/common/linux/elfutils.h
vendored
Normal file
118
thirdparty/breakpad/common/linux/elfutils.h
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
// 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_Word Word;
|
||||
static const int kClass = ELFCLASS32;
|
||||
static const size_t kAddrSize = sizeof(Elf32_Addr);
|
||||
};
|
||||
|
||||
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_Word Word;
|
||||
static const int kClass = ELFCLASS64;
|
||||
static const size_t kAddrSize = sizeof(Elf64_Addr);
|
||||
};
|
||||
|
||||
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,
|
||||
int *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,
|
||||
int *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__
|
145
thirdparty/breakpad/common/linux/file_id.cc
vendored
145
thirdparty/breakpad/common/linux/file_id.cc
vendored
@@ -36,144 +36,50 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#if defined(__ANDROID__)
|
||||
#include <linux/elf.h>
|
||||
#include "client/linux/android_link.h"
|
||||
#else
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#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 "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
#ifndef NT_GNU_BUILD_ID
|
||||
#define NT_GNU_BUILD_ID 3
|
||||
#endif
|
||||
|
||||
FileID::FileID(const char* path) {
|
||||
strncpy(path_, path, sizeof(path_));
|
||||
}
|
||||
|
||||
struct ElfClass32 {
|
||||
typedef Elf32_Ehdr Ehdr;
|
||||
typedef Elf32_Nhdr Nhdr;
|
||||
typedef Elf32_Shdr Shdr;
|
||||
static const int kClass = ELFCLASS32;
|
||||
};
|
||||
// ELF note name and desc are 32-bits word padded.
|
||||
#define NOTE_PADDING(a) ((a + 3) & ~3)
|
||||
|
||||
struct ElfClass64 {
|
||||
typedef Elf64_Ehdr Ehdr;
|
||||
typedef Elf64_Nhdr Nhdr;
|
||||
typedef Elf64_Shdr Shdr;
|
||||
static const int kClass = ELFCLASS64;
|
||||
};
|
||||
|
||||
// These six functions are also used inside the crashed process, so be safe
|
||||
// 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 void FindElfClassSection(const char *elf_base,
|
||||
const char *section_name,
|
||||
uint32_t section_type,
|
||||
const void **section_start,
|
||||
int *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);
|
||||
|
||||
int name_len = my_strlen(section_name);
|
||||
|
||||
const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base);
|
||||
assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass);
|
||||
|
||||
const Shdr* sections =
|
||||
reinterpret_cast<const Shdr*>(elf_base + elf_header->e_shoff);
|
||||
const Shdr* string_section = sections + elf_header->e_shstrndx;
|
||||
|
||||
const Shdr* section = NULL;
|
||||
for (int i = 0; i < elf_header->e_shnum; ++i) {
|
||||
if (sections[i].sh_type == section_type) {
|
||||
const char* current_section_name = (char*)(elf_base +
|
||||
string_section->sh_offset +
|
||||
sections[i].sh_name);
|
||||
if (!my_strncmp(current_section_name, section_name, name_len)) {
|
||||
section = §ions[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (section != NULL && section->sh_size > 0) {
|
||||
*section_start = elf_base + section->sh_offset;
|
||||
*section_size = section->sh_size;
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
static bool FindElfSection(const void *elf_mapped_base,
|
||||
const char *section_name,
|
||||
uint32_t section_type,
|
||||
const void **section_start,
|
||||
int *section_size,
|
||||
int *elfclass) {
|
||||
assert(elf_mapped_base);
|
||||
assert(section_start);
|
||||
assert(section_size);
|
||||
|
||||
*section_start = NULL;
|
||||
*section_size = 0;
|
||||
|
||||
const char* elf_base =
|
||||
static_cast<const char*>(elf_mapped_base);
|
||||
const ElfW(Ehdr)* elf_header =
|
||||
reinterpret_cast<const ElfW(Ehdr)*>(elf_base);
|
||||
if (my_strncmp(elf_base, ELFMAG, SELFMAG) != 0)
|
||||
return false;
|
||||
|
||||
if (elfclass) {
|
||||
*elfclass = elf_header->e_ident[EI_CLASS];
|
||||
}
|
||||
|
||||
if (elf_header->e_ident[EI_CLASS] == ELFCLASS32) {
|
||||
FindElfClassSection<ElfClass32>(elf_base, section_name, section_type,
|
||||
section_start, section_size);
|
||||
return *section_start != NULL;
|
||||
} else if (elf_header->e_ident[EI_CLASS] == ELFCLASS64) {
|
||||
FindElfClassSection<ElfClass64>(elf_base, section_name, section_type,
|
||||
section_start, section_size);
|
||||
return *section_start != NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename ElfClass>
|
||||
static bool ElfClassBuildIDNoteIdentifier(const void *section,
|
||||
static bool ElfClassBuildIDNoteIdentifier(const void *section, int length,
|
||||
uint8_t identifier[kMDGUIDSize]) {
|
||||
typedef typename ElfClass::Nhdr Nhdr;
|
||||
|
||||
const void* section_end = reinterpret_cast<const char*>(section) + length;
|
||||
const Nhdr* note_header = reinterpret_cast<const Nhdr*>(section);
|
||||
if (note_header->n_type != NT_GNU_BUILD_ID ||
|
||||
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 char* build_id = reinterpret_cast<const char*>(section) +
|
||||
sizeof(Nhdr) + note_header->n_namesz;
|
||||
const char* build_id = reinterpret_cast<const char*>(note_header) +
|
||||
sizeof(Nhdr) + NOTE_PADDING(note_header->n_namesz);
|
||||
// Copy as many bits of the build ID as will fit
|
||||
// into the GUID space.
|
||||
my_memset(identifier, 0, kMDGUIDSize);
|
||||
@@ -189,16 +95,21 @@ static bool FindElfBuildIDNote(const void *elf_mapped_base,
|
||||
uint8_t identifier[kMDGUIDSize]) {
|
||||
void* note_section;
|
||||
int note_size, elfclass;
|
||||
if (!FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE,
|
||||
(const void**)¬e_section, ¬e_size, &elfclass) ||
|
||||
note_size == 0) {
|
||||
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, identifier);
|
||||
return ElfClassBuildIDNoteIdentifier<ElfClass32>(note_section, note_size,
|
||||
identifier);
|
||||
} else if (elfclass == ELFCLASS64) {
|
||||
return ElfClassBuildIDNoteIdentifier<ElfClass64>(note_section, identifier);
|
||||
return ElfClassBuildIDNoteIdentifier<ElfClass64>(note_section, note_size,
|
||||
identifier);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
183
thirdparty/breakpad/common/linux/file_id_unittest.cc
vendored
183
thirdparty/breakpad/common/linux/file_id_unittest.cc
vendored
@@ -32,19 +32,27 @@
|
||||
#include <elf.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#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::ElfClass32;
|
||||
using google_breakpad::ElfClass64;
|
||||
using google_breakpad::SafeReadLink;
|
||||
using google_breakpad::synth_elf::BuildIDNote;
|
||||
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 ::testing::Types;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -58,6 +66,9 @@ void PopulateSection(Section* section, int size, int prime_number) {
|
||||
|
||||
} // 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,
|
||||
@@ -67,12 +78,14 @@ TEST(FileIDStripTest, StripSelf) {
|
||||
|
||||
// copy our binary to a temp file, and strip it
|
||||
AutoTempDir temp_dir;
|
||||
std::string templ = temp_dir.path() + "/file-id-unittest";
|
||||
string templ = temp_dir.path() + "/file-id-unittest";
|
||||
char cmdline[4096];
|
||||
sprintf(cmdline, "cp \"%s\" \"%s\"", exe_name, templ.c_str());
|
||||
ASSERT_EQ(system(cmdline), 0);
|
||||
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(system(cmdline), 0);
|
||||
ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline;
|
||||
|
||||
uint8_t identifier1[sizeof(MDGUID)];
|
||||
uint8_t identifier2[sizeof(MDGUID)];
|
||||
@@ -88,13 +101,15 @@ TEST(FileIDStripTest, StripSelf) {
|
||||
37);
|
||||
EXPECT_STREQ(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(0, contents.size());
|
||||
ASSERT_LT(0U, contents.size());
|
||||
|
||||
elfdata_v.clear();
|
||||
elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end());
|
||||
@@ -105,48 +120,35 @@ public:
|
||||
uint8_t* elfdata;
|
||||
};
|
||||
|
||||
TEST_F(FileIDTest, ElfClass) {
|
||||
typedef Types<ElfClass32, ElfClass64> ElfClasses;
|
||||
|
||||
TYPED_TEST_CASE(FileIDTest, ElfClasses);
|
||||
|
||||
TYPED_TEST(FileIDTest, ElfClass) {
|
||||
uint8_t identifier[sizeof(MDGUID)];
|
||||
const char expected_identifier_string[] =
|
||||
"80808080-8080-0000-0000-008080808080";
|
||||
char identifier_string[sizeof(expected_identifier_string)];
|
||||
const size_t kTextSectionSize = 128;
|
||||
|
||||
ELF elf32(EM_386, ELFCLASS32, kLittleEndian);
|
||||
Section text32(kLittleEndian);
|
||||
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section text(kLittleEndian);
|
||||
for (size_t i = 0; i < kTextSectionSize; ++i) {
|
||||
text32.D8(i * 3);
|
||||
text.D8(i * 3);
|
||||
}
|
||||
elf32.AddSection(".text", text32, SHT_PROGBITS);
|
||||
elf32.Finish();
|
||||
GetElfContents(elf32);
|
||||
elf.AddSection(".text", text, SHT_PROGBITS);
|
||||
elf.Finish();
|
||||
this->GetElfContents(elf);
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier));
|
||||
|
||||
FileID::ConvertIdentifierToString(identifier, identifier_string,
|
||||
sizeof(identifier_string));
|
||||
EXPECT_STREQ(expected_identifier_string, identifier_string);
|
||||
|
||||
memset(identifier, 0, sizeof(identifier));
|
||||
memset(identifier_string, 0, sizeof(identifier_string));
|
||||
|
||||
ELF elf64(EM_X86_64, ELFCLASS64, kLittleEndian);
|
||||
Section text64(kLittleEndian);
|
||||
for (size_t i = 0; i < kTextSectionSize; ++i) {
|
||||
text64.D8(i * 3);
|
||||
}
|
||||
elf64.AddSection(".text", text64, SHT_PROGBITS);
|
||||
elf64.Finish();
|
||||
GetElfContents(elf64);
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier));
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier));
|
||||
|
||||
FileID::ConvertIdentifierToString(identifier, identifier_string,
|
||||
sizeof(identifier_string));
|
||||
EXPECT_STREQ(expected_identifier_string, identifier_string);
|
||||
}
|
||||
|
||||
TEST_F(FileIDTest, BuildID) {
|
||||
TYPED_TEST(FileIDTest, BuildID) {
|
||||
const uint8_t kExpectedIdentifier[sizeof(MDGUID)] =
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
|
||||
@@ -159,35 +161,54 @@ TEST_F(FileIDTest, BuildID) {
|
||||
uint8_t identifier[sizeof(MDGUID)];
|
||||
char identifier_string[sizeof(expected_identifier_string)];
|
||||
|
||||
ELF elf32(EM_386, ELFCLASS32, kLittleEndian);
|
||||
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section text(kLittleEndian);
|
||||
text.Append(4096, 0);
|
||||
elf32.AddSection(".text", text, SHT_PROGBITS);
|
||||
BuildIDNote::AppendSection(elf32,
|
||||
kExpectedIdentifier,
|
||||
sizeof(kExpectedIdentifier));
|
||||
elf32.Finish();
|
||||
GetElfContents(elf32);
|
||||
elf.AddSection(".text", text, SHT_PROGBITS);
|
||||
Notes notes(kLittleEndian);
|
||||
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifier,
|
||||
sizeof(kExpectedIdentifier));
|
||||
elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
|
||||
elf.Finish();
|
||||
this->GetElfContents(elf);
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier));
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier));
|
||||
|
||||
FileID::ConvertIdentifierToString(identifier, identifier_string,
|
||||
sizeof(identifier_string));
|
||||
EXPECT_STREQ(expected_identifier_string, identifier_string);
|
||||
}
|
||||
|
||||
memset(identifier, 0, sizeof(identifier));
|
||||
memset(identifier_string, 0, sizeof(identifier_string));
|
||||
TYPED_TEST(FileIDTest, BuildIDPH) {
|
||||
const uint8_t kExpectedIdentifier[sizeof(MDGUID)] =
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
|
||||
char expected_identifier_string[] =
|
||||
"00000000-0000-0000-0000-000000000000";
|
||||
FileID::ConvertIdentifierToString(kExpectedIdentifier,
|
||||
expected_identifier_string,
|
||||
sizeof(expected_identifier_string));
|
||||
|
||||
ELF elf64(EM_X86_64, ELFCLASS64, kLittleEndian);
|
||||
// Re-use empty text section from previous test
|
||||
elf64.AddSection(".text", text, SHT_PROGBITS);
|
||||
BuildIDNote::AppendSection(elf64,
|
||||
kExpectedIdentifier,
|
||||
sizeof(kExpectedIdentifier));
|
||||
elf64.Finish();
|
||||
GetElfContents(elf64);
|
||||
uint8_t identifier[sizeof(MDGUID)];
|
||||
char identifier_string[sizeof(expected_identifier_string)];
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier));
|
||||
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", kExpectedIdentifier,
|
||||
sizeof(kExpectedIdentifier));
|
||||
int note_idx = elf.AddSection(".note", notes, SHT_NOTE);
|
||||
elf.AddSegment(note_idx, note_idx, PT_NOTE);
|
||||
elf.Finish();
|
||||
this->GetElfContents(elf);
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier));
|
||||
|
||||
FileID::ConvertIdentifierToString(identifier, identifier_string,
|
||||
sizeof(identifier_string));
|
||||
@@ -196,7 +217,7 @@ TEST_F(FileIDTest, BuildID) {
|
||||
|
||||
// Test to make sure two files with different text sections produce
|
||||
// different hashes when not using a build id.
|
||||
TEST_F(FileIDTest, UniqueHashes32) {
|
||||
TYPED_TEST(FileIDTest, UniqueHashes) {
|
||||
char identifier_string_1[] =
|
||||
"00000000-0000-0000-0000-000000000000";
|
||||
char identifier_string_2[] =
|
||||
@@ -205,7 +226,7 @@ TEST_F(FileIDTest, UniqueHashes32) {
|
||||
uint8_t identifier_2[sizeof(MDGUID)];
|
||||
|
||||
{
|
||||
ELF elf1(EM_386, ELFCLASS32, kLittleEndian);
|
||||
ELF elf1(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section foo_1(kLittleEndian);
|
||||
PopulateSection(&foo_1, 32, 5);
|
||||
elf1.AddSection(".foo", foo_1, SHT_PROGBITS);
|
||||
@@ -213,15 +234,16 @@ TEST_F(FileIDTest, UniqueHashes32) {
|
||||
PopulateSection(&text_1, 4096, 17);
|
||||
elf1.AddSection(".text", text_1, SHT_PROGBITS);
|
||||
elf1.Finish();
|
||||
GetElfContents(elf1);
|
||||
this->GetElfContents(elf1);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier_1));
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier_1));
|
||||
FileID::ConvertIdentifierToString(identifier_1, identifier_string_1,
|
||||
sizeof(identifier_string_1));
|
||||
|
||||
{
|
||||
ELF elf2(EM_386, ELFCLASS32, kLittleEndian);
|
||||
ELF elf2(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section text_2(kLittleEndian);
|
||||
Section foo_2(kLittleEndian);
|
||||
PopulateSection(&foo_2, 32, 5);
|
||||
@@ -229,54 +251,11 @@ TEST_F(FileIDTest, UniqueHashes32) {
|
||||
PopulateSection(&text_2, 4096, 31);
|
||||
elf2.AddSection(".text", text_2, SHT_PROGBITS);
|
||||
elf2.Finish();
|
||||
GetElfContents(elf2);
|
||||
this->GetElfContents(elf2);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier_2));
|
||||
FileID::ConvertIdentifierToString(identifier_2, identifier_string_2,
|
||||
sizeof(identifier_string_2));
|
||||
|
||||
EXPECT_STRNE(identifier_string_1, identifier_string_2);
|
||||
}
|
||||
|
||||
// Same as UniqueHashes32, for x86-64.
|
||||
TEST_F(FileIDTest, UniqueHashes64) {
|
||||
char identifier_string_1[] =
|
||||
"00000000-0000-0000-0000-000000000000";
|
||||
char identifier_string_2[] =
|
||||
"00000000-0000-0000-0000-000000000000";
|
||||
uint8_t identifier_1[sizeof(MDGUID)];
|
||||
uint8_t identifier_2[sizeof(MDGUID)];
|
||||
|
||||
{
|
||||
ELF elf1(EM_X86_64, ELFCLASS64, 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();
|
||||
GetElfContents(elf1);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier_1));
|
||||
FileID::ConvertIdentifierToString(identifier_1, identifier_string_1,
|
||||
sizeof(identifier_string_1));
|
||||
|
||||
{
|
||||
ELF elf2(EM_X86_64, ELFCLASS64, 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();
|
||||
GetElfContents(elf2);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(elfdata, identifier_2));
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier_2));
|
||||
FileID::ConvertIdentifierToString(identifier_2, identifier_string_2,
|
||||
sizeof(identifier_string_2));
|
||||
|
||||
|
@@ -37,21 +37,21 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using std::string;
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
GoogleCrashdumpUploader::GoogleCrashdumpUploader(const std::string& product,
|
||||
const std::string& version,
|
||||
const std::string& guid,
|
||||
const std::string& ptime,
|
||||
const std::string& ctime,
|
||||
const std::string& email,
|
||||
const std::string& comments,
|
||||
const std::string& minidump_pathname,
|
||||
const std::string& crash_server,
|
||||
const std::string& proxy_host,
|
||||
const std::string& proxy_userpassword) {
|
||||
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,
|
||||
@@ -67,17 +67,17 @@ GoogleCrashdumpUploader::GoogleCrashdumpUploader(const std::string& product,
|
||||
http_layer);
|
||||
}
|
||||
|
||||
GoogleCrashdumpUploader::GoogleCrashdumpUploader(const std::string& product,
|
||||
const std::string& version,
|
||||
const std::string& guid,
|
||||
const std::string& ptime,
|
||||
const std::string& ctime,
|
||||
const std::string& email,
|
||||
const std::string& comments,
|
||||
const std::string& minidump_pathname,
|
||||
const std::string& crash_server,
|
||||
const std::string& proxy_host,
|
||||
const std::string& proxy_userpassword,
|
||||
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,
|
||||
@@ -93,17 +93,17 @@ GoogleCrashdumpUploader::GoogleCrashdumpUploader(const std::string& product,
|
||||
http_layer);
|
||||
}
|
||||
|
||||
void GoogleCrashdumpUploader::Init(const std::string& product,
|
||||
const std::string& version,
|
||||
const std::string& guid,
|
||||
const std::string& ptime,
|
||||
const std::string& ctime,
|
||||
const std::string& email,
|
||||
const std::string& comments,
|
||||
const std::string& minidump_pathname,
|
||||
const std::string& crash_server,
|
||||
const std::string& proxy_host,
|
||||
const std::string& proxy_userpassword,
|
||||
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;
|
||||
@@ -137,7 +137,7 @@ void GoogleCrashdumpUploader::Init(const std::string& product,
|
||||
}
|
||||
|
||||
bool GoogleCrashdumpUploader::CheckRequiredParametersArePresent() {
|
||||
std::string error_text;
|
||||
string error_text;
|
||||
if (product_.empty()) {
|
||||
error_text.append("\nProduct name must be specified.");
|
||||
}
|
||||
|
@@ -31,48 +31,50 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class LibcurlWrapper;
|
||||
|
||||
class GoogleCrashdumpUploader {
|
||||
public:
|
||||
GoogleCrashdumpUploader(const std::string& product,
|
||||
const std::string& version,
|
||||
const std::string& guid,
|
||||
const std::string& ptime,
|
||||
const std::string& ctime,
|
||||
const std::string& email,
|
||||
const std::string& comments,
|
||||
const std::string& minidump_pathname,
|
||||
const std::string& crash_server,
|
||||
const std::string& proxy_host,
|
||||
const std::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);
|
||||
|
||||
GoogleCrashdumpUploader(const std::string& product,
|
||||
const std::string& version,
|
||||
const std::string& guid,
|
||||
const std::string& ptime,
|
||||
const std::string& ctime,
|
||||
const std::string& email,
|
||||
const std::string& comments,
|
||||
const std::string& minidump_pathname,
|
||||
const std::string& crash_server,
|
||||
const std::string& proxy_host,
|
||||
const std::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 std::string& product,
|
||||
const std::string& version,
|
||||
const std::string& guid,
|
||||
const std::string& ptime,
|
||||
const std::string& ctime,
|
||||
const std::string& email,
|
||||
const std::string& comments,
|
||||
const std::string& minidump_pathname,
|
||||
const std::string& crash_server,
|
||||
const std::string& proxy_host,
|
||||
const std::string& proxy_userpassword,
|
||||
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();
|
||||
|
||||
@@ -80,19 +82,19 @@ class GoogleCrashdumpUploader {
|
||||
bool CheckRequiredParametersArePresent();
|
||||
|
||||
LibcurlWrapper* http_layer_;
|
||||
std::string product_;
|
||||
std::string version_;
|
||||
std::string guid_;
|
||||
std::string ptime_;
|
||||
std::string ctime_;
|
||||
std::string email_;
|
||||
std::string comments_;
|
||||
std::string minidump_pathname_;
|
||||
string product_;
|
||||
string version_;
|
||||
string guid_;
|
||||
string ptime_;
|
||||
string ctime_;
|
||||
string email_;
|
||||
string comments_;
|
||||
string minidump_pathname_;
|
||||
|
||||
std::string crash_server_;
|
||||
std::string proxy_host_;
|
||||
std::string proxy_userpassword_;
|
||||
string crash_server_;
|
||||
string proxy_host_;
|
||||
string proxy_userpassword_;
|
||||
|
||||
std::map<std::string, std::string> parameters_;
|
||||
std::map<string, string> parameters_;
|
||||
};
|
||||
}
|
||||
|
@@ -29,9 +29,12 @@
|
||||
|
||||
// Unit test for crash dump uploader.
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/linux/google_crashdump_uploader.h"
|
||||
#include "common/linux/libcurl_wrapper.h"
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
@@ -41,14 +44,14 @@ using ::testing::_;
|
||||
class MockLibcurlWrapper : public LibcurlWrapper {
|
||||
public:
|
||||
MOCK_METHOD0(Init, bool());
|
||||
MOCK_METHOD2(SetProxy, bool(const std::string& proxy_host,
|
||||
const std::string& proxy_userpwd));
|
||||
MOCK_METHOD2(AddFile, bool(const std::string& upload_file_path,
|
||||
const std::string& basename));
|
||||
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_METHOD3(SendRequest,
|
||||
bool(const std::string& url,
|
||||
const std::map<std::string, std::string>& parameters,
|
||||
std::string* server_response));
|
||||
bool(const string& url,
|
||||
const std::map<string, string>& parameters,
|
||||
string* server_response));
|
||||
};
|
||||
|
||||
class GoogleCrashdumpUploaderTest : public ::testing::Test {
|
||||
|
16
thirdparty/breakpad/common/linux/guid_creator.cc
vendored
16
thirdparty/breakpad/common/linux/guid_creator.cc
vendored
@@ -46,14 +46,14 @@
|
||||
//
|
||||
class GUIDGenerator {
|
||||
public:
|
||||
static u_int32_t BytesToUInt32(const u_int8_t bytes[]) {
|
||||
return ((u_int32_t) bytes[0]
|
||||
| ((u_int32_t) bytes[1] << 8)
|
||||
| ((u_int32_t) bytes[2] << 16)
|
||||
| ((u_int32_t) bytes[3] << 24));
|
||||
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(u_int8_t bytes[], u_int32_t n) {
|
||||
static void UInt32ToBytes(uint8_t bytes[], uint32_t n) {
|
||||
bytes[0] = n & 0xff;
|
||||
bytes[1] = (n >> 8) & 0xff;
|
||||
bytes[2] = (n >> 16) & 0xff;
|
||||
@@ -63,8 +63,8 @@ class GUIDGenerator {
|
||||
static bool CreateGUID(GUID *guid) {
|
||||
InitOnce();
|
||||
guid->data1 = random();
|
||||
guid->data2 = (u_int16_t)(random());
|
||||
guid->data3 = (u_int16_t)(random());
|
||||
guid->data2 = (uint16_t)(random());
|
||||
guid->data3 = (uint16_t)(random());
|
||||
UInt32ToBytes(&guid->data4[0], random());
|
||||
UInt32ToBytes(&guid->data4[4], random());
|
||||
return true;
|
||||
|
40
thirdparty/breakpad/common/linux/ignore_ret.h
vendored
Normal file
40
thirdparty/breakpad/common/linux/ignore_ret.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2012 Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef COMMON_LINUX_IGNORE_RET_H_
|
||||
#define COMMON_LINUX_IGNORE_RET_H_
|
||||
|
||||
// Some compilers are prone to warn about unused return values. In cases where
|
||||
// either a) the call cannot fail, or b) there is nothing that can be done when
|
||||
// the call fails, IGNORE_RET() can be used to mark the return code as ignored.
|
||||
// This avoids spurious compiler warnings.
|
||||
|
||||
#define IGNORE_RET(x) do { if (x); } while (0)
|
||||
|
||||
#endif // COMMON_LINUX_IGNORE_RET_H_
|
@@ -33,8 +33,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "common/linux/libcurl_wrapper.h"
|
||||
|
||||
using std::string;
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
LibcurlWrapper::LibcurlWrapper()
|
||||
@@ -58,8 +57,8 @@ LibcurlWrapper::LibcurlWrapper()
|
||||
return;
|
||||
}
|
||||
|
||||
bool LibcurlWrapper::SetProxy(const std::string& proxy_host,
|
||||
const std::string& proxy_userpwd) {
|
||||
bool LibcurlWrapper::SetProxy(const string& proxy_host,
|
||||
const string& proxy_userpwd) {
|
||||
if (!init_ok_) {
|
||||
return false;
|
||||
}
|
||||
@@ -80,8 +79,8 @@ bool LibcurlWrapper::SetProxy(const std::string& proxy_host,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibcurlWrapper::AddFile(const std::string& upload_file_path,
|
||||
const std::string& basename) {
|
||||
bool LibcurlWrapper::AddFile(const string& upload_file_path,
|
||||
const string& basename) {
|
||||
if (!init_ok_) {
|
||||
return false;
|
||||
}
|
||||
@@ -101,17 +100,17 @@ static size_t WriteCallback(void *ptr, size_t size,
|
||||
if (!userp)
|
||||
return 0;
|
||||
|
||||
std::string *response = reinterpret_cast<std::string *>(userp);
|
||||
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 std::string& url,
|
||||
const std::map<std::string, std::string>& parameters,
|
||||
std::string* server_response) {
|
||||
bool LibcurlWrapper::SendRequest(const string& url,
|
||||
const std::map<string, string>& parameters,
|
||||
string* server_response) {
|
||||
(*easy_setopt_)(curl_, CURLOPT_URL, url.c_str());
|
||||
std::map<std::string, std::string>::const_iterator iter = parameters.begin();
|
||||
std::map<string, string>::const_iterator iter = parameters.begin();
|
||||
for (; iter != parameters.end(); ++iter)
|
||||
(*formadd_)(&formpost_, &lastptr_,
|
||||
CURLFORM_COPYNAME, iter->first.c_str(),
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
#include "third_party/curl/curl.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
@@ -40,13 +41,13 @@ class LibcurlWrapper {
|
||||
public:
|
||||
LibcurlWrapper();
|
||||
virtual bool Init();
|
||||
virtual bool SetProxy(const std::string& proxy_host,
|
||||
const std::string& proxy_userpwd);
|
||||
virtual bool AddFile(const std::string& upload_file_path,
|
||||
const std::string& basename);
|
||||
virtual bool SendRequest(const std::string& url,
|
||||
const std::map<std::string, std::string>& parameters,
|
||||
std::string* server_response);
|
||||
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,
|
||||
string* server_response);
|
||||
private:
|
||||
// This function initializes class state corresponding to function
|
||||
// pointers into the CURL library.
|
||||
@@ -55,7 +56,7 @@ class LibcurlWrapper {
|
||||
bool init_ok_; // Whether init succeeded
|
||||
void* curl_lib_; // Pointer to result of dlopen() on
|
||||
// curl library
|
||||
std::string last_curl_error_; // The text of the last error when
|
||||
string last_curl_error_; // The text of the last error when
|
||||
// dealing
|
||||
// with CURL.
|
||||
|
||||
|
237
thirdparty/breakpad/common/linux/linux_libc_support.cc
vendored
Normal file
237
thirdparty/breakpad/common/linux/linux_libc_support.cc
vendored
Normal file
@@ -0,0 +1,237 @@
|
||||
// Copyright (c) 2012, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// This source file provides replacements for libc functions that we need. If
|
||||
// we call the libc functions directly we risk crashing in the dynamic linker
|
||||
// as it tries to resolve uncached PLT entries.
|
||||
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
size_t my_strlen(const char* s) {
|
||||
size_t len = 0;
|
||||
while (*s++) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
int my_strcmp(const char* a, const char* b) {
|
||||
for (;;) {
|
||||
if (*a < *b)
|
||||
return -1;
|
||||
else if (*a > *b)
|
||||
return 1;
|
||||
else if (*a == 0)
|
||||
return 0;
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
}
|
||||
|
||||
int my_strncmp(const char* a, const char* b, size_t len) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if (*a < *b)
|
||||
return -1;
|
||||
else if (*a > *b)
|
||||
return 1;
|
||||
else if (*a == 0)
|
||||
return 0;
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse a non-negative integer.
|
||||
// result: (output) the resulting non-negative integer
|
||||
// s: a NUL terminated string
|
||||
// Return true iff successful.
|
||||
bool my_strtoui(int* result, const char* s) {
|
||||
if (*s == 0)
|
||||
return false;
|
||||
int r = 0;
|
||||
for (;; s++) {
|
||||
if (*s == 0)
|
||||
break;
|
||||
const int old_r = r;
|
||||
r *= 10;
|
||||
if (*s < '0' || *s > '9')
|
||||
return false;
|
||||
r += *s - '0';
|
||||
if (r < old_r)
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = r;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the length of the given unsigned integer when expressed in base 10.
|
||||
unsigned my_uint_len(uintmax_t i) {
|
||||
if (!i)
|
||||
return 1;
|
||||
|
||||
int len = 0;
|
||||
while (i) {
|
||||
len++;
|
||||
i /= 10;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// Convert an unsigned integer to a string
|
||||
// output: (output) the resulting string is written here. This buffer must be
|
||||
// large enough to hold the resulting string. Call |my_uint_len| to get the
|
||||
// required length.
|
||||
// i: the unsigned integer to serialise.
|
||||
// i_len: the length of the integer in base 10 (see |my_uint_len|).
|
||||
void my_uitos(char* output, uintmax_t i, unsigned i_len) {
|
||||
for (unsigned index = i_len; index; --index, i /= 10)
|
||||
output[index - 1] = '0' + (i % 10);
|
||||
}
|
||||
|
||||
const char* my_strchr(const char* haystack, char needle) {
|
||||
while (*haystack && *haystack != needle)
|
||||
haystack++;
|
||||
if (*haystack == needle)
|
||||
return haystack;
|
||||
return (const char*) 0;
|
||||
}
|
||||
|
||||
const char* my_strrchr(const char* haystack, char needle) {
|
||||
const char* ret = NULL;
|
||||
while (*haystack) {
|
||||
if (*haystack == needle)
|
||||
ret = haystack;
|
||||
haystack++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void* my_memchr(const void* src, int needle, size_t src_len) {
|
||||
const unsigned char* p = (const unsigned char*)src;
|
||||
const unsigned char* p_end = p + src_len;
|
||||
for (; p < p_end; ++p) {
|
||||
if (*p == needle)
|
||||
return (void*)p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Read a hex value
|
||||
// result: (output) the resulting value
|
||||
// s: a string
|
||||
// Returns a pointer to the first invalid charactor.
|
||||
const char* my_read_hex_ptr(uintptr_t* result, const char* s) {
|
||||
uintptr_t r = 0;
|
||||
|
||||
for (;; ++s) {
|
||||
if (*s >= '0' && *s <= '9') {
|
||||
r <<= 4;
|
||||
r += *s - '0';
|
||||
} else if (*s >= 'a' && *s <= 'f') {
|
||||
r <<= 4;
|
||||
r += (*s - 'a') + 10;
|
||||
} else if (*s >= 'A' && *s <= 'F') {
|
||||
r <<= 4;
|
||||
r += (*s - 'A') + 10;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*result = r;
|
||||
return s;
|
||||
}
|
||||
|
||||
const char* my_read_decimal_ptr(uintptr_t* result, const char* s) {
|
||||
uintptr_t r = 0;
|
||||
|
||||
for (;; ++s) {
|
||||
if (*s >= '0' && *s <= '9') {
|
||||
r *= 10;
|
||||
r += *s - '0';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
*result = r;
|
||||
return s;
|
||||
}
|
||||
|
||||
void my_memset(void* ip, char c, size_t len) {
|
||||
char* p = (char *) ip;
|
||||
while (len--)
|
||||
*p++ = c;
|
||||
}
|
||||
|
||||
size_t my_strlcpy(char* s1, const char* s2, size_t len) {
|
||||
size_t pos1 = 0;
|
||||
size_t pos2 = 0;
|
||||
|
||||
while (s2[pos2] != '\0') {
|
||||
if (pos1 + 1 < len) {
|
||||
s1[pos1] = s2[pos2];
|
||||
pos1++;
|
||||
}
|
||||
pos2++;
|
||||
}
|
||||
if (len > 0)
|
||||
s1[pos1] = '\0';
|
||||
|
||||
return pos2;
|
||||
}
|
||||
|
||||
size_t my_strlcat(char* s1, const char* s2, size_t len) {
|
||||
size_t pos1 = 0;
|
||||
|
||||
while (pos1 < len && s1[pos1] != '\0')
|
||||
pos1++;
|
||||
|
||||
if (pos1 == len)
|
||||
return pos1;
|
||||
|
||||
return pos1 + my_strlcpy(s1 + pos1, s2, len - pos1);
|
||||
}
|
||||
|
||||
int my_isspace(int ch) {
|
||||
// Matches the C locale.
|
||||
const char spaces[] = " \t\f\n\r\t\v";
|
||||
for (size_t i = 0; i < sizeof(spaces); i++) {
|
||||
if (ch == spaces[i])
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // extern "C"
|
@@ -40,138 +40,56 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
static inline size_t
|
||||
my_strlen(const char* s) {
|
||||
size_t len = 0;
|
||||
while (*s++) len++;
|
||||
return len;
|
||||
}
|
||||
extern size_t my_strlen(const char* s);
|
||||
|
||||
static inline 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++;
|
||||
}
|
||||
}
|
||||
extern int my_strcmp(const char* a, const char* b);
|
||||
|
||||
static inline 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;
|
||||
}
|
||||
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.
|
||||
static inline 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;
|
||||
}
|
||||
extern bool my_strtoui(int* result, const char* s);
|
||||
|
||||
*result = r;
|
||||
return true;
|
||||
}
|
||||
// Return the length of the given unsigned integer when expressed in base 10.
|
||||
extern unsigned my_uint_len(uintmax_t i);
|
||||
|
||||
// Return the length of the given, non-negative integer when expressed in base
|
||||
// 10.
|
||||
static inline unsigned
|
||||
my_int_len(intmax_t i) {
|
||||
if (!i)
|
||||
return 1;
|
||||
|
||||
int len = 0;
|
||||
while (i) {
|
||||
len++;
|
||||
i /= 10;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// Convert a non-negative integer to a string
|
||||
// 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_int_len| to get the
|
||||
// large enough to hold the resulting string. Call |my_uint_len| to get the
|
||||
// required length.
|
||||
// i: the non-negative integer to serialise.
|
||||
// i_len: the length of the integer in base 10 (see |my_int_len|).
|
||||
static inline void
|
||||
my_itos(char* output, intmax_t i, unsigned i_len) {
|
||||
for (unsigned index = i_len; index; --index, i /= 10)
|
||||
output[index - 1] = '0' + (i % 10);
|
||||
}
|
||||
// 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);
|
||||
|
||||
static inline const char*
|
||||
my_strchr(const char* haystack, char needle) {
|
||||
while (*haystack && *haystack != needle)
|
||||
haystack++;
|
||||
if (*haystack == needle)
|
||||
return haystack;
|
||||
return (const char*) 0;
|
||||
}
|
||||
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.
|
||||
static inline const char*
|
||||
my_read_hex_ptr(uintptr_t* result, const char* s) {
|
||||
uintptr_t r = 0;
|
||||
extern const char* my_read_hex_ptr(uintptr_t* result, const char* s);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
extern const char* my_read_decimal_ptr(uintptr_t* result, const char* s);
|
||||
|
||||
*result = r;
|
||||
return s;
|
||||
}
|
||||
extern void my_memset(void* ip, char c, size_t len);
|
||||
|
||||
static inline void
|
||||
my_memset(void* ip, char c, size_t len) {
|
||||
char* p = (char *) ip;
|
||||
while (len--)
|
||||
*p++ = c;
|
||||
}
|
||||
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"
|
||||
|
||||
|
@@ -27,8 +27,8 @@
|
||||
// (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"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
typedef testing::Test LinuxLibcSupportTest;
|
||||
@@ -89,35 +89,41 @@ TEST(LinuxLibcSupportTest, strtoui) {
|
||||
ASSERT_EQ(result, 123);
|
||||
}
|
||||
|
||||
TEST(LinuxLibcSupportTest, int_len) {
|
||||
ASSERT_EQ(my_int_len(0), 1);
|
||||
ASSERT_EQ(my_int_len(2), 1);
|
||||
ASSERT_EQ(my_int_len(5), 1);
|
||||
ASSERT_EQ(my_int_len(9), 1);
|
||||
ASSERT_EQ(my_int_len(10), 2);
|
||||
ASSERT_EQ(my_int_len(99), 2);
|
||||
ASSERT_EQ(my_int_len(100), 3);
|
||||
ASSERT_EQ(my_int_len(101), 3);
|
||||
ASSERT_EQ(my_int_len(1000), 4);
|
||||
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, itos) {
|
||||
char buf[10];
|
||||
TEST(LinuxLibcSupportTest, uitos) {
|
||||
char buf[32];
|
||||
|
||||
my_itos(buf, 0, 1);
|
||||
my_uitos(buf, 0, 1);
|
||||
ASSERT_EQ(0, memcmp(buf, "0", 1));
|
||||
|
||||
my_itos(buf, 1, 1);
|
||||
my_uitos(buf, 1, 1);
|
||||
ASSERT_EQ(0, memcmp(buf, "1", 1));
|
||||
|
||||
my_itos(buf, 10, 2);
|
||||
my_uitos(buf, 10, 2);
|
||||
ASSERT_EQ(0, memcmp(buf, "10", 2));
|
||||
|
||||
my_itos(buf, 63, 2);
|
||||
my_uitos(buf, 63, 2);
|
||||
ASSERT_EQ(0, memcmp(buf, "63", 2));
|
||||
|
||||
my_itos(buf, 101, 3);
|
||||
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) {
|
||||
@@ -129,6 +135,35 @@ TEST(LinuxLibcSupportTest, strchr) {
|
||||
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) {
|
||||
@@ -136,22 +171,43 @@ TEST(LinuxLibcSupportTest, read_hex_ptr) {
|
||||
const char* last;
|
||||
|
||||
last = my_read_hex_ptr(&result, "");
|
||||
ASSERT_EQ(result, 0);
|
||||
ASSERT_EQ(result, 0U);
|
||||
ASSERT_EQ(*last, 0);
|
||||
|
||||
last = my_read_hex_ptr(&result, "0");
|
||||
ASSERT_EQ(result, 0);
|
||||
ASSERT_EQ(result, 0U);
|
||||
ASSERT_EQ(*last, 0);
|
||||
|
||||
last = my_read_hex_ptr(&result, "0123");
|
||||
ASSERT_EQ(result, 0x123);
|
||||
ASSERT_EQ(result, 0x123U);
|
||||
ASSERT_EQ(*last, 0);
|
||||
|
||||
last = my_read_hex_ptr(&result, "0123a");
|
||||
ASSERT_EQ(result, 0x123a);
|
||||
ASSERT_EQ(result, 0x123aU);
|
||||
ASSERT_EQ(*last, 0);
|
||||
|
||||
last = my_read_hex_ptr(&result, "0123a-");
|
||||
ASSERT_EQ(result, 0x123a);
|
||||
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, '-');
|
||||
}
|
||||
|
@@ -62,10 +62,7 @@ bool MemoryMappedFile::Map(const char* path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) != 0) {
|
||||
#elif defined(__x86_64__)
|
||||
#if defined(__x86_64__)
|
||||
struct kernel_stat st;
|
||||
if (sys_fstat(fd, &st) == -1 || st.st_size < 0) {
|
||||
#else
|
||||
@@ -100,7 +97,7 @@ bool MemoryMappedFile::Map(const char* path) {
|
||||
|
||||
void MemoryMappedFile::Unmap() {
|
||||
if (content_.data()) {
|
||||
sys_munmap(const_cast<u_int8_t*>(content_.data()), content_.length());
|
||||
sys_munmap(const_cast<uint8_t*>(content_.data()), content_.length());
|
||||
content_.Set(NULL, 0);
|
||||
}
|
||||
}
|
||||
|
@@ -37,15 +37,14 @@
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/eintr_wrapper.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;
|
||||
using std::string;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -54,7 +53,7 @@ class MemoryMappedFileTest : public testing::Test {
|
||||
void ExpectNoMappedData(const MemoryMappedFile& mapped_file) {
|
||||
EXPECT_TRUE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() == NULL);
|
||||
EXPECT_EQ(0, mapped_file.size());
|
||||
EXPECT_EQ(0U, mapped_file.size());
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -48,7 +48,7 @@ TEST(SafeReadLinkTest, BoundaryBufferSize) {
|
||||
char buffer[PATH_MAX];
|
||||
EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer, sizeof(buffer)));
|
||||
size_t path_length = strlen(buffer);
|
||||
EXPECT_LT(0, path_length);
|
||||
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.
|
||||
|
117
thirdparty/breakpad/common/linux/synth_elf.cc
vendored
117
thirdparty/breakpad/common/linux/synth_elf.cc
vendored
@@ -5,19 +5,19 @@
|
||||
#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 {
|
||||
|
||||
#ifndef NT_GNU_BUILD_ID
|
||||
#define NT_GNU_BUILD_ID 3
|
||||
#endif
|
||||
|
||||
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) {
|
||||
@@ -113,18 +113,75 @@ int ELF::AddSection(const string& name, const Section& section,
|
||||
// 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 (type == SHT_NULL) {
|
||||
offset_label = 0;
|
||||
} else if (type == SHT_NOBITS) {
|
||||
offset_label = offset;
|
||||
if (section.type_ == SHT_NULL) {
|
||||
section.offset_label_ = 0;
|
||||
} else if (section.type_ == SHT_NOBITS) {
|
||||
section.offset_label_ = section.offset_;
|
||||
} else {
|
||||
Mark(&offset_label);
|
||||
Mark(§ion.offset_label_);
|
||||
Append(section);
|
||||
Align(4);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
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() {
|
||||
@@ -134,10 +191,19 @@ void ELF::Finish() {
|
||||
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_;
|
||||
// TODO: allow adding entries to program header table
|
||||
program_header_label_ = 0;
|
||||
|
||||
// Section header table starts here.
|
||||
Mark(§ion_header_label_);
|
||||
@@ -174,30 +240,21 @@ void SymbolTable::AddSymbol(const string& name, uint64_t value,
|
||||
D64(size);
|
||||
}
|
||||
|
||||
BuildIDNote::BuildIDNote(const uint8_t* id_bytes,
|
||||
size_t id_size,
|
||||
Endianness endianness) : Section(endianness) {
|
||||
const char kNoteName[] = "GNU";
|
||||
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 = sizeof(kNoteName);
|
||||
note_header.n_descsz = id_size;
|
||||
note_header.n_type = NT_GNU_BUILD_ID;
|
||||
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(kNoteName);
|
||||
Append(id_bytes, id_size);
|
||||
}
|
||||
|
||||
// static
|
||||
void BuildIDNote::AppendSection(ELF& elf,
|
||||
const uint8_t* id_bytes,
|
||||
size_t id_size) {
|
||||
const char kBuildIDSectionName[] = ".note.gnu.build-id";
|
||||
BuildIDNote note(id_bytes, id_size, elf.endianness());
|
||||
elf.AddSection(kBuildIDSectionName, note, SHT_NOTE);
|
||||
AppendCString(name);
|
||||
Align(4);
|
||||
Append(desc_bytes, desc_size);
|
||||
Align(4);
|
||||
}
|
||||
|
||||
} // namespace synth_elf
|
||||
|
43
thirdparty/breakpad/common/linux/synth_elf.h
vendored
43
thirdparty/breakpad/common/linux/synth_elf.h
vendored
@@ -39,17 +39,20 @@
|
||||
#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 std::string;
|
||||
using test_assembler::Endianness;
|
||||
using test_assembler::kLittleEndian;
|
||||
using test_assembler::kUnsetEndian;
|
||||
@@ -101,6 +104,10 @@ class ELF : public 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();
|
||||
|
||||
@@ -113,6 +120,8 @@ class ELF : public Section {
|
||||
// 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_;
|
||||
@@ -127,6 +136,25 @@ class ELF : public Section {
|
||||
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.
|
||||
@@ -149,13 +177,16 @@ class SymbolTable : public Section {
|
||||
StringTable& table_;
|
||||
};
|
||||
|
||||
// A class to build GNU Build ID note sections
|
||||
class BuildIDNote : public Section {
|
||||
// A class for note sections
|
||||
class Notes : public Section {
|
||||
public:
|
||||
BuildIDNote(const uint8_t* id_bytes, size_t id_size, Endianness endianness);
|
||||
Notes(Endianness endianness)
|
||||
: Section(endianness) {
|
||||
}
|
||||
|
||||
// Append a new Build ID note section to |elf|.
|
||||
static void AppendSection(ELF& elf, const uint8_t* id_bytes, size_t id_size);
|
||||
// Add a note.
|
||||
void AddNote(int type, const string &name, const uint8_t* desc_bytes,
|
||||
size_t desc_size);
|
||||
};
|
||||
|
||||
} // namespace synth_elf
|
||||
|
@@ -35,17 +35,23 @@
|
||||
#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 std::string;
|
||||
using ::testing::Test;
|
||||
using ::testing::Types;
|
||||
|
||||
class StringTableTest : public Test {
|
||||
public:
|
||||
@@ -55,7 +61,7 @@ public:
|
||||
};
|
||||
|
||||
TEST_F(StringTableTest, Empty) {
|
||||
EXPECT_EQ(1, table.Size());
|
||||
EXPECT_EQ(1U, table.Size());
|
||||
string contents;
|
||||
ASSERT_TRUE(table.GetContents(&contents));
|
||||
const char* kExpectedContents = "\0";
|
||||
@@ -63,7 +69,7 @@ TEST_F(StringTableTest, Empty) {
|
||||
contents.c_str(),
|
||||
contents.size()));
|
||||
ASSERT_TRUE(table.empty_string.IsKnownConstant());
|
||||
EXPECT_EQ(0, table.empty_string.Value());
|
||||
EXPECT_EQ(0U, table.empty_string.Value());
|
||||
}
|
||||
|
||||
TEST_F(StringTableTest, Basic) {
|
||||
@@ -84,7 +90,7 @@ TEST_F(StringTableTest, Basic) {
|
||||
contents.size()));
|
||||
// empty_string is at zero, other strings start at 1.
|
||||
ASSERT_TRUE(l1.IsKnownConstant());
|
||||
EXPECT_EQ(1, l1.Value());
|
||||
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());
|
||||
@@ -105,7 +111,7 @@ TEST_F(StringTableTest, Duplicates) {
|
||||
EXPECT_EQ(0, memcmp(kExpectedContents,
|
||||
contents.c_str(),
|
||||
contents.size()));
|
||||
EXPECT_EQ(0, table.empty_string.Value());
|
||||
EXPECT_EQ(0U, table.empty_string.Value());
|
||||
EXPECT_EQ(table.empty_string.Value(), l3.Value());
|
||||
EXPECT_EQ(l2.Value(), l4.Value());
|
||||
}
|
||||
@@ -178,88 +184,230 @@ TEST_F(SymbolTableTest, Simple32) {
|
||||
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__)
|
||||
|
||||
TEST_F(BasicElf, EmptyLE32) {
|
||||
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(Elf32_Ehdr) +
|
||||
const size_t kExpectedSize = sizeof(Ehdr) +
|
||||
// Two sections, SHT_NULL + the section header string table.
|
||||
2 * sizeof(Elf32_Shdr) +
|
||||
2 * sizeof(Shdr) +
|
||||
kStringTableSize + kStringTableAlign;
|
||||
|
||||
ELF elf(EM_386, ELFCLASS32, kLittleEndian);
|
||||
// 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 Elf32_Ehdr* header =
|
||||
reinterpret_cast<const Elf32_Ehdr*>(contents.data());
|
||||
const Ehdr* header =
|
||||
reinterpret_cast<const Ehdr*>(contents.data());
|
||||
const uint8_t kIdent[] = {
|
||||
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
||||
ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV,
|
||||
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(EV_CURRENT, header->e_version);
|
||||
EXPECT_EQ(0, header->e_entry);
|
||||
EXPECT_EQ(0, header->e_phoff);
|
||||
EXPECT_EQ(sizeof(Elf32_Ehdr) + kStringTableSize + kStringTableAlign,
|
||||
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(0, header->e_flags);
|
||||
EXPECT_EQ(sizeof(Elf32_Ehdr), header->e_ehsize);
|
||||
EXPECT_EQ(sizeof(Elf32_Phdr), header->e_phentsize);
|
||||
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(Elf32_Shdr), header->e_shentsize);
|
||||
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);
|
||||
}
|
||||
|
||||
TEST_F(BasicElf, EmptyLE64) {
|
||||
const size_t kStringTableSize = sizeof("\0.shstrtab");
|
||||
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(Elf64_Ehdr) +
|
||||
// Two sections, SHT_NULL + the section header string table.
|
||||
2 * sizeof(Elf64_Shdr) +
|
||||
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;
|
||||
|
||||
ELF elf(EM_X86_64, ELFCLASS64, kLittleEndian);
|
||||
// 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 Elf64_Ehdr* header =
|
||||
reinterpret_cast<const Elf64_Ehdr*>(contents.data());
|
||||
const Ehdr* header =
|
||||
reinterpret_cast<const Ehdr*>(contents.data());
|
||||
const uint8_t kIdent[] = {
|
||||
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
||||
ELFCLASS64, ELFDATA2LSB, EV_CURRENT, ELFOSABI_SYSV,
|
||||
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_X86_64, header->e_machine);
|
||||
EXPECT_EQ(EV_CURRENT, header->e_version);
|
||||
EXPECT_EQ(0, header->e_entry);
|
||||
EXPECT_EQ(0, header->e_phoff);
|
||||
EXPECT_EQ(sizeof(Elf64_Ehdr) + kStringTableSize + kStringTableAlign,
|
||||
header->e_shoff);
|
||||
EXPECT_EQ(0, header->e_flags);
|
||||
EXPECT_EQ(sizeof(Elf64_Ehdr), header->e_ehsize);
|
||||
EXPECT_EQ(sizeof(Elf64_Phdr), header->e_phentsize);
|
||||
EXPECT_EQ(0, header->e_phnum);
|
||||
EXPECT_EQ(sizeof(Elf64_Shdr), header->e_shentsize);
|
||||
EXPECT_EQ(2, header->e_shnum);
|
||||
EXPECT_EQ(1, header->e_shstrndx);
|
||||
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__)
|
||||
|
124
thirdparty/breakpad/common/linux/tests/auto_testfile.h
vendored
Normal file
124
thirdparty/breakpad/common/linux/tests/auto_testfile.h
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
// 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
|
@@ -43,9 +43,13 @@
|
||||
|
||||
#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 {
|
||||
|
||||
@@ -97,11 +101,11 @@ bool CrashGenerator::HasDefaultCorePattern() const {
|
||||
buffer_size == 5 && memcmp(buffer, "core", 4) == 0;
|
||||
}
|
||||
|
||||
std::string CrashGenerator::GetCoreFilePath() const {
|
||||
string CrashGenerator::GetCoreFilePath() const {
|
||||
return temp_dir_.path() + "/core";
|
||||
}
|
||||
|
||||
std::string CrashGenerator::GetDirectoryOfProcFilesCopy() const {
|
||||
string CrashGenerator::GetDirectoryOfProcFilesCopy() const {
|
||||
return temp_dir_.path() + "/proc";
|
||||
}
|
||||
|
||||
@@ -170,7 +174,7 @@ bool CrashGenerator::CreateChildCrash(
|
||||
}
|
||||
if (SetCoreFileSizeLimit(kCoreSizeLimit)) {
|
||||
CreateThreadsInChildProcess(num_threads);
|
||||
std::string proc_dir = GetDirectoryOfProcFilesCopy();
|
||||
string proc_dir = GetDirectoryOfProcFilesCopy();
|
||||
if (mkdir(proc_dir.c_str(), 0755) == -1) {
|
||||
perror("CrashGenerator: Failed to create proc directory");
|
||||
exit(1);
|
||||
|
@@ -38,6 +38,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "common/tests/auto_tempdir.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
@@ -59,10 +60,10 @@ class CrashGenerator {
|
||||
bool HasDefaultCorePattern() const;
|
||||
|
||||
// Returns the expected path of the core dump file.
|
||||
std::string GetCoreFilePath() const;
|
||||
string GetCoreFilePath() const;
|
||||
|
||||
// Returns the directory of a copy of proc files of the child process.
|
||||
std::string GetDirectoryOfProcFilesCopy() const;
|
||||
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
|
||||
|
@@ -31,3 +31,4 @@
|
||||
|
||||
GCC_OPTIMIZATION_LEVEL = s
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) NDEBUG
|
||||
|
279
thirdparty/breakpad/common/mac/GTMDefines.h
vendored
279
thirdparty/breakpad/common/mac/GTMDefines.h
vendored
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// GTMDefines.h
|
||||
//
|
||||
// Copyright 2008 Google Inc.
|
||||
@@ -6,21 +6,29 @@
|
||||
// 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
|
||||
@@ -28,6 +36,29 @@
|
||||
#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
|
||||
@@ -35,7 +66,7 @@
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
// By setting the GTM_CONTAINERS_VALIDATION_FAILED_LOG and
|
||||
// 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.
|
||||
@@ -47,7 +78,7 @@
|
||||
// a few different actual definitions, so we're based off of the foundation
|
||||
// one.
|
||||
#if !defined(GTM_INLINE)
|
||||
#if defined (__GNUC__) && (__GNUC__ == 4)
|
||||
#if (defined (__GNUC__) && (__GNUC__ == 4)) || defined (__clang__)
|
||||
#define GTM_INLINE static __inline__ __attribute__((always_inline))
|
||||
#else
|
||||
#define GTM_INLINE static __inline__
|
||||
@@ -59,8 +90,12 @@
|
||||
#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
|
||||
|
||||
@@ -70,6 +105,12 @@
|
||||
#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
|
||||
@@ -82,12 +123,12 @@
|
||||
// _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
|
||||
@@ -100,11 +141,6 @@
|
||||
|
||||
#endif // _GTMDevLog
|
||||
|
||||
// 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, ...);
|
||||
|
||||
#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)
|
||||
@@ -145,28 +181,6 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
|
||||
typedef char _GTMCompileAssertSymbol(__LINE__, msg) [ ((test) ? 1 : -1) ]
|
||||
#endif // _GTMCompileAssert
|
||||
|
||||
// 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_OBJECT(element, collection) \
|
||||
for (element in collection)
|
||||
#define GTM_FOREACH_KEY(element, collection) \
|
||||
for (element in collection)
|
||||
#else
|
||||
#define GTM_FOREACH_OBJECT(element, collection) \
|
||||
for (NSEnumerator * _ ## element ## _enum = [collection objectEnumerator]; \
|
||||
(element = [_ ## element ## _enum nextObject]) != nil; )
|
||||
#define GTM_FOREACH_KEY(element, collection) \
|
||||
for (NSEnumerator * _ ## element ## _enum = [collection keyEnumerator]; \
|
||||
(element = [_ ## element ## _enum nextObject]) != nil; )
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// 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
|
||||
@@ -183,11 +197,26 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
|
||||
#else
|
||||
#define GTM_IPHONE_DEVICE 1
|
||||
#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
|
||||
#else
|
||||
// For MacOS specific stuff
|
||||
#define GTM_MACOS_SDK 1
|
||||
#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
|
||||
|
||||
// Provide a symbol to include/exclude extra code for GC support. (This mainly
|
||||
// just controls the inclusion of finalize methods).
|
||||
#ifndef GTM_SUPPORT_GC
|
||||
@@ -197,7 +226,7 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
|
||||
#else
|
||||
// We can't find a symbol to tell if GC is supported/required, so best we
|
||||
// do on Mac targets is include it if we're on 10.5 or later.
|
||||
#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5
|
||||
#define GTM_SUPPORT_GC 0
|
||||
#else
|
||||
#define GTM_SUPPORT_GC 1
|
||||
@@ -207,7 +236,7 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
|
||||
|
||||
// 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_4
|
||||
#if !(MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
|
||||
// NSInteger/NSUInteger and Max/Mins
|
||||
#ifndef NSINTEGER_DEFINED
|
||||
#if __LP64__ || NS_BUILD_32_LIKE_64
|
||||
@@ -238,4 +267,178 @@ GTM_EXTERN void _GTMUnitTestDevLog(NSString *format, ...);
|
||||
#endif /* !defined(__LP64__) || !__LP64__ */
|
||||
#define CGFLOAT_DEFINED 1
|
||||
#endif // CGFLOAT_DEFINED
|
||||
#endif // MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
|
||||
#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
|
||||
#define GTM_NONNULL(x) __attribute__((nonnull(x)))
|
||||
#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
|
||||
|
||||
#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__
|
||||
|
128
thirdparty/breakpad/common/mac/GTMLogger.h
vendored
128
thirdparty/breakpad/common/mac/GTMLogger.h
vendored
@@ -6,9 +6,9 @@
|
||||
// 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
|
||||
@@ -18,15 +18,15 @@
|
||||
|
||||
// Key Abstractions
|
||||
// ----------------
|
||||
//
|
||||
// This file declares multiple classes and protocols that are used by the
|
||||
//
|
||||
// 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).
|
||||
@@ -44,7 +44,7 @@
|
||||
// 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,
|
||||
// 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.
|
||||
@@ -55,12 +55,6 @@
|
||||
// Predeclaration of used protocols that are declared later in this file.
|
||||
@protocol GTMLogWriter, GTMLogFormatter, GTMLogFilter;
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
|
||||
#define CHECK_FORMAT_NSSTRING(a, b) __attribute__((format(__NSString__, a, b)))
|
||||
#else
|
||||
#define CHECK_FORMAT_NSSTRING(a, b)
|
||||
#endif
|
||||
|
||||
// GTMLogger
|
||||
//
|
||||
// GTMLogger is the primary user-facing class for an object-oriented logging
|
||||
@@ -69,7 +63,7 @@
|
||||
// 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,
|
||||
@@ -77,7 +71,7 @@
|
||||
// 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
|
||||
@@ -85,13 +79,13 @@
|
||||
// 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
|
||||
@@ -113,10 +107,10 @@
|
||||
// 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:
|
||||
@@ -146,7 +140,7 @@
|
||||
// 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.
|
||||
@@ -160,14 +154,14 @@
|
||||
//
|
||||
// GTMLoggerDebug(@"foo = %@", foo);
|
||||
//
|
||||
// 2. The previous example is similar to the following. The major difference is
|
||||
// 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
|
||||
// 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"
|
||||
@@ -185,12 +179,12 @@
|
||||
// 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
|
||||
// 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.
|
||||
//
|
||||
@@ -198,7 +192,7 @@
|
||||
// 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
|
||||
@@ -244,6 +238,10 @@
|
||||
// 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.
|
||||
@@ -274,20 +272,20 @@
|
||||
//
|
||||
|
||||
// Logs a message at the debug level (kGTMLoggerLevelDebug).
|
||||
- (void)logDebug:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
|
||||
- (void)logDebug:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2);
|
||||
// Logs a message at the info level (kGTMLoggerLevelInfo).
|
||||
- (void)logInfo:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
|
||||
- (void)logInfo:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2);
|
||||
// Logs a message at the error level (kGTMLoggerLevelError).
|
||||
- (void)logError:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
|
||||
- (void)logError:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2);
|
||||
// Logs a message at the assert level (kGTMLoggerLevelAssert).
|
||||
- (void)logAssert:(NSString *)fmt, ... CHECK_FORMAT_NSSTRING(1, 2);
|
||||
- (void)logAssert:(NSString *)fmt, ... NS_FORMAT_FUNCTION(1, 2);
|
||||
|
||||
|
||||
//
|
||||
// Accessors
|
||||
//
|
||||
|
||||
// Accessor methods for the log writer. If the log writer is set to nil,
|
||||
// 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;
|
||||
@@ -306,20 +304,23 @@
|
||||
@end // GTMLogger
|
||||
|
||||
|
||||
// Helper functions that are used by the convenience GTMLogger*() macros that
|
||||
// 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, ...
|
||||
CHECK_FORMAT_NSSTRING(2, 3);
|
||||
NS_FORMAT_FUNCTION(2, 3);
|
||||
- (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ...
|
||||
CHECK_FORMAT_NSSTRING(2, 3);
|
||||
NS_FORMAT_FUNCTION(2, 3);
|
||||
- (void)logFuncError:(const char *)func msg:(NSString *)fmt, ...
|
||||
CHECK_FORMAT_NSSTRING(2, 3);
|
||||
NS_FORMAT_FUNCTION(2, 3);
|
||||
- (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ...
|
||||
CHECK_FORMAT_NSSTRING(2, 3);
|
||||
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.
|
||||
@@ -339,6 +340,8 @@
|
||||
#define GTMLoggerDebug(...) do {} while(0)
|
||||
#endif
|
||||
|
||||
#endif // !defined(GTMLoggerInfo)
|
||||
|
||||
// Log levels.
|
||||
typedef enum {
|
||||
kGTMLoggerLevelUnknown,
|
||||
@@ -365,7 +368,7 @@ typedef enum {
|
||||
// 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|
|
||||
// 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
|
||||
@@ -379,7 +382,7 @@ typedef enum {
|
||||
//
|
||||
// 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
|
||||
// writers you wish to use, then set the array as the "writer" for your
|
||||
// GTMLogger instance.
|
||||
@interface NSArray (GTMArrayCompositeLogWriter) <GTMLogWriter>
|
||||
@end // GTMArrayCompositeLogWriter
|
||||
@@ -390,7 +393,7 @@ typedef enum {
|
||||
//
|
||||
// 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
|
||||
// that with a different log writer that may have its own formatter and/or
|
||||
// filter.
|
||||
@interface GTMLogger (GTMLoggerLogWriter) <GTMLogWriter>
|
||||
@end // GTMLoggerLogWriter
|
||||
@@ -407,14 +410,18 @@ typedef enum {
|
||||
- (NSString *)stringForFunc:(NSString *)func
|
||||
withFormat:(NSString *)fmt
|
||||
valist:(va_list)args
|
||||
level:(GTMLoggerLevel)level;
|
||||
level:(GTMLoggerLevel)level NS_FORMAT_FUNCTION(2, 0);
|
||||
@end // GTMLogFormatter
|
||||
|
||||
|
||||
// A basic log formatter that formats a string the same way that NSLog (or
|
||||
// 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
|
||||
|
||||
|
||||
@@ -450,9 +457,48 @@ typedef enum {
|
||||
@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
|
||||
|
||||
|
371
thirdparty/breakpad/common/mac/GTMLogger.m
vendored
371
thirdparty/breakpad/common/mac/GTMLogger.m
vendored
@@ -6,9 +6,9 @@
|
||||
// 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
|
||||
@@ -24,39 +24,30 @@
|
||||
#import <pthread.h>
|
||||
|
||||
|
||||
// Define a trivial assertion macro to avoid dependencies
|
||||
#ifdef DEBUG
|
||||
#define GTMLOGGER_ASSERT(expr) assert(expr)
|
||||
#else
|
||||
#define GTMLOGGER_ASSERT(expr)
|
||||
#endif
|
||||
#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__
|
||||
|
||||
|
||||
@interface GTMLogger (PrivateMethods)
|
||||
|
||||
- (void)logInternalFunc:(const char *)func
|
||||
format:(NSString *)fmt
|
||||
valist:(va_list)args
|
||||
level:(GTMLoggerLevel)level;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
// Reference to the shared GTMLogger instance. This is not a singleton, it's
|
||||
// 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
|
||||
// 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];
|
||||
}
|
||||
GTMLOGGER_ASSERT(gSharedLogger != nil);
|
||||
}
|
||||
return [[gSharedLogger retain] autorelease];
|
||||
}
|
||||
@@ -69,24 +60,85 @@ static GTMLogger *gSharedLogger = nil;
|
||||
}
|
||||
|
||||
+ (id)standardLogger {
|
||||
id<GTMLogWriter> writer = [NSFileHandle fileHandleWithStandardOutput];
|
||||
id<GTMLogFormatter> fr = [[[GTMLogStandardFormatter alloc] init] autorelease];
|
||||
id<GTMLogFilter> filter = [[[GTMLogLevelFilter alloc] init] autorelease];
|
||||
return [self loggerWithWriter:writer formatter:fr filter:filter];
|
||||
// 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 {
|
||||
id me = [self standardLogger];
|
||||
[me setWriter:[NSFileHandle fileHandleWithStandardError]];
|
||||
return me;
|
||||
// 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 {
|
||||
NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644];
|
||||
if (fh == nil) return nil;
|
||||
id me = [self standardLogger];
|
||||
[me setWriter:fh];
|
||||
return me;
|
||||
@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
|
||||
@@ -112,69 +164,85 @@ static GTMLogger *gSharedLogger = nil;
|
||||
[self setWriter:writer];
|
||||
[self setFormatter:formatter];
|
||||
[self setFilter:filter];
|
||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
||||
GTMLOGGER_ASSERT(filter_ != nil);
|
||||
GTMLOGGER_ASSERT(writer_ != nil);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
GTMLOGGER_ASSERT(writer_ != nil);
|
||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
||||
GTMLOGGER_ASSERT(filter_ != nil);
|
||||
[writer_ release];
|
||||
[formatter_ release];
|
||||
[filter_ release];
|
||||
// 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 {
|
||||
GTMLOGGER_ASSERT(writer_ != nil);
|
||||
return [[writer_ retain] autorelease];
|
||||
}
|
||||
|
||||
- (void)setWriter:(id<GTMLogWriter>)writer {
|
||||
@synchronized(self) {
|
||||
[writer_ autorelease];
|
||||
if (writer == nil)
|
||||
writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain];
|
||||
else
|
||||
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];
|
||||
}
|
||||
}
|
||||
GTMLOGGER_ASSERT(writer_ != nil);
|
||||
}
|
||||
|
||||
- (id<GTMLogFormatter>)formatter {
|
||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
||||
return [[formatter_ retain] autorelease];
|
||||
}
|
||||
|
||||
- (void)setFormatter:(id<GTMLogFormatter>)formatter {
|
||||
@synchronized(self) {
|
||||
[formatter_ autorelease];
|
||||
if (formatter == nil)
|
||||
formatter_ = [[GTMLogBasicFormatter alloc] init];
|
||||
else
|
||||
formatter_ = nil;
|
||||
if (formatter == nil) {
|
||||
@try {
|
||||
formatter_ = [[GTMLogBasicFormatter alloc] init];
|
||||
}
|
||||
@catch (id e) {
|
||||
// Leave |formatter_| nil
|
||||
}
|
||||
} else {
|
||||
formatter_ = [formatter retain];
|
||||
}
|
||||
}
|
||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
||||
}
|
||||
|
||||
- (id<GTMLogFilter>)filter {
|
||||
GTMLOGGER_ASSERT(filter_ != nil);
|
||||
return [[filter_ retain] autorelease];
|
||||
}
|
||||
|
||||
- (void)setFilter:(id<GTMLogFilter>)filter {
|
||||
@synchronized(self) {
|
||||
[filter_ autorelease];
|
||||
if (filter == nil)
|
||||
filter_ = [[GTMLogNoFilter alloc] init];
|
||||
else
|
||||
filter_ = nil;
|
||||
if (filter == nil) {
|
||||
@try {
|
||||
filter_ = [[GTMLogNoFilter alloc] init];
|
||||
}
|
||||
@catch (id e) {
|
||||
// Leave |filter_| nil
|
||||
}
|
||||
} else {
|
||||
filter_ = [filter retain];
|
||||
}
|
||||
}
|
||||
GTMLOGGER_ASSERT(filter_ != nil);
|
||||
}
|
||||
|
||||
- (void)logDebug:(NSString *)fmt, ... {
|
||||
@@ -207,7 +275,6 @@ static GTMLogger *gSharedLogger = nil;
|
||||
|
||||
@end // GTMLogger
|
||||
|
||||
|
||||
@implementation GTMLogger (GTMLoggerMacroHelpers)
|
||||
|
||||
- (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... {
|
||||
@@ -240,24 +307,26 @@ static GTMLogger *gSharedLogger = nil;
|
||||
|
||||
@end // GTMLoggerMacroHelpers
|
||||
|
||||
|
||||
@implementation GTMLogger (PrivateMethods)
|
||||
|
||||
- (void)logInternalFunc:(const char *)func
|
||||
format:(NSString *)fmt
|
||||
valist:(va_list)args
|
||||
valist:(va_list)args
|
||||
level:(GTMLoggerLevel)level {
|
||||
GTMLOGGER_ASSERT(formatter_ != nil);
|
||||
GTMLOGGER_ASSERT(filter_ != nil);
|
||||
GTMLOGGER_ASSERT(writer_ != nil);
|
||||
|
||||
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];
|
||||
// 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
|
||||
@@ -278,8 +347,16 @@ static GTMLogger *gSharedLogger = nil;
|
||||
|
||||
- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
|
||||
@synchronized(self) {
|
||||
NSString *line = [NSString stringWithFormat:@"%@\n", msg];
|
||||
[self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,18 +383,18 @@ static GTMLogger *gSharedLogger = nil;
|
||||
- (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
|
||||
switch (level) {
|
||||
case kGTMLoggerLevelDebug:
|
||||
[self logDebug:@"%@", msg];
|
||||
[self logDebug:@"%@", msg];
|
||||
break;
|
||||
case kGTMLoggerLevelInfo:
|
||||
[self logInfo:@"%@", msg];
|
||||
break;
|
||||
case kGTMLoggerLevelError:
|
||||
case kGTMLoggerLevelError:
|
||||
[self logError:@"%@", msg];
|
||||
break;
|
||||
case kGTMLoggerLevelAssert:
|
||||
[self logAssert:@"%@", msg];
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
// Ignore the message.
|
||||
break;
|
||||
}
|
||||
@@ -328,19 +405,32 @@ static GTMLogger *gSharedLogger = nil;
|
||||
|
||||
@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
|
||||
valist:(va_list)args
|
||||
level:(GTMLoggerLevel)level {
|
||||
// Performance note: since we always have to create a new NSString from the
|
||||
// returned CFStringRef, we may want to do a quick check here to see if |fmt|
|
||||
// contains a '%', and if not, simply return 'fmt'.
|
||||
CFStringRef cfmsg = NULL;
|
||||
cfmsg = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault,
|
||||
NULL, // format options
|
||||
(CFStringRef)fmt,
|
||||
args);
|
||||
return GTMCFAutorelease(cfmsg);
|
||||
// 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
|
||||
@@ -355,6 +445,10 @@ static GTMLogger *gSharedLogger = nil;
|
||||
[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;
|
||||
}
|
||||
@@ -367,17 +461,17 @@ static GTMLogger *gSharedLogger = nil;
|
||||
|
||||
- (NSString *)stringForFunc:(NSString *)func
|
||||
withFormat:(NSString *)fmt
|
||||
valist:(va_list)args
|
||||
valist:(va_list)args
|
||||
level:(GTMLoggerLevel)level {
|
||||
GTMLOGGER_ASSERT(dateFormatter_ != nil);
|
||||
NSString *tstamp = nil;
|
||||
@synchronized (dateFormatter_) {
|
||||
tstamp = [dateFormatter_ stringFromDate:[NSDate date]];
|
||||
}
|
||||
return [NSString stringWithFormat:@"%@ %@[%d/%p] [lvl=%d] %@ %@",
|
||||
tstamp, pname_, pid_, pthread_self(),
|
||||
level, (func ? func : @"(no func)"),
|
||||
[super stringForFunc:func withFormat:fmt valist:args level:level]];
|
||||
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
|
||||
@@ -391,14 +485,20 @@ static GTMLogger *gSharedLogger = nil;
|
||||
// COV_NF_START
|
||||
static BOOL IsVerboseLoggingEnabled(void) {
|
||||
static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging";
|
||||
static char *env = NULL;
|
||||
if (env == NULL)
|
||||
env = getenv([kVerboseLoggingKey UTF8String]);
|
||||
|
||||
if (env && env[0]) {
|
||||
return (strtol(env, NULL, 10) != 0);
|
||||
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
|
||||
@@ -409,15 +509,15 @@ static BOOL IsVerboseLoggingEnabled(void) {
|
||||
#if DEBUG
|
||||
return YES;
|
||||
#endif
|
||||
|
||||
|
||||
BOOL allow = YES;
|
||||
|
||||
|
||||
switch (level) {
|
||||
case kGTMLoggerLevelDebug:
|
||||
allow = NO;
|
||||
break;
|
||||
case kGTMLoggerLevelInfo:
|
||||
allow = (IsVerboseLoggingEnabled() == YES);
|
||||
allow = IsVerboseLoggingEnabled();
|
||||
break;
|
||||
case kGTMLoggerLevelError:
|
||||
allow = YES;
|
||||
@@ -443,3 +543,70 @@ static BOOL IsVerboseLoggingEnabled(void) {
|
||||
}
|
||||
|
||||
@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__
|
||||
|
||||
|
8
thirdparty/breakpad/common/mac/MachIPC.h
vendored
8
thirdparty/breakpad/common/mac/MachIPC.h
vendored
@@ -164,11 +164,11 @@ class MachMessage {
|
||||
public:
|
||||
|
||||
// The receiver of the message can retrieve the raw data this way
|
||||
u_int8_t *GetData() {
|
||||
uint8_t *GetData() {
|
||||
return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
|
||||
}
|
||||
|
||||
u_int32_t GetDataLength() {
|
||||
uint32_t GetDataLength() {
|
||||
return EndianU32_LtoN(GetDataPacket()->data_length);
|
||||
}
|
||||
|
||||
@@ -210,7 +210,7 @@ class MachMessage {
|
||||
struct MessageDataPacket {
|
||||
int32_t id; // little-endian
|
||||
int32_t data_length; // little-endian
|
||||
u_int8_t data[1]; // actual size limited by sizeof(MachMessage)
|
||||
uint8_t data[1]; // actual size limited by sizeof(MachMessage)
|
||||
};
|
||||
|
||||
MessageDataPacket* GetDataPacket();
|
||||
@@ -223,7 +223,7 @@ class MachMessage {
|
||||
|
||||
mach_msg_header_t head;
|
||||
mach_msg_body_t body;
|
||||
u_int8_t padding[1024]; // descriptors and data may be embedded here
|
||||
uint8_t padding[1024]; // descriptors and data may be embedded here
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
@@ -1,195 +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.
|
||||
//
|
||||
// SimpleStringDictionary.h
|
||||
//
|
||||
|
||||
#ifndef SimpleStringDictionary_H__
|
||||
#define SimpleStringDictionary_H__
|
||||
|
||||
#import <string>
|
||||
#import <vector>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
//==============================================================================
|
||||
// SimpleStringDictionary (and associated class KeyValueEntry) implement a very
|
||||
// basic dictionary container class. It has the property of not making any
|
||||
// memory allocations when getting and setting values. But it is not very
|
||||
// efficient, with calls to get and set values operating in linear time.
|
||||
// It has the additional limitation of having a fairly small fixed capacity of
|
||||
// SimpleStringDictionary::MAX_NUM_ENTRIES entries. An assert() will fire if
|
||||
// the client attempts to set more than this number of key/value pairs.
|
||||
// Ordinarilly a C++ programmer would use something like the std::map template
|
||||
// class, or on the Macintosh would often choose CFDictionary or NSDictionary.
|
||||
// But these dictionary classes may call malloc() during get and set operations.
|
||||
// Google Breakpad requires that no memory allocations be made in code running
|
||||
// in its exception handling thread, so it uses SimpleStringDictionary as the
|
||||
// underlying implementation for the GoogleBreakpad.framework APIs:
|
||||
// GoogleBreakpadSetKeyValue(), GoogleBreakpadKeyValue(), and
|
||||
// GoogleBreakpadRemoveKeyValue()
|
||||
//
|
||||
|
||||
//==============================================================================
|
||||
// KeyValueEntry
|
||||
//
|
||||
// A helper class used by SimpleStringDictionary representing a single
|
||||
// storage cell for a key/value pair. Each key and value string are
|
||||
// limited to MAX_STRING_STORAGE_SIZE-1 bytes (not glyphs). This class
|
||||
// performs no memory allocations. It has methods for setting and getting
|
||||
// key and value strings.
|
||||
//
|
||||
class KeyValueEntry {
|
||||
public:
|
||||
KeyValueEntry() {
|
||||
Clear();
|
||||
}
|
||||
|
||||
KeyValueEntry(const char *key, const char *value) {
|
||||
SetKeyValue(key, value);
|
||||
}
|
||||
|
||||
void SetKeyValue(const char *key, const char *value) {
|
||||
if (!key) {
|
||||
key = "";
|
||||
}
|
||||
if (!value) {
|
||||
value = "";
|
||||
}
|
||||
|
||||
strlcpy(key_, key, sizeof(key_));
|
||||
strlcpy(value_, value, sizeof(value_));
|
||||
}
|
||||
|
||||
void SetValue(const char *value) {
|
||||
if (!value) {
|
||||
value = "";
|
||||
}
|
||||
strlcpy(value_, value, sizeof(value_));
|
||||
};
|
||||
|
||||
// Removes the key/value
|
||||
void Clear() {
|
||||
memset(key_, 0, sizeof(key_));
|
||||
memset(value_, 0, sizeof(value_));
|
||||
}
|
||||
|
||||
bool IsActive() const { return key_[0] != '\0'; }
|
||||
const char *GetKey() const { return key_; }
|
||||
const char *GetValue() const { return value_; }
|
||||
|
||||
// Don't change this without considering the fixed size
|
||||
// of MachMessage (in MachIPC.h)
|
||||
// (see also struct KeyValueMessageData in Inspector.h)
|
||||
enum {MAX_STRING_STORAGE_SIZE = 256};
|
||||
|
||||
private:
|
||||
char key_[MAX_STRING_STORAGE_SIZE];
|
||||
char value_[MAX_STRING_STORAGE_SIZE];
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// This class is not an efficient dictionary, but for the purposes of breakpad
|
||||
// will be just fine. We're just dealing with ten or so distinct
|
||||
// key/value pairs. The idea is to avoid any malloc() or free() calls
|
||||
// in certain important methods to be called when a process is in a
|
||||
// crashed state. Each key and value string are limited to
|
||||
// KeyValueEntry::MAX_STRING_STORAGE_SIZE-1 bytes (not glyphs). Strings passed
|
||||
// in exceeding this length will be truncated.
|
||||
//
|
||||
class SimpleStringDictionary {
|
||||
public:
|
||||
SimpleStringDictionary() {}; // entries will all be cleared
|
||||
|
||||
// Returns the number of active key/value pairs. The upper limit for this
|
||||
// is MAX_NUM_ENTRIES.
|
||||
int GetCount() const;
|
||||
|
||||
// Given |key|, returns its corresponding |value|.
|
||||
// If |key| is NULL, an assert will fire or NULL will be returned. If |key|
|
||||
// is not found or is an empty string, NULL is returned.
|
||||
const char *GetValueForKey(const char *key) const;
|
||||
|
||||
// Stores a string |value| represented by |key|. If |key| is NULL or an empty
|
||||
// string, this will assert (or do nothing). If |value| is NULL then
|
||||
// the |key| will be removed. An empty string is OK for |value|.
|
||||
void SetKeyValue(const char *key, const char *value);
|
||||
|
||||
// Given |key|, removes any associated value. It will assert (or do nothing)
|
||||
// if NULL is passed in. It will do nothing if |key| is not found.
|
||||
void RemoveKey(const char *key);
|
||||
|
||||
// This is the maximum number of key/value pairs which may be set in the
|
||||
// dictionary. An assert may fire if more values than this are set.
|
||||
// Don't change this without also changing comment in GoogleBreakpad.h
|
||||
enum {MAX_NUM_ENTRIES = 64};
|
||||
|
||||
private:
|
||||
friend class SimpleStringDictionaryIterator;
|
||||
|
||||
const KeyValueEntry *GetEntry(int i) const;
|
||||
|
||||
KeyValueEntry entries_[MAX_NUM_ENTRIES];
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class SimpleStringDictionaryIterator {
|
||||
public:
|
||||
SimpleStringDictionaryIterator(const SimpleStringDictionary &dict)
|
||||
: dict_(dict), i_(0) {
|
||||
}
|
||||
|
||||
// Initializes iterator to the beginning (may later call Next() )
|
||||
void Start() {
|
||||
i_ = 0;
|
||||
}
|
||||
|
||||
// like the nextObject method of NSEnumerator (in Cocoa)
|
||||
// returns NULL when there are no more entries
|
||||
//
|
||||
const KeyValueEntry* Next() {
|
||||
for (; i_ < SimpleStringDictionary::MAX_NUM_ENTRIES; ++i_) {
|
||||
const KeyValueEntry *entry = dict_.GetEntry(i_);
|
||||
if (entry->IsActive()) {
|
||||
i_++; // move to next entry for next time
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; // reached end of array
|
||||
}
|
||||
|
||||
private:
|
||||
const SimpleStringDictionary& dict_;
|
||||
int i_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // SimpleStringDictionary_H__
|
@@ -1,133 +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.
|
||||
//
|
||||
// SimpleStringDictionary.mm
|
||||
// Simple string dictionary that does not allocate memory
|
||||
//
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#import "SimpleStringDictionary.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
//==============================================================================
|
||||
const KeyValueEntry *SimpleStringDictionary::GetEntry(int i) const {
|
||||
return (i >= 0 && i < MAX_NUM_ENTRIES) ? &entries_[i] : NULL;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
int SimpleStringDictionary::GetCount() const {
|
||||
int count = 0;
|
||||
for (int i = 0; i < MAX_NUM_ENTRIES; ++i) {
|
||||
if (entries_[i].IsActive() ) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
const char *SimpleStringDictionary::GetValueForKey(const char *key) const {
|
||||
assert(key);
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
for (int i = 0; i < MAX_NUM_ENTRIES; ++i) {
|
||||
const KeyValueEntry &entry = entries_[i];
|
||||
if (entry.IsActive() && !strcmp(entry.GetKey(), key)) {
|
||||
return entry.GetValue();
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void SimpleStringDictionary::SetKeyValue(const char *key,
|
||||
const char *value) {
|
||||
if (!value) {
|
||||
RemoveKey(key);
|
||||
return;
|
||||
}
|
||||
|
||||
// key must not be NULL
|
||||
assert(key);
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
// key must not be empty string
|
||||
assert(key[0] != '\0');
|
||||
if (key[0] == '\0')
|
||||
return;
|
||||
|
||||
int free_index = -1;
|
||||
|
||||
// check if key already exists
|
||||
for (int i = 0; i < MAX_NUM_ENTRIES; ++i) {
|
||||
KeyValueEntry &entry = entries_[i];
|
||||
|
||||
if (entry.IsActive()) {
|
||||
if (!strcmp(entry.GetKey(), key)) {
|
||||
entry.SetValue(value);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// Make a note of an empty slot
|
||||
if (free_index == -1) {
|
||||
free_index = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check if we've run out of space
|
||||
assert(free_index != -1);
|
||||
|
||||
// Put new key into an empty slot (if found)
|
||||
if (free_index != -1) {
|
||||
entries_[free_index].SetKeyValue(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void SimpleStringDictionary::RemoveKey(const char *key) {
|
||||
assert(key);
|
||||
if (!key)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < MAX_NUM_ENTRIES; ++i) {
|
||||
if (!strcmp(entries_[i].GetKey(), key)) {
|
||||
entries_[i].Clear();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
113
thirdparty/breakpad/common/mac/arch_utilities.cc
vendored
Normal file
113
thirdparty/breakpad/common/mac/arch_utilities.cc
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// 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 <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef CPU_TYPE_ARM
|
||||
#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
|
||||
#endif // CPU_TYPE_ARM
|
||||
|
||||
#ifndef CPU_SUBTYPE_ARM_V7
|
||||
#define CPU_SUBTYPE_ARM_V7 (static_cast<cpu_subtype_t>(9))
|
||||
#endif // CPU_SUBTYPE_ARM_V7
|
||||
|
||||
#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 (static_cast<cpu_type_t>(16777228))
|
||||
#endif // CPU_TYPE_ARM64
|
||||
|
||||
#ifndef CPU_SUBTYPE_ARM64_ALL
|
||||
#define CPU_SUBTYPE_ARM64_ALL (static_cast<cpu_type_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
|
47
thirdparty/breakpad/common/mac/arch_utilities.h
vendored
Normal file
47
thirdparty/breakpad/common/mac/arch_utilities.h
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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__
|
27
thirdparty/breakpad/common/mac/dump_syms.h
vendored
27
thirdparty/breakpad/common/mac/dump_syms.h
vendored
@@ -47,13 +47,16 @@
|
||||
#include "common/byte_cursor.h"
|
||||
#include "common/mac/macho_reader.h"
|
||||
#include "common/module.h"
|
||||
#include "common/symbol_data.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class DumpSymbols {
|
||||
public:
|
||||
DumpSymbols()
|
||||
: input_pathname_(),
|
||||
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_(),
|
||||
selected_object_file_(),
|
||||
@@ -110,9 +113,14 @@ class DumpSymbols {
|
||||
}
|
||||
|
||||
// Read the selected object file's debugging information, and write it out to
|
||||
// |stream|. Write the CFI section if |cfi| is true. Return true on success;
|
||||
// if an error occurs, report it and return false.
|
||||
bool WriteSymbolFile(std::ostream &stream, bool cfi);
|
||||
// |stream|. Return true on success; if an error occurs, report it and
|
||||
// return false.
|
||||
bool WriteSymbolFile(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.
|
||||
@@ -127,7 +135,8 @@ class DumpSymbols {
|
||||
// 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) const;
|
||||
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,
|
||||
@@ -139,6 +148,12 @@ class DumpSymbols {
|
||||
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.
|
||||
NSString *input_pathname_;
|
||||
|
130
thirdparty/breakpad/common/mac/dump_syms.mm
vendored
130
thirdparty/breakpad/common/mac/dump_syms.mm
vendored
@@ -50,10 +50,13 @@
|
||||
#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))
|
||||
@@ -69,6 +72,7 @@ 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;
|
||||
@@ -191,7 +195,8 @@ bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
|
||||
|
||||
bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
|
||||
bool arch_set = false;
|
||||
const NXArchInfo *arch_info = NXGetArchInfoFromName(arch_name.c_str());
|
||||
const NXArchInfo *arch_info =
|
||||
google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str());
|
||||
if (arch_info) {
|
||||
arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype);
|
||||
}
|
||||
@@ -202,7 +207,8 @@ string DumpSymbols::Identifier() {
|
||||
FileID file_id([object_filename_ fileSystemRepresentation]);
|
||||
unsigned char identifier_bytes[16];
|
||||
cpu_type_t cpu_type = selected_object_file_->cputype;
|
||||
if (!file_id.MachoIdentifier(cpu_type, identifier_bytes)) {
|
||||
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_ fileSystemRepresentation]);
|
||||
return "";
|
||||
@@ -224,24 +230,31 @@ string DumpSymbols::Identifier() {
|
||||
// dwarf2reader::LineInfo and populates a Module and a line vector
|
||||
// with the results.
|
||||
class DumpSymbols::DumperLineToModule:
|
||||
public DwarfCUToModule::LineToModuleFunctor {
|
||||
public DwarfCUToModule::LineToModuleHandler {
|
||||
public:
|
||||
// Create a line-to-module converter using BYTE_READER.
|
||||
DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
|
||||
: byte_reader_(byte_reader) { }
|
||||
void operator()(const char *program, uint64 length,
|
||||
Module *module, vector<Module::Line> *lines) {
|
||||
DwarfLineToModule handler(module, lines);
|
||||
|
||||
void StartCompilationUnit(const string& compilation_dir) {
|
||||
compilation_dir_ = compilation_dir;
|
||||
}
|
||||
|
||||
void ReadProgram(const char *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::ReadDwarf(google_breakpad::Module *module,
|
||||
const mach_o::Reader &macho_reader,
|
||||
const mach_o::SectionMap &dwarf_sections) const {
|
||||
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
|
||||
@@ -249,19 +262,24 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
|
||||
|
||||
// Construct a context for this file.
|
||||
DwarfCUToModule::FileContext file_context(selected_object_name_,
|
||||
module);
|
||||
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.section_map[it->first] =
|
||||
make_pair(reinterpret_cast<const char *>(it->second.contents.start),
|
||||
it->second.contents.Size());
|
||||
it != dwarf_sections.end(); ++it) {
|
||||
file_context.AddSectionToSectionMap(
|
||||
it->first,
|
||||
reinterpret_cast<const char *>(it->second.contents.start),
|
||||
it->second.contents.Size());
|
||||
}
|
||||
|
||||
// Find the __debug_info section.
|
||||
std::pair<const char *, uint64> debug_info_section
|
||||
= file_context.section_map["__debug_info"];
|
||||
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 char*, 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",
|
||||
@@ -283,7 +301,7 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
|
||||
// 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(file_context.section_map,
|
||||
dwarf2reader::CompilationUnit dwarf_reader(file_context.section_map(),
|
||||
offset,
|
||||
&byte_reader,
|
||||
&die_dispatcher);
|
||||
@@ -312,9 +330,8 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
|
||||
register_names = DwarfCFIToModule::RegisterNames::ARM();
|
||||
break;
|
||||
default: {
|
||||
const NXArchInfo *arch =
|
||||
NXGetArchInfoFromCpuType(macho_reader.cpu_type(),
|
||||
macho_reader.cpu_subtype());
|
||||
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)
|
||||
@@ -362,8 +379,14 @@ class DumpSymbols::LoadCommandDumper:
|
||||
// file, and adding data to MODULE.
|
||||
LoadCommandDumper(const DumpSymbols &dumper,
|
||||
google_breakpad::Module *module,
|
||||
const mach_o::Reader &reader)
|
||||
: dumper_(dumper), module_(module), reader_(reader) { }
|
||||
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);
|
||||
@@ -372,6 +395,8 @@ class DumpSymbols::LoadCommandDumper:
|
||||
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) {
|
||||
@@ -381,23 +406,31 @@ bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
|
||||
|
||||
if (segment.name == "__TEXT") {
|
||||
module_->SetLoadAddress(segment.vmaddr);
|
||||
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);
|
||||
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 (!dumper_.ReadDwarf(module_, reader_, section_map))
|
||||
return false;
|
||||
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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -421,7 +454,7 @@ bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
|
||||
bool DumpSymbols::ReadSymbolData(Module** out_module) {
|
||||
// Select an object file, if SetArchitecture hasn't been called to set one
|
||||
// explicitly.
|
||||
if (!selected_object_file_) {
|
||||
@@ -446,9 +479,9 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
|
||||
|
||||
// Find the name of the selected file's architecture, to appear in
|
||||
// the MODULE record and in error messages.
|
||||
const NXArchInfo *selected_arch_info
|
||||
= NXGetArchInfoFromCpuType(selected_object_file_->cputype,
|
||||
selected_object_file_->cpusubtype);
|
||||
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)
|
||||
@@ -472,8 +505,10 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
|
||||
identifier += "0";
|
||||
|
||||
// Create a module to hold the debugging information.
|
||||
Module module([module_name UTF8String], "mac", selected_arch_name,
|
||||
identifier);
|
||||
scoped_ptr<Module> module(new Module([module_name UTF8String],
|
||||
"mac",
|
||||
selected_arch_name,
|
||||
identifier));
|
||||
|
||||
// Parse the selected object file.
|
||||
mach_o::Reader::Reporter reporter(selected_object_name_);
|
||||
@@ -486,11 +521,26 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
|
||||
return false;
|
||||
|
||||
// Walk its load commands, and deal with whatever is there.
|
||||
LoadCommandDumper load_command_dumper(*this, &module, reader);
|
||||
LoadCommandDumper load_command_dumper(*this, module.get(), reader,
|
||||
symbol_data_, handle_inter_cu_refs_);
|
||||
if (!reader.WalkLoadCommands(&load_command_dumper))
|
||||
return false;
|
||||
|
||||
return module.Write(stream, cfi);
|
||||
*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;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
14
thirdparty/breakpad/common/mac/file_id.cc
vendored
14
thirdparty/breakpad/common/mac/file_id.cc
vendored
@@ -70,13 +70,15 @@ bool FileID::FileIdentifier(unsigned char identifier[16]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileID::MachoIdentifier(int cpu_type, unsigned char identifier[16]) {
|
||||
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, identifier))
|
||||
if (macho.UUIDCommand(cpu_type, cpu_subtype, identifier))
|
||||
return true;
|
||||
|
||||
return macho.MD5(cpu_type, identifier);
|
||||
return macho.MD5(cpu_type, cpu_subtype, identifier);
|
||||
}
|
||||
|
||||
// static
|
||||
@@ -90,8 +92,10 @@ void FileID::ConvertIdentifierToString(const unsigned char identifier[16],
|
||||
if (idx == 4 || idx == 6 || idx == 8 || idx == 10)
|
||||
buffer[buffer_idx++] = '-';
|
||||
|
||||
buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi;
|
||||
buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo;
|
||||
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
|
||||
|
17
thirdparty/breakpad/common/mac/file_id.h
vendored
17
thirdparty/breakpad/common/mac/file_id.h
vendored
@@ -35,6 +35,7 @@
|
||||
#define COMMON_MAC_FILE_ID_H__
|
||||
|
||||
#include <limits.h>
|
||||
#include <mach/machine.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
@@ -50,15 +51,18 @@ class FileID {
|
||||
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| (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.
|
||||
// Returns false if opening the file failed or if the |cpu_type| is not
|
||||
// present in the file.
|
||||
// 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(int cpu_type, unsigned char identifier[16]);
|
||||
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).
|
||||
@@ -75,4 +79,3 @@ class FileID {
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_MAC_FILE_ID_H__
|
||||
|
||||
|
27
thirdparty/breakpad/common/mac/macho_id.cc
vendored
27
thirdparty/breakpad/common/mac/macho_id.cc
vendored
@@ -153,10 +153,12 @@ void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) {
|
||||
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, UUIDWalkerCB, &uuid_cmd))
|
||||
if (!WalkHeader(cpu_type, cpu_subtype, UUIDWalkerCB, &uuid_cmd))
|
||||
return false;
|
||||
|
||||
// If we found the command, we'll have initialized the uuid_command
|
||||
@@ -169,10 +171,12 @@ bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) {
|
||||
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, IDWalkerCB, &dylib_cmd))
|
||||
if (!WalkHeader(cpu_type, cpu_subtype, IDWalkerCB, &dylib_cmd))
|
||||
return false;
|
||||
|
||||
// If we found the command, we'll have initialized the dylib_command
|
||||
@@ -210,37 +214,38 @@ bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t MachoID::Adler32(int cpu_type) {
|
||||
uint32_t MachoID::Adler32(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
|
||||
update_function_ = &MachoID::UpdateCRC;
|
||||
crc_ = 0;
|
||||
|
||||
if (!WalkHeader(cpu_type, WalkerCB, this))
|
||||
if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
|
||||
return 0;
|
||||
|
||||
return crc_;
|
||||
}
|
||||
|
||||
bool MachoID::MD5(int cpu_type, unsigned char identifier[16]) {
|
||||
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, WalkerCB, this))
|
||||
if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
|
||||
return false;
|
||||
|
||||
MD5Final(identifier, &md5_context_);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MachoID::WalkHeader(int cpu_type,
|
||||
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);
|
||||
return walker.WalkHeader(cpu_type, cpu_subtype);
|
||||
} else {
|
||||
MachoWalker walker(path_, callback, context);
|
||||
return walker.WalkHeader(cpu_type);
|
||||
return walker.WalkHeader(cpu_type, cpu_subtype);
|
||||
}
|
||||
}
|
||||
|
||||
|
33
thirdparty/breakpad/common/mac/macho_id.h
vendored
33
thirdparty/breakpad/common/mac/macho_id.h
vendored
@@ -35,6 +35,7 @@
|
||||
#define COMMON_MAC_MACHO_ID_H__
|
||||
|
||||
#include <limits.h>
|
||||
#include <mach/machine.h>
|
||||
#include <mach-o/loader.h>
|
||||
|
||||
#include "common/mac/macho_walker.h"
|
||||
@@ -48,22 +49,32 @@ class MachoID {
|
||||
MachoID(const char *path, void *memory, size_t size);
|
||||
~MachoID();
|
||||
|
||||
// For the given |cpu_type|, return a UUID from the LC_UUID command.
|
||||
// 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(int cpu_type, unsigned char identifier[16]);
|
||||
bool UUIDCommand(cpu_type_t cpu_type,
|
||||
cpu_subtype_t cpu_subtype,
|
||||
unsigned char identifier[16]);
|
||||
|
||||
// For the given |cpu_type|, return a UUID from the LC_ID_DYLIB command.
|
||||
// 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(int cpu_type, unsigned char identifier[16]);
|
||||
bool IDCommand(cpu_type_t cpu_type,
|
||||
cpu_subtype_t cpu_subtype,
|
||||
unsigned char identifier[16]);
|
||||
|
||||
// For the given |cpu_type|, return the Adler32 CRC for the mach-o data
|
||||
// segment(s).
|
||||
// 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(int cpu_type);
|
||||
uint32_t Adler32(cpu_type_t cpu_type,
|
||||
cpu_subtype_t cpu_subtype);
|
||||
|
||||
// For the given |cpu_type|, return the MD5 for the mach-o data segment(s).
|
||||
// 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(int cpu_type, unsigned char identifier[16]);
|
||||
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
|
||||
@@ -81,8 +92,8 @@ class MachoID {
|
||||
void Update(MachoWalker *walker, off_t offset, size_t size);
|
||||
|
||||
// Factory for the MachoWalker
|
||||
bool WalkHeader(int cpu_type, MachoWalker::LoadCommandCallback callback,
|
||||
void *context);
|
||||
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,
|
||||
|
@@ -43,6 +43,10 @@
|
||||
#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 {
|
||||
|
||||
@@ -242,6 +246,7 @@ bool Reader::Read(const uint8_t *buffer,
|
||||
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;
|
||||
|
@@ -54,14 +54,6 @@
|
||||
# define LC_UUID 0x1b /* the uuid */
|
||||
#endif
|
||||
|
||||
#if TARGET_CPU_X86
|
||||
# define BREAKPAD_MACHINE_THREAD_STATE i386_THREAD_STATE
|
||||
#elif TARGET_CPU_X86_64
|
||||
# define BREAKPAD_MACHINE_THREAD_STATE x86_THREAD_STATE64
|
||||
#else
|
||||
# define BREAKPAD_MACHINE_THREAD_STATE MACHINE_THREAD_STATE
|
||||
#endif
|
||||
|
||||
// The uuid_command struct/swap routines were added during the 10.4 series.
|
||||
// Their presence isn't guaranteed.
|
||||
struct breakpad_uuid_command {
|
||||
|
39
thirdparty/breakpad/common/mac/macho_walker.cc
vendored
39
thirdparty/breakpad/common/mac/macho_walker.cc
vendored
@@ -79,21 +79,18 @@ MachoWalker::~MachoWalker() {
|
||||
close(file_);
|
||||
}
|
||||
|
||||
int MachoWalker::ValidateCPUType(int cpu_type) {
|
||||
// If the user didn't specify, use the local architecture.
|
||||
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);
|
||||
cpu_type = arch->cputype;
|
||||
valid_cpu_type = arch->cputype;
|
||||
valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE;
|
||||
}
|
||||
|
||||
return cpu_type;
|
||||
}
|
||||
|
||||
bool MachoWalker::WalkHeader(int cpu_type) {
|
||||
int valid_cpu_type = ValidateCPUType(cpu_type);
|
||||
off_t offset;
|
||||
if (FindHeader(valid_cpu_type, offset)) {
|
||||
if (FindHeader(valid_cpu_type, valid_cpu_subtype, offset)) {
|
||||
if (cpu_type & CPU_ARCH_ABI64)
|
||||
return WalkHeader64AtOffset(offset);
|
||||
|
||||
@@ -111,7 +108,7 @@ bool MachoWalker::ReadBytes(void *buffer, size_t size, off_t offset) {
|
||||
if (offset + size > memory_size_) {
|
||||
if (static_cast<size_t>(offset) >= memory_size_)
|
||||
return false;
|
||||
size = memory_size_ - offset;
|
||||
size = memory_size_ - static_cast<size_t>(offset);
|
||||
result = false;
|
||||
}
|
||||
memcpy(buffer, static_cast<char *>(memory_) + offset, size);
|
||||
@@ -131,8 +128,9 @@ bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
|
||||
int valid_cpu_type = ValidateCPUType(cpu_type);
|
||||
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))
|
||||
@@ -153,15 +151,18 @@ bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
|
||||
if (!is_fat) {
|
||||
// If we don't have a fat header, check if the cpu type matches the single
|
||||
// header
|
||||
cpu_type_t header_cpu_type;
|
||||
if (!ReadBytes(&header_cpu_type, sizeof(header_cpu_type), offset))
|
||||
struct mach_header header;
|
||||
if (!ReadBytes(&header, sizeof(header), 0))
|
||||
return false;
|
||||
|
||||
if (magic == MH_CIGAM || magic == MH_CIGAM_64)
|
||||
header_cpu_type = ByteSwap(header_cpu_type);
|
||||
swap_mach_header(&header, NXHostByteOrder());
|
||||
|
||||
if (valid_cpu_type != header_cpu_type)
|
||||
if (cpu_type != header.cputype ||
|
||||
(cpu_subtype != CPU_SUBTYPE_MULTIPLE &&
|
||||
cpu_subtype != header.cpusubtype)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
return true;
|
||||
@@ -186,7 +187,9 @@ bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
|
||||
if (NXHostByteOrder() != NX_BigEndian)
|
||||
swap_fat_arch(&arch, 1, NXHostByteOrder());
|
||||
|
||||
if (arch.cputype == valid_cpu_type) {
|
||||
if (arch.cputype == cpu_type &&
|
||||
(cpu_subtype == CPU_SUBTYPE_MULTIPLE ||
|
||||
arch.cpusubtype == cpu_subtype)) {
|
||||
offset = arch.offset;
|
||||
return true;
|
||||
}
|
||||
|
26
thirdparty/breakpad/common/mac/macho_walker.h
vendored
26
thirdparty/breakpad/common/mac/macho_walker.h
vendored
@@ -34,6 +34,7 @@
|
||||
#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>
|
||||
|
||||
@@ -56,16 +57,14 @@ class MachoWalker {
|
||||
void *context);
|
||||
~MachoWalker();
|
||||
|
||||
// Begin walking the header for |cpu_type|. 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).
|
||||
// Returns false if opening the file failed or if the |cpu_type| is not
|
||||
// present in the file.
|
||||
bool WalkHeader(int cpu_type);
|
||||
|
||||
// Locate (if any) the header offset for |cpu_type| and return in |offset|.
|
||||
// Return true if found, false otherwise.
|
||||
bool FindHeader(int cpu_type, off_t &offset);
|
||||
// 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);
|
||||
@@ -74,8 +73,11 @@ class MachoWalker {
|
||||
bool CurrentHeader(struct mach_header_64 *header, off_t *offset);
|
||||
|
||||
private:
|
||||
// Validate the |cpu_type|
|
||||
int ValidateCPUType(int cpu_type);
|
||||
// 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.
|
||||
|
@@ -27,7 +27,7 @@
|
||||
// (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 "processor/scoped_ptr.h"
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "common/mac/string_utilities.h"
|
||||
|
||||
namespace MacStringUtils {
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -17,13 +17,20 @@
|
||||
//
|
||||
|
||||
#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
|
||||
#import "GTMGarbageCollection.h"
|
||||
#endif // !GTM_IPHONE_SDK
|
||||
|
||||
#if GTM_IPHONE_SDK
|
||||
#if GTM_IPHONE_SDK && !GTM_IPHONE_USE_SENTEST
|
||||
#import <stdarg.h>
|
||||
|
||||
@interface NSException (GTMSenTestPrivateAdditions)
|
||||
@@ -84,7 +91,7 @@
|
||||
}
|
||||
|
||||
NSString *reason = [NSString stringWithFormat:@"'%@' should be %s. %@",
|
||||
condition, isTrue ? "TRUE" : "FALSE", testDescription];
|
||||
condition, isTrue ? "false" : "true", testDescription];
|
||||
|
||||
return [self failureInFile:filename atLine:lineNumber reason:reason];
|
||||
}
|
||||
@@ -213,6 +220,22 @@ NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
|
||||
@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];
|
||||
}
|
||||
@@ -220,17 +243,24 @@ NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
|
||||
- (void)setUp {
|
||||
}
|
||||
|
||||
- (void)performTest:(SEL)sel {
|
||||
currentSelector_ = sel;
|
||||
- (void)performTest {
|
||||
@try {
|
||||
[self invokeTest];
|
||||
} @catch (NSException *exception) {
|
||||
[[self class] printException:exception
|
||||
fromTestName:NSStringFromSelector(sel)];
|
||||
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];
|
||||
@@ -261,7 +291,17 @@ NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
|
||||
@try {
|
||||
[self setUp];
|
||||
@try {
|
||||
[self performSelector:currentSelector_];
|
||||
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];
|
||||
}
|
||||
@@ -284,15 +324,84 @@ NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
|
||||
|
||||
- (NSString *)description {
|
||||
// This matches the description OCUnit would return to you
|
||||
return [NSString stringWithFormat:@"-[%@ %@]", [self class],
|
||||
NSStringFromSelector(currentSelector_)];
|
||||
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
|
||||
#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)];
|
||||
@@ -304,19 +413,34 @@ NSString *const SenTestLineNumberKey = @"SenTestLineNumberKey";
|
||||
[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
|
||||
|
||||
// Leak detection
|
||||
#if !GTM_IPHONE_DEVICE
|
||||
#if !GTM_IPHONE_DEVICE && !GTM_SUPPRESS_RUN_LEAKS_HOOK
|
||||
// Don't want to get leaks on the iPhone Device as the device doesn't
|
||||
// have 'leaks'. The simulator does though.
|
||||
|
||||
// COV_NF_START
|
||||
// We don't have leak checking on by default, so this won't be hit.
|
||||
static void _GTMRunLeaks(void) {
|
||||
// This is an atexit handler. It runs leaks for us to check if we are
|
||||
// leaking anything in our tests.
|
||||
// This is an atexit handler. It runs leaks for us to check if we are
|
||||
// leaking anything in our tests.
|
||||
const char* cExclusionsEnv = getenv("GTM_LEAKS_SYMBOLS_TO_IGNORE");
|
||||
NSMutableString *exclusions = [NSMutableString string];
|
||||
if (cExclusionsEnv) {
|
||||
@@ -329,13 +453,21 @@ static void _GTMRunLeaks(void) {
|
||||
[exclusions appendFormat:@"-exclude \"%@\" ", exclusion];
|
||||
}
|
||||
}
|
||||
NSString *string
|
||||
= [NSString stringWithFormat:@"/usr/bin/leaks %@%d"
|
||||
@"| /usr/bin/sed -e 's/Leak: /Leaks:0: warning: Leak /'",
|
||||
// Clearing out DYLD_ROOT_PATH because iPhone Simulator framework libraries
|
||||
// are different from regular OS X libraries and leaks will fail to run
|
||||
// because of missing symbols. Also capturing the output of leaks and then
|
||||
// pipe rather than a direct pipe, because otherwise if leaks failed,
|
||||
// the system() call will still be successful. Bug:
|
||||
// http://code.google.com/p/google-toolbox-for-mac/issues/detail?id=56
|
||||
NSString *string
|
||||
= [NSString stringWithFormat:
|
||||
@"LeakOut=`DYLD_ROOT_PATH='' /usr/bin/leaks %@%d` &&"
|
||||
@"echo \"$LeakOut\"|/usr/bin/sed -e 's/Leak: /Leaks:0: warning: Leak /'",
|
||||
exclusions, getpid()];
|
||||
int ret = system([string UTF8String]);
|
||||
if (ret) {
|
||||
fprintf(stderr, "%s:%d: Error: Unable to run leaks. 'system' returned: %d",
|
||||
fprintf(stderr,
|
||||
"%s:%d: Error: Unable to run leaks. 'system' returned: %d\n",
|
||||
__FILE__, __LINE__, ret);
|
||||
fflush(stderr);
|
||||
}
|
||||
@@ -355,12 +487,14 @@ static __attribute__((constructor)) void _GTMInstallLeaks(void) {
|
||||
fprintf(stderr, "Leak Checking Enabled\n");
|
||||
fflush(stderr);
|
||||
int ret = atexit(&_GTMRunLeaks);
|
||||
_GTMDevAssert(ret == 0,
|
||||
@"Unable to install _GTMRunLeaks as an atexit handler (%d)",
|
||||
// To avoid unused variable warning when _GTMDevAssert is stripped.
|
||||
(void)ret;
|
||||
_GTMDevAssert(ret == 0,
|
||||
@"Unable to install _GTMRunLeaks as an atexit handler (%d)",
|
||||
errno);
|
||||
// COV_NF_END
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !GTM_IPHONE_DEVICE
|
||||
#endif // !GTM_IPHONE_DEVICE && !GTM_SUPPRESS_RUN_LEAKS_HOOK
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user