Added submodule contents into tree
This commit is contained in:
parent
01a752555c
commit
9b991208cd
4934 changed files with 1657477 additions and 5 deletions
9
externals/breakpad/src/common/android/include/asm-mips/README.md
vendored
Normal file
9
externals/breakpad/src/common/android/include/asm-mips/README.md
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# asm-mips
|
||||
|
||||
The files in this directory are almost direct copies from Android NDK r12, with
|
||||
the exception of changing the include guards to Breakpad ones. They are copied
|
||||
from the MIPS asm/ directory, but are meant to be used as replacements for both
|
||||
asm/ and machine/ includes since the files in each are largely duplicates.
|
||||
|
||||
Some MIPS asm/ and all machine/ headers were removed in the move to unified NDK
|
||||
headers, so Breakpad fails to compile on newer NDK versions without these files.
|
||||
270
externals/breakpad/src/common/android/include/asm-mips/asm.h
vendored
Normal file
270
externals/breakpad/src/common/android/include/asm-mips/asm.h
vendored
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_ASM_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_ASM_H
|
||||
|
||||
#if defined(__has_include_next) && __has_include_next(<asm/asm.h>)
|
||||
#include_next <asm/asm.h>
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
****************************************************************************
|
||||
***
|
||||
*** This header was automatically generated from a Linux kernel header
|
||||
*** of the same name, to make information necessary for userspace to
|
||||
*** call into the kernel available to libc. It contains only constants,
|
||||
*** structures, and macros generated from the original header, and thus,
|
||||
*** contains no copyrightable information.
|
||||
***
|
||||
*** To edit the content of this header, modify the corresponding
|
||||
*** source file (e.g. under external/kernel-headers/original/) then
|
||||
*** run bionic/libc/kernel/tools/update_all.py
|
||||
***
|
||||
*** Any manual change here will be lost the next time this script will
|
||||
*** be run. You've been warned!
|
||||
***
|
||||
****************************************************************************
|
||||
****************************************************************************/
|
||||
|
||||
#include <asm/sgidefs.h>
|
||||
#ifndef CAT
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#ifdef __STDC__
|
||||
#define __CAT(str1, str2) str1##str2
|
||||
#else
|
||||
#define __CAT(str1, str2) str1 str2
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#define CAT(str1, str2) __CAT(str1, str2)
|
||||
#endif
|
||||
#ifdef __PIC__
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define CPRESTORE(register) .cprestore register
|
||||
#define CPADD(register) .cpadd register
|
||||
#define CPLOAD(register) .cpload register
|
||||
#else
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define CPRESTORE(register)
|
||||
#define CPADD(register)
|
||||
#define CPLOAD(register)
|
||||
#endif
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LEAF(symbol) .globl symbol; .align 2; .type symbol, @function; .ent symbol, 0; symbol: .frame sp, 0, ra
|
||||
#define NESTED(symbol, framesize, rpc) .globl symbol; .align 2; .type symbol, @function; .ent symbol, 0; symbol: .frame sp, framesize, rpc
|
||||
#define END(function) .end function; .size function, .-function
|
||||
#define EXPORT(symbol) .globl symbol; symbol:
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define FEXPORT(symbol) .globl symbol; .type symbol, @function; symbol:
|
||||
#define ABS(symbol,value) .globl symbol; symbol = value
|
||||
#define PANIC(msg) .set push; .set reorder; PTR_LA a0, 8f; jal panic; 9: b 9b; .set pop; TEXT(msg)
|
||||
#define PRINT(string)
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define TEXT(msg) .pushsection .data; 8: .asciiz msg; .popsection;
|
||||
#define TTABLE(string) .pushsection .text; .word 1f; .popsection .pushsection .data; 1: .asciiz string; .popsection
|
||||
#define PREF(hint, addr)
|
||||
#define PREFX(hint, addr)
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#if _MIPS_ISA == _MIPS_ISA_MIPS1
|
||||
#define MOVN(rd, rs, rt) .set push; .set reorder; beqz rt, 9f; move rd, rs; .set pop; 9:
|
||||
#define MOVZ(rd, rs, rt) .set push; .set reorder; bnez rt, 9f; move rd, rs; .set pop; 9:
|
||||
#endif
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#if _MIPS_ISA == _MIPS_ISA_MIPS2 || _MIPS_ISA == _MIPS_ISA_MIPS3
|
||||
#define MOVN(rd, rs, rt) .set push; .set noreorder; bnezl rt, 9f; move rd, rs; .set pop; 9:
|
||||
#define MOVZ(rd, rs, rt) .set push; .set noreorder; beqzl rt, 9f; move rd, rs; .set pop; 9:
|
||||
#endif
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#if _MIPS_ISA == _MIPS_ISA_MIPS4 || _MIPS_ISA == _MIPS_ISA_MIPS5 || _MIPS_ISA == _MIPS_ISA_MIPS32 || _MIPS_ISA == _MIPS_ISA_MIPS64
|
||||
#define MOVN(rd, rs, rt) movn rd, rs, rt
|
||||
#define MOVZ(rd, rs, rt) movz rd, rs, rt
|
||||
#endif
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
#define ALSZ 7
|
||||
#define ALMASK ~7
|
||||
#endif
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#if _MIPS_SIM == _MIPS_SIM_NABI32 || _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
#define ALSZ 15
|
||||
#define ALMASK ~15
|
||||
#endif
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#ifdef __mips64
|
||||
#define SZREG 8
|
||||
#else
|
||||
#define SZREG 4
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
#define REG_S sw
|
||||
#define REG_L lw
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define REG_SUBU subu
|
||||
#define REG_ADDU addu
|
||||
#endif
|
||||
#if _MIPS_SIM == _MIPS_SIM_NABI32 || _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define REG_S sd
|
||||
#define REG_L ld
|
||||
#define REG_SUBU dsubu
|
||||
#define REG_ADDU daddu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SZINT == 32
|
||||
#define INT_ADD add
|
||||
#define INT_ADDU addu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define INT_ADDI addi
|
||||
#define INT_ADDIU addiu
|
||||
#define INT_SUB sub
|
||||
#define INT_SUBU subu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define INT_L lw
|
||||
#define INT_S sw
|
||||
#define INT_SLL sll
|
||||
#define INT_SLLV sllv
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define INT_SRL srl
|
||||
#define INT_SRLV srlv
|
||||
#define INT_SRA sra
|
||||
#define INT_SRAV srav
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SZINT == 64
|
||||
#define INT_ADD dadd
|
||||
#define INT_ADDU daddu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define INT_ADDI daddi
|
||||
#define INT_ADDIU daddiu
|
||||
#define INT_SUB dsub
|
||||
#define INT_SUBU dsubu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define INT_L ld
|
||||
#define INT_S sd
|
||||
#define INT_SLL dsll
|
||||
#define INT_SLLV dsllv
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define INT_SRL dsrl
|
||||
#define INT_SRLV dsrlv
|
||||
#define INT_SRA dsra
|
||||
#define INT_SRAV dsrav
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SZLONG == 32
|
||||
#define LONG_ADD add
|
||||
#define LONG_ADDU addu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG_ADDI addi
|
||||
#define LONG_ADDIU addiu
|
||||
#define LONG_SUB sub
|
||||
#define LONG_SUBU subu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG_L lw
|
||||
#define LONG_S sw
|
||||
#define LONG_SLL sll
|
||||
#define LONG_SLLV sllv
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG_SRL srl
|
||||
#define LONG_SRLV srlv
|
||||
#define LONG_SRA sra
|
||||
#define LONG_SRAV srav
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG .word
|
||||
#define LONGSIZE 4
|
||||
#define LONGMASK 3
|
||||
#define LONGLOG 2
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SZLONG == 64
|
||||
#define LONG_ADD dadd
|
||||
#define LONG_ADDU daddu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG_ADDI daddi
|
||||
#define LONG_ADDIU daddiu
|
||||
#define LONG_SUB dsub
|
||||
#define LONG_SUBU dsubu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG_L ld
|
||||
#define LONG_S sd
|
||||
#define LONG_SLL dsll
|
||||
#define LONG_SLLV dsllv
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG_SRL dsrl
|
||||
#define LONG_SRLV dsrlv
|
||||
#define LONG_SRA dsra
|
||||
#define LONG_SRAV dsrav
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define LONG .dword
|
||||
#define LONGSIZE 8
|
||||
#define LONGMASK 7
|
||||
#define LONGLOG 3
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SZPTR == 32
|
||||
#define PTR_ADD add
|
||||
#define PTR_ADDU addu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_ADDI addi
|
||||
#define PTR_ADDIU addiu
|
||||
#define PTR_SUB sub
|
||||
#define PTR_SUBU subu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_L lw
|
||||
#define PTR_S sw
|
||||
#define PTR_LA la
|
||||
#define PTR_LI li
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_SLL sll
|
||||
#define PTR_SLLV sllv
|
||||
#define PTR_SRL srl
|
||||
#define PTR_SRLV srlv
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_SRA sra
|
||||
#define PTR_SRAV srav
|
||||
#define PTR_SCALESHIFT 2
|
||||
#define PTR .word
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTRSIZE 4
|
||||
#define PTRLOG 2
|
||||
#endif
|
||||
#if _MIPS_SZPTR == 64
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_ADD dadd
|
||||
#define PTR_ADDU daddu
|
||||
#define PTR_ADDI daddi
|
||||
#define PTR_ADDIU daddiu
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_SUB dsub
|
||||
#define PTR_SUBU dsubu
|
||||
#define PTR_L ld
|
||||
#define PTR_S sd
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_LA dla
|
||||
#define PTR_LI dli
|
||||
#define PTR_SLL dsll
|
||||
#define PTR_SLLV dsllv
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_SRL dsrl
|
||||
#define PTR_SRLV dsrlv
|
||||
#define PTR_SRA dsra
|
||||
#define PTR_SRAV dsrav
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define PTR_SCALESHIFT 3
|
||||
#define PTR .dword
|
||||
#define PTRSIZE 8
|
||||
#define PTRLOG 3
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
#define MFC0 mfc0
|
||||
#define MTC0 mtc0
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#if _MIPS_SIM == _MIPS_SIM_NABI32 || _MIPS_SIM == _MIPS_SIM_ABI64
|
||||
#define MFC0 dmfc0
|
||||
#define MTC0 dmtc0
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#define SSNOP sll zero, zero, 1
|
||||
#define R10KCBARRIER(addr)
|
||||
#endif // defined(__has_include_next) && __has_include_next(<asm/asm.h>)
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_ASM_H
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
117
externals/breakpad/src/common/android/include/asm-mips/fpregdef.h
vendored
Normal file
117
externals/breakpad/src/common/android/include/asm-mips/fpregdef.h
vendored
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_FPREGDEF_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_FPREGDEF_H
|
||||
|
||||
#if defined(__has_include_next) && __has_include_next(<asm/fpregdef.h>)
|
||||
#include_next <asm/fpregdef.h>
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
****************************************************************************
|
||||
***
|
||||
*** This header was automatically generated from a Linux kernel header
|
||||
*** of the same name, to make information necessary for userspace to
|
||||
*** call into the kernel available to libc. It contains only constants,
|
||||
*** structures, and macros generated from the original header, and thus,
|
||||
*** contains no copyrightable information.
|
||||
***
|
||||
*** To edit the content of this header, modify the corresponding
|
||||
*** source file (e.g. under external/kernel-headers/original/) then
|
||||
*** run bionic/libc/kernel/tools/update_all.py
|
||||
***
|
||||
*** Any manual change here will be lost the next time this script will
|
||||
*** be run. You've been warned!
|
||||
***
|
||||
****************************************************************************
|
||||
****************************************************************************/
|
||||
|
||||
#include <asm/sgidefs.h>
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fv0 $f0
|
||||
#define fv0f $f1
|
||||
#define fv1 $f2
|
||||
#define fv1f $f3
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fa0 $f12
|
||||
#define fa0f $f13
|
||||
#define fa1 $f14
|
||||
#define fa1f $f15
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define ft0 $f4
|
||||
#define ft0f $f5
|
||||
#define ft1 $f6
|
||||
#define ft1f $f7
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define ft2 $f8
|
||||
#define ft2f $f9
|
||||
#define ft3 $f10
|
||||
#define ft3f $f11
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define ft4 $f16
|
||||
#define ft4f $f17
|
||||
#define ft5 $f18
|
||||
#define ft5f $f19
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fs0 $f20
|
||||
#define fs0f $f21
|
||||
#define fs1 $f22
|
||||
#define fs1f $f23
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fs2 $f24
|
||||
#define fs2f $f25
|
||||
#define fs3 $f26
|
||||
#define fs3f $f27
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fs4 $f28
|
||||
#define fs4f $f29
|
||||
#define fs5 $f30
|
||||
#define fs5f $f31
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fcr31 $31
|
||||
#endif
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
|
||||
#define fv0 $f0
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fv1 $f2
|
||||
#define fa0 $f12
|
||||
#define fa1 $f13
|
||||
#define fa2 $f14
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fa3 $f15
|
||||
#define fa4 $f16
|
||||
#define fa5 $f17
|
||||
#define fa6 $f18
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fa7 $f19
|
||||
#define ft0 $f4
|
||||
#define ft1 $f5
|
||||
#define ft2 $f6
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define ft3 $f7
|
||||
#define ft4 $f8
|
||||
#define ft5 $f9
|
||||
#define ft6 $f10
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define ft7 $f11
|
||||
#define ft8 $f20
|
||||
#define ft9 $f21
|
||||
#define ft10 $f22
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define ft11 $f23
|
||||
#define ft12 $f1
|
||||
#define ft13 $f3
|
||||
#define fs0 $f24
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fs1 $f25
|
||||
#define fs2 $f26
|
||||
#define fs3 $f27
|
||||
#define fs4 $f28
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define fs5 $f29
|
||||
#define fs6 $f30
|
||||
#define fs7 $f31
|
||||
#define fcr31 $31
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#endif
|
||||
#endif // defined(__has_include_next) && __has_include_next(<asm/fpregdef.h>)
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_FPREGDEF_H
|
||||
125
externals/breakpad/src/common/android/include/asm-mips/regdef.h
vendored
Normal file
125
externals/breakpad/src/common/android/include/asm-mips/regdef.h
vendored
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_REGDEF_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_REGDEF_H
|
||||
|
||||
#if defined(__has_include_next) && __has_include_next(<asm/regdef.h>)
|
||||
#include_next <asm/regdef.h>
|
||||
#else
|
||||
|
||||
/****************************************************************************
|
||||
****************************************************************************
|
||||
***
|
||||
*** This header was automatically generated from a Linux kernel header
|
||||
*** of the same name, to make information necessary for userspace to
|
||||
*** call into the kernel available to libc. It contains only constants,
|
||||
*** structures, and macros generated from the original header, and thus,
|
||||
*** contains no copyrightable information.
|
||||
***
|
||||
*** To edit the content of this header, modify the corresponding
|
||||
*** source file (e.g. under external/kernel-headers/original/) then
|
||||
*** run bionic/libc/kernel/tools/update_all.py
|
||||
***
|
||||
*** Any manual change here will be lost the next time this script will
|
||||
*** be run. You've been warned!
|
||||
***
|
||||
****************************************************************************
|
||||
****************************************************************************/
|
||||
|
||||
#include <asm/sgidefs.h>
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI32
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define zero $0
|
||||
#define AT $1
|
||||
#define v0 $2
|
||||
#define v1 $3
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define a0 $4
|
||||
#define a1 $5
|
||||
#define a2 $6
|
||||
#define a3 $7
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define t0 $8
|
||||
#define t1 $9
|
||||
#define t2 $10
|
||||
#define t3 $11
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define t4 $12
|
||||
#define t5 $13
|
||||
#define t6 $14
|
||||
#define t7 $15
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define s0 $16
|
||||
#define s1 $17
|
||||
#define s2 $18
|
||||
#define s3 $19
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define s4 $20
|
||||
#define s5 $21
|
||||
#define s6 $22
|
||||
#define s7 $23
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define t8 $24
|
||||
#define t9 $25
|
||||
#define jp $25
|
||||
#define k0 $26
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define k1 $27
|
||||
#define gp $28
|
||||
#define sp $29
|
||||
#define fp $30
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define s8 $30
|
||||
#define ra $31
|
||||
#endif
|
||||
#if _MIPS_SIM == _MIPS_SIM_ABI64 || _MIPS_SIM == _MIPS_SIM_NABI32
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define zero $0
|
||||
#define AT $at
|
||||
#define v0 $2
|
||||
#define v1 $3
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define a0 $4
|
||||
#define a1 $5
|
||||
#define a2 $6
|
||||
#define a3 $7
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define a4 $8
|
||||
#define ta0 $8
|
||||
#define a5 $9
|
||||
#define ta1 $9
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define a6 $10
|
||||
#define ta2 $10
|
||||
#define a7 $11
|
||||
#define ta3 $11
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define t0 $12
|
||||
#define t1 $13
|
||||
#define t2 $14
|
||||
#define t3 $15
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define s0 $16
|
||||
#define s1 $17
|
||||
#define s2 $18
|
||||
#define s3 $19
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define s4 $20
|
||||
#define s5 $21
|
||||
#define s6 $22
|
||||
#define s7 $23
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define t8 $24
|
||||
#define t9 $25
|
||||
#define jp $25
|
||||
#define k0 $26
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define k1 $27
|
||||
#define gp $28
|
||||
#define sp $29
|
||||
#define fp $30
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
#define s8 $30
|
||||
#define ra $31
|
||||
#endif
|
||||
#endif // defined(__has_include_next) && __has_include_next(<asm/regdef.h>)
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_ASM_MIPS_REGDEF_H
|
||||
/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
|
||||
156
externals/breakpad/src/common/android/include/elf.h
vendored
Normal file
156
externals/breakpad/src/common/android/include/elf.h
vendored
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC 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;
|
||||
|
||||
|
||||
// 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
|
||||
76
externals/breakpad/src/common/android/include/link.h
vendored
Normal file
76
externals/breakpad/src/common/android/include/link.h
vendored
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_ANDROID_INCLUDE_LINK_H
|
||||
#define GOOGLE_BREAKPAD_ANDROID_INCLUDE_LINK_H
|
||||
|
||||
/* Android doesn't provide all the data-structures required in its <link.h>.
|
||||
Provide custom version here. */
|
||||
#include_next <link.h>
|
||||
|
||||
#include <android/api-level.h>
|
||||
|
||||
// TODO(rmcilroy): Remove this file once the NDK API level is updated to at
|
||||
// least 21 for all architectures. https://crbug.com/358831
|
||||
|
||||
// These structures are only present in traditional headers at API level 21 and
|
||||
// above. Unified headers define these structures regardless of the chosen API
|
||||
// level. __ANDROID_API_N__ is a proxy for determining whether unified headers
|
||||
// are in use. It’s only defined by unified headers.
|
||||
#if __ANDROID_API__ < 21 && !defined(__ANDROID_API_N__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
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 // __ANDROID_API__ < 21 && !defined(__ANDROID_API_N__)
|
||||
|
||||
#endif /* GOOGLE_BREAKPAD_ANDROID_INCLUDE_LINK_H */
|
||||
99
externals/breakpad/src/common/android/include/stab.h
vendored
Normal file
99
externals/breakpad/src/common/android/include/stab.h
vendored
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC 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
|
||||
123
externals/breakpad/src/common/android/include/sys/procfs.h
vendored
Normal file
123
externals/breakpad/src/common/android/include/sys/procfs.h
vendored
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_SYS_PROCFS_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_ANDROID_SYS_PROCFS_H
|
||||
|
||||
#ifdef __BIONIC_HAVE_SYS_PROCFS_H
|
||||
|
||||
#include_next <sys/procfs.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <asm/ptrace.h>
|
||||
#include <sys/cdefs.h>
|
||||
#if defined (__mips__)
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <sys/user.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#if defined(__x86_64__) || defined(__aarch64__)
|
||||
typedef unsigned long long elf_greg_t;
|
||||
#else
|
||||
typedef unsigned long elf_greg_t;
|
||||
#endif
|
||||
|
||||
#ifdef __arm__
|
||||
#define ELF_NGREG (sizeof(struct user_regs) / sizeof(elf_greg_t))
|
||||
#elif defined(__aarch64__)
|
||||
#define ELF_NGREG (sizeof(struct user_pt_regs) / sizeof(elf_greg_t))
|
||||
#elif defined(__mips__)
|
||||
#define ELF_NGREG 45
|
||||
#else
|
||||
#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
|
||||
#endif
|
||||
|
||||
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
|
||||
|
||||
struct elf_siginfo {
|
||||
int si_signo;
|
||||
int si_code;
|
||||
int si_errno;
|
||||
};
|
||||
|
||||
struct elf_prstatus {
|
||||
struct elf_siginfo pr_info;
|
||||
short pr_cursig;
|
||||
unsigned long pr_sigpend;
|
||||
unsigned long pr_sighold;
|
||||
pid_t pr_pid;
|
||||
pid_t pr_ppid;
|
||||
pid_t pr_pgrp;
|
||||
pid_t pd_sid;
|
||||
struct timeval pr_utime;
|
||||
struct timeval pr_stime;
|
||||
struct timeval pr_cutime;
|
||||
struct timeval pr_cstime;
|
||||
elf_gregset_t pr_reg;
|
||||
int pr_fpvalid;
|
||||
};
|
||||
|
||||
#define ELF_PRARGSZ 80
|
||||
|
||||
struct elf_prpsinfo {
|
||||
char pr_state;
|
||||
char pr_sname;
|
||||
char pr_zomb;
|
||||
char pr_nice;
|
||||
unsigned long pr_flags;
|
||||
#ifdef __x86_64__
|
||||
unsigned int pr_uid;
|
||||
unsigned int pr_gid;
|
||||
#elif defined(__mips__)
|
||||
__kernel_uid_t pr_uid;
|
||||
__kernel_gid_t pr_gid;
|
||||
#else
|
||||
unsigned short pr_uid;
|
||||
unsigned short pr_gid;
|
||||
#endif
|
||||
int pr_pid;
|
||||
int pr_ppid;
|
||||
int pr_pgrp;
|
||||
int pr_sid;
|
||||
char pr_fname[16];
|
||||
char pr_psargs[ELF_PRARGSZ];
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // __BIONIC_HAVE_SYS_PROCFS_H
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_SYS_PROCFS_H
|
||||
68
externals/breakpad/src/common/android/include/sys/user.h
vendored
Normal file
68
externals/breakpad/src/common/android/include/sys/user.h
vendored
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H
|
||||
|
||||
// The purpose of this file is to glue the mismatching headers (Android NDK vs
|
||||
// glibc) and therefore avoid doing otherwise awkward #ifdefs in the code.
|
||||
// The following quirks are currently handled by this file:
|
||||
// - i386: Use the Android NDK but alias user_fxsr_struct > user_fpxregs_struct.
|
||||
|
||||
// TODO(primiano): remove these changes after Chromium has stably rolled to
|
||||
// an NDK with the appropriate fixes. https://crbug.com/358831
|
||||
|
||||
// With traditional headers, <sys/user.h> forgot to do this. Unified headers get
|
||||
// it right.
|
||||
#include <sys/types.h>
|
||||
|
||||
#include_next <sys/user.h>
|
||||
|
||||
#include <android/api-level.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#if defined(__i386__)
|
||||
#if __ANDROID_API__ < 21 && !defined(__ANDROID_API_N__)
|
||||
|
||||
// user_fpxregs_struct was called user_fxsr_struct in traditional headers before
|
||||
// API level 21. Unified headers call it user_fpxregs_struct regardless of the
|
||||
// chosen API level. __ANDROID_API_N__ is a proxy for determining whether
|
||||
// unified headers are in use. It’s only defined by unified headers.
|
||||
typedef struct user_fxsr_struct user_fpxregs_struct;
|
||||
|
||||
#endif // __ANDROID_API__ < 21 && !defined(__ANDROID_API_N__)
|
||||
#endif // defined(__i386__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_INCLUDE_SYS_USER_H
|
||||
75
externals/breakpad/src/common/android/testing/include/wchar.h
vendored
Normal file
75
externals/breakpad/src/common/android/testing/include/wchar.h
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Android doesn't provide wcscasecmp(), so provide an alternative here.
|
||||
//
|
||||
// Note that this header is not needed when Breakpad is compiled against
|
||||
// a recent version of Googletest. It shall be considered for removal once
|
||||
// src/testing/ is updated to an appropriate revision in the future.
|
||||
|
||||
#ifndef GOOGLEBREAKPAD_COMMON_ANDROID_INCLUDE_WCHAR_H
|
||||
#define GOOGLEBREAKPAD_COMMON_ANDROID_INCLUDE_WCHAR_H
|
||||
|
||||
#include_next <wchar.h>
|
||||
|
||||
#if !defined(__aarch64__) && !defined(__x86_64__) && \
|
||||
!(defined(__mips__) && _MIPS_SIM == _ABI64)
|
||||
|
||||
// This needs to be in an extern "C" namespace, or Googletest will not
|
||||
// compile against it.
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
static wchar_t inline wcstolower(wchar_t ch) {
|
||||
if (ch >= L'a' && ch <= L'A')
|
||||
ch -= L'a' - L'A';
|
||||
return ch;
|
||||
}
|
||||
|
||||
static int inline wcscasecmp(const wchar_t* s1, const wchar_t* s2) {
|
||||
for (;;) {
|
||||
wchar_t c1 = wcstolower(*s1);
|
||||
wchar_t c2 = wcstolower(*s2);
|
||||
if (c1 < c2)
|
||||
return -1;
|
||||
if (c1 > c2)
|
||||
return 1;
|
||||
if (c1 == L'0')
|
||||
return 0;
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
#endif
|
||||
|
||||
#endif // GOOGLEBREAKPAD_COMMON_ANDROID_INCLUDE_WCHAR_H
|
||||
109
externals/breakpad/src/common/android/testing/mkdtemp.h
vendored
Normal file
109
externals/breakpad/src/common/android/testing/mkdtemp.h
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC 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
|
||||
93
externals/breakpad/src/common/android/testing/pthread_fixes.h
vendored
Normal file
93
externals/breakpad/src/common/android/testing/pthread_fixes.h
vendored
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC 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)
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_ANDROID_TESTING_PTHREAD_FIXES_H
|
||||
49
externals/breakpad/src/common/basictypes.h
vendored
Normal file
49
externals/breakpad/src/common/basictypes.h
vendored
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef COMMON_BASICTYPES_H_
|
||||
#define COMMON_BASICTYPES_H_
|
||||
|
||||
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_
|
||||
265
externals/breakpad/src/common/byte_cursor.h
vendored
Normal file
265
externals/breakpad/src/common/byte_cursor.h
vendored
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// byte_cursor.h: Classes for parsing values from a buffer of bytes.
|
||||
// The ByteCursor class provides a convenient interface for reading
|
||||
// fixed-size integers of arbitrary endianness, being thorough about
|
||||
// checking for buffer overruns.
|
||||
|
||||
#ifndef COMMON_BYTE_CURSOR_H_
|
||||
#define COMMON_BYTE_CURSOR_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A buffer holding a series of bytes.
|
||||
struct ByteBuffer {
|
||||
ByteBuffer() : start(0), end(0) { }
|
||||
ByteBuffer(const uint8_t* set_start, size_t set_size)
|
||||
: start(set_start), end(set_start + set_size) { }
|
||||
~ByteBuffer() { };
|
||||
|
||||
// Equality operators. Useful in unit tests, and when we're using
|
||||
// ByteBuffers to refer to regions of a larger buffer.
|
||||
bool operator==(const ByteBuffer& that) const {
|
||||
return start == that.start && end == that.end;
|
||||
}
|
||||
bool operator!=(const ByteBuffer& that) const {
|
||||
return start != that.start || end != that.end;
|
||||
}
|
||||
|
||||
// Not C++ style guide compliant, but this definitely belongs here.
|
||||
size_t Size() const {
|
||||
assert(start <= end);
|
||||
return end - start;
|
||||
}
|
||||
|
||||
const uint8_t* start;
|
||||
const uint8_t* end;
|
||||
};
|
||||
|
||||
// A cursor pointing into a ByteBuffer that can parse numbers of various
|
||||
// widths and representations, strings, and data blocks, advancing through
|
||||
// the buffer as it goes. All ByteCursor operations check that accesses
|
||||
// haven't gone beyond the end of the enclosing ByteBuffer.
|
||||
class ByteCursor {
|
||||
public:
|
||||
// Create a cursor reading bytes from the start of BUFFER. By default, the
|
||||
// cursor reads multi-byte values in little-endian form.
|
||||
ByteCursor(const ByteBuffer* buffer, bool big_endian = false)
|
||||
: buffer_(buffer), here_(buffer->start),
|
||||
big_endian_(big_endian), complete_(true) { }
|
||||
|
||||
// Accessor and setter for this cursor's endianness flag.
|
||||
bool big_endian() const { return big_endian_; }
|
||||
void set_big_endian(bool big_endian) { big_endian_ = big_endian; }
|
||||
|
||||
// Accessor and setter for this cursor's current position. The setter
|
||||
// returns a reference to this cursor.
|
||||
const uint8_t* here() const { return here_; }
|
||||
ByteCursor& set_here(const uint8_t* here) {
|
||||
assert(buffer_->start <= here && here <= buffer_->end);
|
||||
here_ = here;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Return the number of bytes available to read at the cursor.
|
||||
size_t Available() const { return size_t(buffer_->end - here_); }
|
||||
|
||||
// Return true if this cursor is at the end of its buffer.
|
||||
bool AtEnd() const { return Available() == 0; }
|
||||
|
||||
// When used as a boolean value this cursor converts to true if all
|
||||
// prior reads have been completed, or false if we ran off the end
|
||||
// of the buffer.
|
||||
operator bool() const { return complete_; }
|
||||
|
||||
// Read a SIZE-byte integer at this cursor, signed if IS_SIGNED is true,
|
||||
// unsigned otherwise, using the cursor's established endianness, and set
|
||||
// *RESULT to the number. If we read off the end of our buffer, clear
|
||||
// this cursor's complete_ flag, and store a dummy value in *RESULT.
|
||||
// Return a reference to this cursor.
|
||||
template<typename T>
|
||||
ByteCursor& Read(size_t size, bool is_signed, T* result) {
|
||||
if (CheckAvailable(size)) {
|
||||
T v = 0;
|
||||
if (big_endian_) {
|
||||
for (size_t i = 0; i < size; i++)
|
||||
v = (v << 8) + here_[i];
|
||||
} else {
|
||||
// This loop condition looks weird, but size_t is unsigned, so
|
||||
// decrementing i after it is zero yields the largest size_t value.
|
||||
for (size_t i = size - 1; i < size; i--)
|
||||
v = (v << 8) + here_[i];
|
||||
}
|
||||
if (is_signed && size < sizeof(T)) {
|
||||
size_t sign_bit = (T)1 << (size * 8 - 1);
|
||||
v = (v ^ sign_bit) - sign_bit;
|
||||
}
|
||||
here_ += size;
|
||||
*result = v;
|
||||
} else {
|
||||
*result = (T) 0xdeadbeef;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Read an integer, using the cursor's established endianness and
|
||||
// *RESULT's size and signedness, and set *RESULT to the number. If we
|
||||
// read off the end of our buffer, clear this cursor's complete_ flag.
|
||||
// Return a reference to this cursor.
|
||||
template<typename T>
|
||||
ByteCursor& operator>>(T& result) {
|
||||
bool T_is_signed = (T)-1 < 0;
|
||||
return Read(sizeof(T), T_is_signed, &result);
|
||||
}
|
||||
|
||||
// Copy the SIZE bytes at the cursor to BUFFER, and advance this
|
||||
// cursor to the end of them. If we read off the end of our buffer,
|
||||
// clear this cursor's complete_ flag, and set *POINTER to NULL.
|
||||
// Return a reference to this cursor.
|
||||
ByteCursor& Read(uint8_t* buffer, size_t size) {
|
||||
if (CheckAvailable(size)) {
|
||||
memcpy(buffer, here_, size);
|
||||
here_ += size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Set STR to a copy of the '\0'-terminated string at the cursor. If the
|
||||
// byte buffer does not contain a terminating zero, clear this cursor's
|
||||
// complete_ flag, and set STR to the empty string. Return a reference to
|
||||
// this cursor.
|
||||
ByteCursor& CString(string* str) {
|
||||
const uint8_t* end
|
||||
= static_cast<const uint8_t*>(memchr(here_, '\0', Available()));
|
||||
if (end) {
|
||||
str->assign(reinterpret_cast<const char*>(here_), end - here_);
|
||||
here_ = end + 1;
|
||||
} else {
|
||||
str->clear();
|
||||
here_ = buffer_->end;
|
||||
complete_ = false;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Like CString(STR), but extract the string from a fixed-width buffer
|
||||
// LIMIT bytes long, which may or may not contain a terminating '\0'
|
||||
// byte. Specifically:
|
||||
//
|
||||
// - If there are not LIMIT bytes available at the cursor, clear the
|
||||
// cursor's complete_ flag and set STR to the empty string.
|
||||
//
|
||||
// - Otherwise, if the LIMIT bytes at the cursor contain any '\0'
|
||||
// characters, set *STR to a copy of the bytes before the first '\0',
|
||||
// and advance the cursor by LIMIT bytes.
|
||||
//
|
||||
// - Otherwise, set *STR to a copy of those LIMIT bytes, and advance the
|
||||
// cursor by LIMIT bytes.
|
||||
ByteCursor& CString(string* str, size_t limit) {
|
||||
if (CheckAvailable(limit)) {
|
||||
const uint8_t* end
|
||||
= static_cast<const uint8_t*>(memchr(here_, '\0', limit));
|
||||
if (end)
|
||||
str->assign(reinterpret_cast<const char*>(here_), end - here_);
|
||||
else
|
||||
str->assign(reinterpret_cast<const char*>(here_), limit);
|
||||
here_ += limit;
|
||||
} else {
|
||||
str->clear();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Set *POINTER to point to the SIZE bytes at the cursor, and advance
|
||||
// this cursor to the end of them. If SIZE is omitted, don't move the
|
||||
// cursor. If we read off the end of our buffer, clear this cursor's
|
||||
// complete_ flag, and set *POINTER to NULL. Return a reference to this
|
||||
// cursor.
|
||||
ByteCursor& PointTo(const uint8_t** pointer, size_t size = 0) {
|
||||
if (CheckAvailable(size)) {
|
||||
*pointer = here_;
|
||||
here_ += size;
|
||||
} else {
|
||||
*pointer = NULL;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Skip SIZE bytes at the cursor. If doing so would advance us off
|
||||
// the end of our buffer, clear this cursor's complete_ flag, and
|
||||
// set *POINTER to NULL. Return a reference to this cursor.
|
||||
ByteCursor& Skip(size_t size) {
|
||||
if (CheckAvailable(size))
|
||||
here_ += size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// If there are at least SIZE bytes available to read from the buffer,
|
||||
// return true. Otherwise, set here_ to the end of the buffer, set
|
||||
// complete_ to false, and return false.
|
||||
bool CheckAvailable(size_t size) {
|
||||
if (Available() >= size) {
|
||||
return true;
|
||||
} else {
|
||||
here_ = buffer_->end;
|
||||
complete_ = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The buffer we're reading bytes from.
|
||||
const ByteBuffer* buffer_;
|
||||
|
||||
// The next byte within buffer_ that we'll read.
|
||||
const uint8_t* here_;
|
||||
|
||||
// True if we should read numbers in big-endian form; false if we
|
||||
// should read in little-endian form.
|
||||
bool big_endian_;
|
||||
|
||||
// True if we've been able to read all we've been asked to.
|
||||
bool complete_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_BYTE_CURSOR_H_
|
||||
779
externals/breakpad/src/common/byte_cursor_unittest.cc
vendored
Normal file
779
externals/breakpad/src/common/byte_cursor_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,779 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// byte_cursor_unittest.cc: Unit tests for google_breakpad::ByteBuffer
|
||||
// and google_breakpad::ByteCursor.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/byte_cursor.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using google_breakpad::ByteBuffer;
|
||||
using google_breakpad::ByteCursor;
|
||||
|
||||
TEST(Buffer, SizeOfNothing) {
|
||||
uint8_t data[1];
|
||||
ByteBuffer buffer(data, 0);
|
||||
EXPECT_EQ(0U, buffer.Size());
|
||||
}
|
||||
|
||||
TEST(Buffer, SizeOfSomething) {
|
||||
uint8_t data[10];
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
EXPECT_EQ(10U, buffer.Size());
|
||||
}
|
||||
|
||||
TEST(Extent, AvailableEmpty) {
|
||||
uint8_t data[1];
|
||||
ByteBuffer buffer(data, 0);
|
||||
ByteCursor cursor(&buffer);
|
||||
EXPECT_EQ(0U, cursor.Available());
|
||||
}
|
||||
|
||||
TEST(Extent, AtEndEmpty) {
|
||||
uint8_t data[1];
|
||||
ByteBuffer buffer(data, 0);
|
||||
ByteCursor cursor(&buffer);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
}
|
||||
|
||||
TEST(Extent, AsBoolEmpty) {
|
||||
uint8_t data[1];
|
||||
ByteBuffer buffer(data, 0);
|
||||
ByteCursor cursor(&buffer);
|
||||
EXPECT_TRUE(cursor);
|
||||
}
|
||||
|
||||
TEST(Extent, AvailableSome) {
|
||||
uint8_t data[10];
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
EXPECT_EQ(10U, cursor.Available());
|
||||
}
|
||||
|
||||
TEST(Extent, AtEndSome) {
|
||||
uint8_t data[10];
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
EXPECT_FALSE(cursor.AtEnd());
|
||||
EXPECT_TRUE(cursor.Skip(sizeof(data)).AtEnd());
|
||||
}
|
||||
|
||||
TEST(Extent, AsBoolSome) {
|
||||
uint8_t data[10];
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
EXPECT_TRUE(cursor);
|
||||
EXPECT_TRUE(cursor.Skip(sizeof(data)));
|
||||
EXPECT_FALSE(cursor.Skip(1));
|
||||
}
|
||||
|
||||
TEST(Extent, Cursor) {
|
||||
uint8_t data[] = { 0xf7,
|
||||
0x9f, 0xbe,
|
||||
0x67, 0xfb, 0xd3, 0x58,
|
||||
0x6f, 0x36, 0xde, 0xd1,
|
||||
0x2a, 0x2a, 0x2a };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
|
||||
uint8_t a;
|
||||
uint16_t b;
|
||||
uint32_t c;
|
||||
uint32_t d;
|
||||
uint8_t stars[3];
|
||||
|
||||
EXPECT_EQ(data + 0U, cursor.here());
|
||||
|
||||
EXPECT_TRUE(cursor >> a);
|
||||
EXPECT_EQ(data + 1U, cursor.here());
|
||||
|
||||
EXPECT_TRUE(cursor >> b);
|
||||
EXPECT_EQ(data + 3U, cursor.here());
|
||||
|
||||
EXPECT_TRUE(cursor >> c);
|
||||
EXPECT_EQ(data + 7U, cursor.here());
|
||||
|
||||
EXPECT_TRUE(cursor.Skip(4));
|
||||
EXPECT_EQ(data + 11U, cursor.here());
|
||||
|
||||
EXPECT_TRUE(cursor.Read(stars, 3));
|
||||
EXPECT_EQ(data + 14U, cursor.here());
|
||||
|
||||
EXPECT_FALSE(cursor >> d);
|
||||
EXPECT_EQ(data + 14U, cursor.here());
|
||||
}
|
||||
|
||||
TEST(Extent, SetOffset) {
|
||||
uint8_t data[] = { 0x5c, 0x79, 0x8c, 0xd5 };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
|
||||
uint8_t a, b, c, d, e;
|
||||
EXPECT_TRUE(cursor >> a);
|
||||
EXPECT_EQ(0x5cU, a);
|
||||
EXPECT_EQ(data + 1U, cursor.here());
|
||||
EXPECT_TRUE(((cursor >> b).set_here(data + 3) >> c).set_here(data + 1)
|
||||
>> d >> e);
|
||||
EXPECT_EQ(0x79U, b);
|
||||
EXPECT_EQ(0xd5U, c);
|
||||
EXPECT_EQ(0x79U, d);
|
||||
EXPECT_EQ(0x8cU, e);
|
||||
EXPECT_EQ(data + 3U, cursor.here());
|
||||
}
|
||||
|
||||
TEST(BigEndian, Signed1) {
|
||||
uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
cursor.set_big_endian(true);
|
||||
int a, b, c, d, e;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(1, true, &a)
|
||||
.Read(1, true, &b)
|
||||
.Read(1, true, &c)
|
||||
.Read(1, true, &d));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x7f, b);
|
||||
EXPECT_EQ(-0x80, c);
|
||||
EXPECT_EQ(-1, d);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(1, true, &e));
|
||||
}
|
||||
|
||||
TEST(BigEndian, Signed2) {
|
||||
uint8_t data[] = { 0x00, 0x00, 0x00, 0x80, 0x7f, 0xff,
|
||||
0x80, 0x00, 0x80, 0x80, 0xff, 0xff,
|
||||
0x39, 0xf1, 0x8a, 0xbc, 0x5a, 0xec };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer, true);
|
||||
int a, b, c, d, e, f, g, h, i, j;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(2, true, &a)
|
||||
.Read(2, true, &b)
|
||||
.Read(2, true, &c)
|
||||
.Read(2, true, &d)
|
||||
.Read(2, true, &e)
|
||||
.Read(2, true, &f)
|
||||
.Read(2, true, &g)
|
||||
.Read(2, true, &h)
|
||||
.Read(2, true, &i));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x80, b);
|
||||
EXPECT_EQ(0x7fff, c);
|
||||
EXPECT_EQ(-0x8000, d);
|
||||
EXPECT_EQ(-0x7f80, e);
|
||||
EXPECT_EQ(-1, f);
|
||||
EXPECT_EQ(0x39f1, g);
|
||||
EXPECT_EQ(-0x7544, h);
|
||||
EXPECT_EQ(0x5aec, i);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(2, true, &j));
|
||||
}
|
||||
|
||||
TEST(BigEndian, Signed4) {
|
||||
uint8_t data[] = { 0x00, 0x00, 0x00, 0x00,
|
||||
0x7f, 0xff, 0xff, 0xff,
|
||||
0x80, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0xb6, 0xb1, 0xff, 0xef,
|
||||
0x19, 0x6a, 0xca, 0x46 };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
cursor.set_big_endian(true);
|
||||
int64_t a, b, c, d, e, f, g;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(4, true, &a)
|
||||
.Read(4, true, &b)
|
||||
.Read(4, true, &c)
|
||||
.Read(4, true, &d)
|
||||
.Read(4, true, &e)
|
||||
.Read(4, true, &f));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x7fffffff, b);
|
||||
EXPECT_EQ(-0x80000000LL, c);
|
||||
EXPECT_EQ(-1, d);
|
||||
EXPECT_EQ((int32_t) 0xb6b1ffef, e);
|
||||
EXPECT_EQ(0x196aca46, f);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(4, true, &g));
|
||||
}
|
||||
|
||||
TEST(BigEndian, Signed8) {
|
||||
uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x93, 0x20, 0xd5, 0xe9, 0xd2, 0xd5, 0x87, 0x9c,
|
||||
0x4e, 0x42, 0x49, 0xd2, 0x7f, 0x84, 0x14, 0xa4 };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer, true);
|
||||
int64_t a, b, c, d, e, f, g;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(8, true, &a)
|
||||
.Read(8, true, &b)
|
||||
.Read(8, true, &c)
|
||||
.Read(8, true, &d)
|
||||
.Read(8, true, &e)
|
||||
.Read(8, true, &f));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x7fffffffffffffffLL, b);
|
||||
EXPECT_EQ(-0x7fffffffffffffffLL - 1, c);
|
||||
EXPECT_EQ(-1, d);
|
||||
EXPECT_EQ((int64_t) 0x9320d5e9d2d5879cULL, e);
|
||||
EXPECT_EQ(0x4e4249d27f8414a4LL, f);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(8, true, &g));
|
||||
}
|
||||
|
||||
TEST(BigEndian, Unsigned1) {
|
||||
uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
cursor.set_big_endian(true);
|
||||
int32_t a, b, c, d, e;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(1, false, &a)
|
||||
.Read(1, false, &b)
|
||||
.Read(1, false, &c)
|
||||
.Read(1, false, &d));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x7f, b);
|
||||
EXPECT_EQ(0x80, c);
|
||||
EXPECT_EQ(0xff, d);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(1, false, &e));
|
||||
}
|
||||
|
||||
TEST(BigEndian, Unsigned2) {
|
||||
uint8_t data[] = { 0x00, 0x00, 0x00, 0x80, 0x7f, 0xff,
|
||||
0x80, 0x00, 0x80, 0x80, 0xff, 0xff,
|
||||
0x39, 0xf1, 0x8a, 0xbc, 0x5a, 0xec };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer, true);
|
||||
int64_t a, b, c, d, e, f, g, h, i, j;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(2, false, &a)
|
||||
.Read(2, false, &b)
|
||||
.Read(2, false, &c)
|
||||
.Read(2, false, &d)
|
||||
.Read(2, false, &e)
|
||||
.Read(2, false, &f)
|
||||
.Read(2, false, &g)
|
||||
.Read(2, false, &h)
|
||||
.Read(2, false, &i));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x80, b);
|
||||
EXPECT_EQ(0x7fff, c);
|
||||
EXPECT_EQ(0x8000, d);
|
||||
EXPECT_EQ(0x8080, e);
|
||||
EXPECT_EQ(0xffff, f);
|
||||
EXPECT_EQ(0x39f1, g);
|
||||
EXPECT_EQ(0x8abc, h);
|
||||
EXPECT_EQ(0x5aec, i);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(2, false, &j));
|
||||
}
|
||||
|
||||
TEST(BigEndian, Unsigned4) {
|
||||
uint8_t data[] = { 0x00, 0x00, 0x00, 0x00,
|
||||
0x7f, 0xff, 0xff, 0xff,
|
||||
0x80, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0xb6, 0xb1, 0xff, 0xef,
|
||||
0x19, 0x6a, 0xca, 0x46 };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
cursor.set_big_endian(true);
|
||||
int64_t a, b, c, d, e, f, g;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(4, false, &a)
|
||||
.Read(4, false, &b)
|
||||
.Read(4, false, &c)
|
||||
.Read(4, false, &d)
|
||||
.Read(4, false, &e)
|
||||
.Read(4, false, &f));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x7fffffff, b);
|
||||
EXPECT_EQ(0x80000000, c);
|
||||
EXPECT_EQ(0xffffffff, d);
|
||||
EXPECT_EQ(0xb6b1ffef, e);
|
||||
EXPECT_EQ(0x196aca46, f);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(4, false, &g));
|
||||
}
|
||||
|
||||
TEST(BigEndian, Unsigned8) {
|
||||
uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x93, 0x20, 0xd5, 0xe9, 0xd2, 0xd5, 0x87, 0x9c,
|
||||
0x4e, 0x42, 0x49, 0xd2, 0x7f, 0x84, 0x14, 0xa4 };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer, true);
|
||||
uint64_t a, b, c, d, e, f, g;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(8, false, &a)
|
||||
.Read(8, false, &b)
|
||||
.Read(8, false, &c)
|
||||
.Read(8, false, &d)
|
||||
.Read(8, false, &e)
|
||||
.Read(8, false, &f));
|
||||
EXPECT_EQ(0U, a);
|
||||
EXPECT_EQ(0x7fffffffffffffffULL, b);
|
||||
EXPECT_EQ(0x8000000000000000ULL, c);
|
||||
EXPECT_EQ(0xffffffffffffffffULL, d);
|
||||
EXPECT_EQ(0x9320d5e9d2d5879cULL, e);
|
||||
EXPECT_EQ(0x4e4249d27f8414a4ULL, f);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(8, false, &g));
|
||||
}
|
||||
|
||||
TEST(LittleEndian, Signed1) {
|
||||
uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
int32_t a, b, c, d, e;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(1, true, &a)
|
||||
.Read(1, true, &b)
|
||||
.Read(1, true, &c)
|
||||
.Read(1, true, &d));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x7f, b);
|
||||
EXPECT_EQ(-0x80, c);
|
||||
EXPECT_EQ(-1, d);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(1, true, &e));
|
||||
}
|
||||
|
||||
TEST(LittleEndian, Signed2) {
|
||||
uint8_t data[] = { 0x00, 0x00, 0x80, 0x00, 0xff, 0x7f,
|
||||
0x00, 0x80, 0x80, 0x80, 0xff, 0xff,
|
||||
0xf1, 0x39, 0xbc, 0x8a, 0xec, 0x5a };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer, false);
|
||||
int32_t a, b, c, d, e, f, g, h, i, j;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(2, true, &a)
|
||||
.Read(2, true, &b)
|
||||
.Read(2, true, &c)
|
||||
.Read(2, true, &d)
|
||||
.Read(2, true, &e)
|
||||
.Read(2, true, &f)
|
||||
.Read(2, true, &g)
|
||||
.Read(2, true, &h)
|
||||
.Read(2, true, &i));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x80, b);
|
||||
EXPECT_EQ(0x7fff, c);
|
||||
EXPECT_EQ(-0x8000, d);
|
||||
EXPECT_EQ(-0x7f80, e);
|
||||
EXPECT_EQ(-1, f);
|
||||
EXPECT_EQ(0x39f1, g);
|
||||
EXPECT_EQ(-0x7544, h);
|
||||
EXPECT_EQ(0x5aec, i);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(2, true, &j));
|
||||
}
|
||||
|
||||
TEST(LittleEndian, Signed4) {
|
||||
uint8_t data[] = { 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0x7f,
|
||||
0x00, 0x00, 0x00, 0x80,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0xef, 0xff, 0xb1, 0xb6,
|
||||
0x46, 0xca, 0x6a, 0x19 };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
int64_t a, b, c, d, e, f, g;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(4, true, &a)
|
||||
.Read(4, true, &b)
|
||||
.Read(4, true, &c)
|
||||
.Read(4, true, &d)
|
||||
.Read(4, true, &e)
|
||||
.Read(4, true, &f));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x7fffffff, b);
|
||||
EXPECT_EQ(-0x80000000LL, c);
|
||||
EXPECT_EQ(-1, d);
|
||||
EXPECT_EQ((int32_t) 0xb6b1ffef, e);
|
||||
EXPECT_EQ(0x196aca46, f);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(4, true, &g));
|
||||
}
|
||||
|
||||
TEST(LittleEndian, Signed8) {
|
||||
uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x9c, 0x87, 0xd5, 0xd2, 0xe9, 0xd5, 0x20, 0x93,
|
||||
0xa4, 0x14, 0x84, 0x7f, 0xd2, 0x49, 0x42, 0x4e };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer, false);
|
||||
int64_t a, b, c, d, e, f, g;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(8, true, &a)
|
||||
.Read(8, true, &b)
|
||||
.Read(8, true, &c)
|
||||
.Read(8, true, &d)
|
||||
.Read(8, true, &e)
|
||||
.Read(8, true, &f));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x7fffffffffffffffLL, b);
|
||||
EXPECT_EQ(-0x7fffffffffffffffLL - 1, c);
|
||||
EXPECT_EQ(-1, d);
|
||||
EXPECT_EQ((int64_t) 0x9320d5e9d2d5879cULL, e);
|
||||
EXPECT_EQ(0x4e4249d27f8414a4LL, f);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(8, true, &g));
|
||||
}
|
||||
|
||||
TEST(LittleEndian, Unsigned1) {
|
||||
uint8_t data[] = { 0x00, 0x7f, 0x80, 0xff };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
int32_t a, b, c, d, e;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(1, false, &a)
|
||||
.Read(1, false, &b)
|
||||
.Read(1, false, &c)
|
||||
.Read(1, false, &d));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x7f, b);
|
||||
EXPECT_EQ(0x80, c);
|
||||
EXPECT_EQ(0xff, d);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(1, false, &e));
|
||||
}
|
||||
|
||||
TEST(LittleEndian, Unsigned2) {
|
||||
uint8_t data[] = { 0x00, 0x00, 0x80, 0x00, 0xff, 0x7f,
|
||||
0x00, 0x80, 0x80, 0x80, 0xff, 0xff,
|
||||
0xf1, 0x39, 0xbc, 0x8a, 0xec, 0x5a };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
int32_t a, b, c, d, e, f, g, h, i, j;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(2, false, &a)
|
||||
.Read(2, false, &b)
|
||||
.Read(2, false, &c)
|
||||
.Read(2, false, &d)
|
||||
.Read(2, false, &e)
|
||||
.Read(2, false, &f)
|
||||
.Read(2, false, &g)
|
||||
.Read(2, false, &h)
|
||||
.Read(2, false, &i));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x80, b);
|
||||
EXPECT_EQ(0x7fff, c);
|
||||
EXPECT_EQ(0x8000, d);
|
||||
EXPECT_EQ(0x8080, e);
|
||||
EXPECT_EQ(0xffff, f);
|
||||
EXPECT_EQ(0x39f1, g);
|
||||
EXPECT_EQ(0x8abc, h);
|
||||
EXPECT_EQ(0x5aec, i);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(2, false, &j));
|
||||
}
|
||||
|
||||
TEST(LittleEndian, Unsigned4) {
|
||||
uint8_t data[] = { 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0x7f,
|
||||
0x00, 0x00, 0x00, 0x80,
|
||||
0xff, 0xff, 0xff, 0xff,
|
||||
0xef, 0xff, 0xb1, 0xb6,
|
||||
0x46, 0xca, 0x6a, 0x19 };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
int64_t a, b, c, d, e, f, g;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(4, false, &a)
|
||||
.Read(4, false, &b)
|
||||
.Read(4, false, &c)
|
||||
.Read(4, false, &d)
|
||||
.Read(4, false, &e)
|
||||
.Read(4, false, &f));
|
||||
EXPECT_EQ(0, a);
|
||||
EXPECT_EQ(0x7fffffff, b);
|
||||
EXPECT_EQ(0x80000000, c);
|
||||
EXPECT_EQ(0xffffffff, d);
|
||||
EXPECT_EQ(0xb6b1ffef, e);
|
||||
EXPECT_EQ(0x196aca46, f);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(4, false, &g));
|
||||
}
|
||||
|
||||
TEST(LittleEndian, Unsigned8) {
|
||||
uint8_t data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x9c, 0x87, 0xd5, 0xd2, 0xe9, 0xd5, 0x20, 0x93,
|
||||
0xa4, 0x14, 0x84, 0x7f, 0xd2, 0x49, 0x42, 0x4e };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
uint64_t a, b, c, d, e, f, g;
|
||||
ASSERT_TRUE(cursor
|
||||
.Read(8, false, &a)
|
||||
.Read(8, false, &b)
|
||||
.Read(8, false, &c)
|
||||
.Read(8, false, &d)
|
||||
.Read(8, false, &e)
|
||||
.Read(8, false, &f));
|
||||
EXPECT_EQ(0U, a);
|
||||
EXPECT_EQ(0x7fffffffffffffffULL, b);
|
||||
EXPECT_EQ(0x8000000000000000ULL, c);
|
||||
EXPECT_EQ(0xffffffffffffffffULL, d);
|
||||
EXPECT_EQ(0x9320d5e9d2d5879cULL, e);
|
||||
EXPECT_EQ(0x4e4249d27f8414a4ULL, f);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor.Read(8, false, &g));
|
||||
}
|
||||
|
||||
TEST(Extractor, Signed1) {
|
||||
uint8_t data[] = { 0xfd };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
int8_t a;
|
||||
EXPECT_TRUE(cursor >> a);
|
||||
EXPECT_EQ(-3, a);
|
||||
EXPECT_FALSE(cursor >> a);
|
||||
}
|
||||
|
||||
TEST(Extractor, Signed2) {
|
||||
uint8_t data[] = { 0x13, 0xcd };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
int16_t a;
|
||||
EXPECT_TRUE(cursor >> a);
|
||||
EXPECT_EQ(-13037, a);
|
||||
EXPECT_FALSE(cursor >> a);
|
||||
}
|
||||
|
||||
TEST(Extractor, Signed4) {
|
||||
uint8_t data[] = { 0xd2, 0xe4, 0x53, 0xe9 };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
int32_t a;
|
||||
// For some reason, G++ 4.4.1 complains:
|
||||
// warning: array subscript is above array bounds
|
||||
// in ByteCursor::Read(size_t, bool, T*) as it inlines this call, but
|
||||
// I'm not able to see how such a reference would occur.
|
||||
EXPECT_TRUE(cursor >> a);
|
||||
EXPECT_EQ(-380377902, a);
|
||||
EXPECT_FALSE(cursor >> a);
|
||||
}
|
||||
|
||||
TEST(Extractor, Unsigned1) {
|
||||
uint8_t data[] = { 0xfd };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
uint8_t a;
|
||||
EXPECT_TRUE(cursor >> a);
|
||||
EXPECT_EQ(0xfd, a);
|
||||
EXPECT_FALSE(cursor >> a);
|
||||
}
|
||||
|
||||
TEST(Extractor, Unsigned2) {
|
||||
uint8_t data[] = { 0x13, 0xcd };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
uint16_t a;
|
||||
EXPECT_TRUE(cursor >> a);
|
||||
EXPECT_EQ(0xcd13, a);
|
||||
EXPECT_FALSE(cursor >> a);
|
||||
}
|
||||
|
||||
TEST(Extractor, Unsigned4) {
|
||||
uint8_t data[] = { 0xd2, 0xe4, 0x53, 0xe9 };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
uint32_t a;
|
||||
// For some reason, G++ 4.4.1 complains:
|
||||
// warning: array subscript is above array bounds
|
||||
// in ByteCursor::Read(size_t, bool, T*) as it inlines this call, but
|
||||
// I'm not able to see how such a reference would occur.
|
||||
EXPECT_TRUE(cursor >> a);
|
||||
EXPECT_EQ(0xe953e4d2, a);
|
||||
EXPECT_FALSE(cursor >> a);
|
||||
EXPECT_FALSE(cursor >> a);
|
||||
}
|
||||
|
||||
TEST(Extractor, Mixed) {
|
||||
uint8_t data[] = { 0x42,
|
||||
0x25, 0x0b,
|
||||
0x3d, 0x25, 0xed, 0x2a,
|
||||
0xec, 0x16, 0x9e, 0x14, 0x61, 0x5b, 0x2c, 0xcf,
|
||||
0xd8,
|
||||
0x22, 0xa5,
|
||||
0x3a, 0x02, 0x6a, 0xd7,
|
||||
0x93, 0x2a, 0x2d, 0x8d, 0xb4, 0x95, 0xe0, 0xc6 };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
cursor.set_big_endian(true);
|
||||
|
||||
uint8_t a;
|
||||
uint16_t b;
|
||||
uint32_t c;
|
||||
uint64_t d;
|
||||
int8_t e;
|
||||
int16_t f;
|
||||
int32_t g;
|
||||
int64_t h;
|
||||
int z;
|
||||
EXPECT_FALSE(cursor.AtEnd());
|
||||
EXPECT_TRUE(cursor >> a >> b >> c >> d >> e >> f >> g >> h);
|
||||
EXPECT_EQ(0x42U, a);
|
||||
EXPECT_EQ(0x250bU, b);
|
||||
EXPECT_EQ(0x3d25ed2aU, c);
|
||||
EXPECT_EQ(0xec169e14615b2ccfULL, d);
|
||||
EXPECT_EQ(-40, e);
|
||||
EXPECT_EQ(0x22a5, f);
|
||||
EXPECT_EQ(0x3a026ad7, g);
|
||||
EXPECT_EQ(-7842405714468937530LL, h);
|
||||
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
EXPECT_FALSE(cursor >> z);
|
||||
}
|
||||
|
||||
TEST(Strings, Zero) {
|
||||
uint8_t data[] = { 0xa6 };
|
||||
ByteBuffer buffer(data, 0);
|
||||
ByteCursor cursor(&buffer);
|
||||
|
||||
uint8_t received[1];
|
||||
received[0] = 0xc2;
|
||||
EXPECT_TRUE(cursor.Read(received, 0));
|
||||
EXPECT_EQ(0xc2U, received[0]);
|
||||
}
|
||||
|
||||
TEST(Strings, Some) {
|
||||
uint8_t data[] = { 0x5d, 0x31, 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xbb };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
|
||||
uint8_t received[7] = { 0xa7, 0xf7, 0x43, 0x0c, 0x27, 0xea, 0xed };
|
||||
EXPECT_TRUE(cursor.Skip(2).Read(received, 5));
|
||||
uint8_t expected[7] = { 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xea, 0xed };
|
||||
EXPECT_TRUE(memcmp(received, expected, 7) == 0);
|
||||
}
|
||||
|
||||
TEST(Strings, TooMuch) {
|
||||
uint8_t data[] = { 0x5d, 0x31, 0x09, 0xa6, 0x2e, 0x2c, 0x83, 0xbb };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
|
||||
uint8_t received1[3];
|
||||
uint8_t received2[3];
|
||||
uint8_t received3[3];
|
||||
EXPECT_FALSE(cursor
|
||||
.Read(received1, 3)
|
||||
.Read(received2, 3)
|
||||
.Read(received3, 3));
|
||||
uint8_t expected1[3] = { 0x5d, 0x31, 0x09 };
|
||||
uint8_t expected2[3] = { 0xa6, 0x2e, 0x2c };
|
||||
|
||||
EXPECT_TRUE(memcmp(received1, expected1, 3) == 0);
|
||||
EXPECT_TRUE(memcmp(received2, expected2, 3) == 0);
|
||||
}
|
||||
|
||||
TEST(Strings, PointTo) {
|
||||
uint8_t data[] = { 0x83, 0x80, 0xb4, 0x38, 0x00, 0x2c, 0x0a, 0x27 };
|
||||
ByteBuffer buffer(data, sizeof(data));
|
||||
ByteCursor cursor(&buffer);
|
||||
|
||||
const uint8_t* received1;
|
||||
const uint8_t* received2;
|
||||
const uint8_t* received3;
|
||||
const uint8_t* received4;
|
||||
EXPECT_FALSE(cursor
|
||||
.PointTo(&received1, 3)
|
||||
.PointTo(&received2, 3)
|
||||
.PointTo(&received3)
|
||||
.PointTo(&received4, 3));
|
||||
EXPECT_EQ(data + 0, received1);
|
||||
EXPECT_EQ(data + 3, received2);
|
||||
EXPECT_EQ(data + 6, received3);
|
||||
EXPECT_EQ(NULL, received4);
|
||||
}
|
||||
|
||||
TEST(Strings, CString) {
|
||||
uint8_t data[] = "abc\0\0foo";
|
||||
ByteBuffer buffer(data, sizeof(data) - 1); // don't include terminating '\0'
|
||||
ByteCursor cursor(&buffer);
|
||||
|
||||
string a, b, c;
|
||||
EXPECT_TRUE(cursor.CString(&a).CString(&b));
|
||||
EXPECT_EQ("abc", a);
|
||||
EXPECT_EQ("", b);
|
||||
EXPECT_FALSE(cursor.CString(&c));
|
||||
EXPECT_EQ("", c);
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
}
|
||||
|
||||
TEST(Strings, CStringLimit) {
|
||||
uint8_t data[] = "abcdef\0\0foobar";
|
||||
ByteBuffer buffer(data, sizeof(data) - 1); // don't include terminating '\0'
|
||||
ByteCursor cursor(&buffer);
|
||||
|
||||
string a, b, c, d, e;
|
||||
|
||||
EXPECT_TRUE(cursor.CString(&a, 3));
|
||||
EXPECT_EQ("abc", a);
|
||||
|
||||
EXPECT_TRUE(cursor.CString(&b, 0));
|
||||
EXPECT_EQ("", b);
|
||||
|
||||
EXPECT_TRUE(cursor.CString(&c, 6));
|
||||
EXPECT_EQ("def", c);
|
||||
|
||||
EXPECT_TRUE(cursor.CString(&d, 4));
|
||||
EXPECT_EQ("ooba", d);
|
||||
|
||||
EXPECT_FALSE(cursor.CString(&e, 4));
|
||||
EXPECT_EQ("", e);
|
||||
|
||||
EXPECT_TRUE(cursor.AtEnd());
|
||||
}
|
||||
|
||||
// uint8_t data[] = { 0xa6, 0x54, 0xdf, 0x67, 0x51, 0x43, 0xac, 0xf1 };
|
||||
// ByteBuffer buffer(data, sizeof(data));
|
||||
595
externals/breakpad/src/common/convert_UTF.cc
vendored
Normal file
595
externals/breakpad/src/common/convert_UTF.cc
vendored
Normal file
|
|
@ -0,0 +1,595 @@
|
|||
/*
|
||||
* Copyright © 1991-2015 Unicode, Inc. All rights reserved.
|
||||
* Distributed under the Terms of Use in
|
||||
* http://www.unicode.org/copyright.html.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of the Unicode data files and any associated documentation
|
||||
* (the "Data Files") or Unicode software and any associated documentation
|
||||
* (the "Software") to deal in the Data Files or Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, and/or sell copies of
|
||||
* the Data Files or Software, and to permit persons to whom the Data Files
|
||||
* or Software are furnished to do so, provided that
|
||||
* (a) this copyright and permission notice appear with all copies
|
||||
* of the Data Files or Software,
|
||||
* (b) this copyright and permission notice appear in associated
|
||||
* documentation, and
|
||||
* (c) there is clear notice in each modified Data File or in the Software
|
||||
* as well as in the documentation associated with the Data File(s) or
|
||||
* Software that the data or software has been modified.
|
||||
*
|
||||
* THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
|
||||
* NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
|
||||
* DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of a copyright holder
|
||||
* shall not be used in advertising or otherwise to promote the sale,
|
||||
* use or other dealings in these Data Files or Software without prior
|
||||
* written authorization of the copyright holder.
|
||||
*/
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
|
||||
Author: Mark E. Davis, 1994.
|
||||
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||
Sept 2001: fixed const & error conditions per
|
||||
mods suggested by S. Parent & A. Lillich.
|
||||
June 2002: Tim Dodd added detection and handling of incomplete
|
||||
source sequences, enhanced error detection, added casts
|
||||
to eliminate compiler warnings.
|
||||
July 2003: slight mods to back out aggressive FFFE detection.
|
||||
Jan 2004: updated switches in from-UTF8 conversions.
|
||||
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
|
||||
|
||||
See the header file "ConvertUTF.h" for complete documentation.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "convert_UTF.h"
|
||||
#ifdef CVTUTF_DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "common/macros.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
namespace {
|
||||
|
||||
const int halfShift = 10; /* used for shifting by 10 bits */
|
||||
|
||||
const UTF32 halfBase = 0x0010000UL;
|
||||
const UTF32 halfMask = 0x3FFUL;
|
||||
|
||||
} // namespace
|
||||
|
||||
#define UNI_SUR_HIGH_START (UTF32)0xD800
|
||||
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
|
||||
#define UNI_SUR_LOW_START (UTF32)0xDC00
|
||||
#define UNI_SUR_LOW_END (UTF32)0xDFFF
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF32* source = *sourceStart;
|
||||
UTF16* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
if (target >= targetEnd) {
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch = *source++;
|
||||
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||
/* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = (UTF16)ch; /* normal case */
|
||||
}
|
||||
} else if (ch > UNI_MAX_LEGAL_UTF32) {
|
||||
if (flags == strictConversion) {
|
||||
result = sourceIllegal;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||
if (target + 1 >= targetEnd) {
|
||||
--source; /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch -= halfBase;
|
||||
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF16* source = *sourceStart;
|
||||
UTF32* target = *targetStart;
|
||||
UTF32 ch, ch2;
|
||||
while (source < sourceEnd) {
|
||||
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||
ch = *source++;
|
||||
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
|
||||
/* If the 16 bits following the high surrogate are in the source buffer... */
|
||||
if (source < sourceEnd) {
|
||||
ch2 = *source;
|
||||
/* If it's a low surrogate, convert to UTF32. */
|
||||
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||
++source;
|
||||
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
} else { /* We don't have the 16 bits following the high surrogate. */
|
||||
--source; /* return to the high surrogate */
|
||||
result = sourceExhausted;
|
||||
break;
|
||||
}
|
||||
} else if (flags == strictConversion) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (target >= targetEnd) {
|
||||
source = oldSource; /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
*target++ = ch;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
#ifdef CVTUTF_DEBUG
|
||||
if (result == sourceIllegal) {
|
||||
fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
|
||||
fflush(stderr);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
* Index into the table below with the first byte of a UTF-8 sequence to
|
||||
* get the number of trailing bytes that are supposed to follow it.
|
||||
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
|
||||
* left as-is for anyone who may want to do such conversion, which was
|
||||
* allowed in earlier algorithms.
|
||||
*/
|
||||
const char trailingBytesForUTF8[256] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||
};
|
||||
|
||||
/*
|
||||
* Magic values subtracted from a buffer value during UTF8 conversion.
|
||||
* This table contains as many values as there might be trailing bytes
|
||||
* in a UTF-8 sequence.
|
||||
*/
|
||||
const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
|
||||
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
|
||||
|
||||
/*
|
||||
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
|
||||
* into the first byte, depending on how many bytes follow. There are
|
||||
* as many entries in this table as there are UTF-8 sequence types.
|
||||
* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
|
||||
* for *legal* UTF-8 will be 4 or fewer bytes total.
|
||||
*/
|
||||
const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/* The interface converts a whole buffer to avoid function-call overhead.
|
||||
* Constants have been gathered. Loops & conditionals have been removed as
|
||||
* much as possible for efficiency, in favor of drop-through switches.
|
||||
* (See "Note A" at the bottom of the file for equivalent code.)
|
||||
* If your compiler supports it, the "isLegalUTF8" call can be turned
|
||||
* into an inline function.
|
||||
*/
|
||||
|
||||
} // namespace
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF16* source = *sourceStart;
|
||||
UTF8* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
unsigned short bytesToWrite = 0;
|
||||
const UTF32 byteMask = 0xBF;
|
||||
const UTF32 byteMark = 0x80;
|
||||
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
|
||||
ch = *source++;
|
||||
/* If we have a surrogate pair, convert to UTF32 first. */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
|
||||
/* If the 16 bits following the high surrogate are in the source buffer... */
|
||||
if (source < sourceEnd) {
|
||||
UTF32 ch2 = *source;
|
||||
/* If it's a low surrogate, convert to UTF32. */
|
||||
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
|
||||
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
|
||||
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
|
||||
++source;
|
||||
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
} else { /* We don't have the 16 bits following the high surrogate. */
|
||||
--source; /* return to the high surrogate */
|
||||
result = sourceExhausted;
|
||||
break;
|
||||
}
|
||||
} else if (flags == strictConversion) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Figure out how many bytes the result will require */
|
||||
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||
} else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
|
||||
} else { bytesToWrite = 3;
|
||||
ch = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
|
||||
target += bytesToWrite;
|
||||
if (target > targetEnd) {
|
||||
source = oldSource; /* Back up source pointer! */
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
case 4:
|
||||
*--target = (UTF8)((ch | byteMark) & byteMask);
|
||||
ch >>= 6;
|
||||
BP_FALLTHROUGH;
|
||||
case 3:
|
||||
*--target = (UTF8)((ch | byteMark) & byteMask);
|
||||
ch >>= 6;
|
||||
BP_FALLTHROUGH;
|
||||
case 2:
|
||||
*--target = (UTF8)((ch | byteMark) & byteMask);
|
||||
ch >>= 6;
|
||||
BP_FALLTHROUGH;
|
||||
case 1:
|
||||
*--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
|
||||
}
|
||||
target += bytesToWrite;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
|
||||
* This must be called with the length pre-determined by the first byte.
|
||||
* If not calling this from ConvertUTF8to*, then the length can be set by:
|
||||
* length = trailingBytesForUTF8[*source]+1;
|
||||
* and the sequence is illegal right away if there aren't that many bytes
|
||||
* available.
|
||||
* If presented with a length > 4, this returns false. The Unicode
|
||||
* definition of UTF-8 goes up to 4-byte sequences.
|
||||
*/
|
||||
Boolean isLegalUTF8(const UTF8 *source, int length) {
|
||||
UTF8 a;
|
||||
const UTF8 *srcptr = source+length;
|
||||
switch (length) {
|
||||
default: return false;
|
||||
/* Everything else falls through when "true"... */
|
||||
case 4:
|
||||
if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
BP_FALLTHROUGH;
|
||||
case 3:
|
||||
if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
|
||||
BP_FALLTHROUGH;
|
||||
case 2:
|
||||
if ((a = (*--srcptr)) > 0xBF) return false;
|
||||
|
||||
switch (*source) {
|
||||
/* no fall-through in this inner switch */
|
||||
case 0xE0: if (a < 0xA0) return false; break;
|
||||
case 0xED: if (a > 0x9F) return false; break;
|
||||
case 0xF0: if (a < 0x90) return false; break;
|
||||
case 0xF4: if (a > 0x8F) return false; break;
|
||||
default: if (a < 0x80) return false;
|
||||
}
|
||||
BP_FALLTHROUGH;
|
||||
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
|
||||
}
|
||||
if (*source > 0xF4) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
/*
|
||||
* Exported function to return whether a UTF-8 sequence is legal or not.
|
||||
* This is not used here; it's just exported.
|
||||
*/
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
|
||||
int length = trailingBytesForUTF8[*source]+1;
|
||||
if (source+length > sourceEnd) {
|
||||
return false;
|
||||
}
|
||||
return isLegalUTF8(source, length);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF8* source = *sourceStart;
|
||||
UTF16* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch = 0;
|
||||
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||
if (source + extraBytesToRead >= sourceEnd) {
|
||||
result = sourceExhausted; break;
|
||||
}
|
||||
/* Do this check whether lenient or strict */
|
||||
if (! isLegalUTF8(source, extraBytesToRead+1)) {
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
/* remember, illegal UTF-8 */
|
||||
case 5: ch += *source++; ch <<= 6; BP_FALLTHROUGH;
|
||||
/* remember, illegal UTF-8 */
|
||||
case 4: ch += *source++; ch <<= 6; BP_FALLTHROUGH;
|
||||
case 3: ch += *source++; ch <<= 6; BP_FALLTHROUGH;
|
||||
case 2: ch += *source++; ch <<= 6; BP_FALLTHROUGH;
|
||||
case 1: ch += *source++; ch <<= 6; BP_FALLTHROUGH;
|
||||
case 0: ch += *source++;
|
||||
}
|
||||
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||
|
||||
if (target >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = (UTF16)ch; /* normal case */
|
||||
}
|
||||
} else if (ch > UNI_MAX_UTF16) {
|
||||
if (flags == strictConversion) {
|
||||
result = sourceIllegal;
|
||||
source -= (extraBytesToRead+1); /* return to the start */
|
||||
break; /* Bail out; shouldn't continue */
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
/* target is a character in range 0xFFFF - 0x10FFFF. */
|
||||
if (target + 1 >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
ch -= halfBase;
|
||||
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
|
||||
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF32* source = *sourceStart;
|
||||
UTF8* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch;
|
||||
unsigned short bytesToWrite = 0;
|
||||
const UTF32 byteMask = 0xBF;
|
||||
const UTF32 byteMark = 0x80;
|
||||
ch = *source++;
|
||||
if (flags == strictConversion ) {
|
||||
/* UTF-16 surrogate values are illegal in UTF-32 */
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
--source; /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Figure out how many bytes the result will require. Turn any
|
||||
* illegally large UTF32 things (> Plane 17) into replacement chars.
|
||||
*/
|
||||
if (ch < (UTF32)0x80) { bytesToWrite = 1;
|
||||
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
|
||||
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
|
||||
} else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
|
||||
} else { bytesToWrite = 3;
|
||||
ch = UNI_REPLACEMENT_CHAR;
|
||||
result = sourceIllegal;
|
||||
}
|
||||
|
||||
target += bytesToWrite;
|
||||
if (target > targetEnd) {
|
||||
--source; /* Back up source pointer! */
|
||||
target -= bytesToWrite; result = targetExhausted; break;
|
||||
}
|
||||
switch (bytesToWrite) { /* note: everything falls through. */
|
||||
case 4:
|
||||
*--target = (UTF8)((ch | byteMark) & byteMask);
|
||||
ch >>= 6;
|
||||
BP_FALLTHROUGH;
|
||||
case 3:
|
||||
*--target = (UTF8)((ch | byteMark) & byteMask);
|
||||
ch >>= 6;
|
||||
BP_FALLTHROUGH;
|
||||
case 2:
|
||||
*--target = (UTF8)((ch | byteMark) & byteMask);
|
||||
ch >>= 6;
|
||||
BP_FALLTHROUGH;
|
||||
case 1:
|
||||
*--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
|
||||
}
|
||||
target += bytesToWrite;
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
|
||||
ConversionResult result = conversionOK;
|
||||
const UTF8* source = *sourceStart;
|
||||
UTF32* target = *targetStart;
|
||||
while (source < sourceEnd) {
|
||||
UTF32 ch = 0;
|
||||
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
|
||||
if (source + extraBytesToRead >= sourceEnd) {
|
||||
result = sourceExhausted; break;
|
||||
}
|
||||
/* Do this check whether lenient or strict */
|
||||
if (! isLegalUTF8(source, extraBytesToRead+1)) {
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* The cases all fall through. See "Note A" below.
|
||||
*/
|
||||
switch (extraBytesToRead) {
|
||||
case 5: ch += *source++; ch <<= 6; BP_FALLTHROUGH;
|
||||
case 4: ch += *source++; ch <<= 6; BP_FALLTHROUGH;
|
||||
case 3: ch += *source++; ch <<= 6; BP_FALLTHROUGH;
|
||||
case 2: ch += *source++; ch <<= 6; BP_FALLTHROUGH;
|
||||
case 1: ch += *source++; ch <<= 6; BP_FALLTHROUGH;
|
||||
case 0: ch += *source++;
|
||||
}
|
||||
ch -= offsetsFromUTF8[extraBytesToRead];
|
||||
|
||||
if (target >= targetEnd) {
|
||||
source -= (extraBytesToRead+1); /* Back up the source pointer! */
|
||||
result = targetExhausted; break;
|
||||
}
|
||||
if (ch <= UNI_MAX_LEGAL_UTF32) {
|
||||
/*
|
||||
* UTF-16 surrogate values are illegal in UTF-32, and anything
|
||||
* over Plane 17 (> 0x10FFFF) is illegal.
|
||||
*/
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
|
||||
if (flags == strictConversion) {
|
||||
source -= (extraBytesToRead+1); /* return to the illegal value itself */
|
||||
result = sourceIllegal;
|
||||
break;
|
||||
} else {
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
} else {
|
||||
*target++ = ch;
|
||||
}
|
||||
} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
|
||||
result = sourceIllegal;
|
||||
*target++ = UNI_REPLACEMENT_CHAR;
|
||||
}
|
||||
}
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Note A.
|
||||
The fall-through switches in UTF-8 reading code save a
|
||||
temp variable, some decrements & conditionals. The switches
|
||||
are equivalent to the following loop:
|
||||
{
|
||||
int tmpBytesToRead = extraBytesToRead+1;
|
||||
do {
|
||||
ch += *source++;
|
||||
--tmpBytesToRead;
|
||||
if (tmpBytesToRead) ch <<= 6;
|
||||
} while (tmpBytesToRead > 0);
|
||||
}
|
||||
In UTF-8 writing code, the switches on "bytesToWrite" are
|
||||
similarly unrolled loops.
|
||||
|
||||
--------------------------------------------------------------------- */
|
||||
|
||||
} // namespace google_breakpad
|
||||
159
externals/breakpad/src/common/convert_UTF.h
vendored
Normal file
159
externals/breakpad/src/common/convert_UTF.h
vendored
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright © 1991-2015 Unicode, Inc. All rights reserved.
|
||||
* Distributed under the Terms of Use in
|
||||
* http://www.unicode.org/copyright.html.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of the Unicode data files and any associated documentation
|
||||
* (the "Data Files") or Unicode software and any associated documentation
|
||||
* (the "Software") to deal in the Data Files or Software
|
||||
* without restriction, including without limitation the rights to use,
|
||||
* copy, modify, merge, publish, distribute, and/or sell copies of
|
||||
* the Data Files or Software, and to permit persons to whom the Data Files
|
||||
* or Software are furnished to do so, provided that
|
||||
* (a) this copyright and permission notice appear with all copies
|
||||
* of the Data Files or Software,
|
||||
* (b) this copyright and permission notice appear in associated
|
||||
* documentation, and
|
||||
* (c) there is clear notice in each modified Data File or in the Software
|
||||
* as well as in the documentation associated with the Data File(s) or
|
||||
* Software that the data or software has been modified.
|
||||
*
|
||||
* THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
* ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
|
||||
* NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
|
||||
* DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THE DATA FILES OR SOFTWARE.
|
||||
*
|
||||
* Except as contained in this notice, the name of a copyright holder
|
||||
* shall not be used in advertising or otherwise to promote the sale,
|
||||
* use or other dealings in these Data Files or Software without prior
|
||||
* written authorization of the copyright holder.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_CONVERT_UTF_H_
|
||||
#define COMMON_CONVERT_UTF_H_
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
|
||||
Conversions between UTF32, UTF-16, and UTF-8. Header file.
|
||||
|
||||
Several funtions are included here, forming a complete set of
|
||||
conversions between the three formats. UTF-7 is not included
|
||||
here, but is handled in a separate source file.
|
||||
|
||||
Each of these routines takes pointers to input buffers and output
|
||||
buffers. The input buffers are const.
|
||||
|
||||
Each routine converts the text between *sourceStart and sourceEnd,
|
||||
putting the result into the buffer between *targetStart and
|
||||
targetEnd. Note: the end pointers are *after* the last item: e.g.
|
||||
*(sourceEnd - 1) is the last item.
|
||||
|
||||
The return result indicates whether the conversion was successful,
|
||||
and if not, whether the problem was in the source or target buffers.
|
||||
(Only the first encountered problem is indicated.)
|
||||
|
||||
After the conversion, *sourceStart and *targetStart are both
|
||||
updated to point to the end of last text successfully converted in
|
||||
the respective buffers.
|
||||
|
||||
Input parameters:
|
||||
sourceStart - pointer to a pointer to the source buffer.
|
||||
The contents of this are modified on return so that
|
||||
it points at the next thing to be converted.
|
||||
targetStart - similarly, pointer to pointer to the target buffer.
|
||||
sourceEnd, targetEnd - respectively pointers to the ends of the
|
||||
two buffers, for overflow checking only.
|
||||
|
||||
These conversion functions take a ConversionFlags argument. When this
|
||||
flag is set to strict, both irregular sequences and isolated surrogates
|
||||
will cause an error. When the flag is set to lenient, both irregular
|
||||
sequences and isolated surrogates are converted.
|
||||
|
||||
Whether the flag is strict or lenient, all illegal sequences will cause
|
||||
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
|
||||
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
|
||||
must check for illegal sequences.
|
||||
|
||||
When the flag is set to lenient, characters over 0x10FFFF are converted
|
||||
to the replacement character; otherwise (when the flag is set to strict)
|
||||
they constitute an error.
|
||||
|
||||
Output parameters:
|
||||
The value "sourceIllegal" is returned from some routines if the input
|
||||
sequence is malformed. When "sourceIllegal" is returned, the source
|
||||
value will point to the illegal value that caused the problem. E.g.,
|
||||
in UTF-8 when a sequence is malformed, it points to the start of the
|
||||
malformed sequence.
|
||||
|
||||
Author: Mark E. Davis, 1994.
|
||||
Rev History: Rick McGowan, fixes & updates May 2001.
|
||||
Fixes & updates, Sept 2001.
|
||||
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
The following 4 definitions are compiler-specific.
|
||||
The C standard does not guarantee that wchar_t has at least
|
||||
16 bits, so wchar_t is no less portable than unsigned short!
|
||||
All should be unsigned values to avoid sign extension during
|
||||
bit mask & shift operations.
|
||||
------------------------------------------------------------------------ */
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
typedef unsigned long UTF32; /* at least 32 bits */
|
||||
typedef unsigned short UTF16; /* at least 16 bits */
|
||||
typedef unsigned char UTF8; /* typically 8 bits */
|
||||
typedef unsigned char Boolean; /* 0 or 1 */
|
||||
|
||||
/* Some fundamental constants */
|
||||
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
|
||||
#define UNI_MAX_BMP (UTF32)0x0000FFFF
|
||||
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
|
||||
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
|
||||
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
|
||||
|
||||
typedef enum {
|
||||
conversionOK, /* conversion successful */
|
||||
sourceExhausted, /* partial character in source, but hit end */
|
||||
targetExhausted, /* insuff. room in target for conversion */
|
||||
sourceIllegal /* source sequence is illegal/malformed */
|
||||
} ConversionResult;
|
||||
|
||||
typedef enum {
|
||||
strictConversion = 0,
|
||||
lenientConversion
|
||||
} ConversionFlags;
|
||||
|
||||
ConversionResult ConvertUTF8toUTF16 (const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF16toUTF8 (const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF8toUTF32 (const UTF8** sourceStart, const UTF8* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF32toUTF8 (const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF16toUTF32 (const UTF16** sourceStart, const UTF16* sourceEnd,
|
||||
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
|
||||
|
||||
ConversionResult ConvertUTF32toUTF16 (const UTF32** sourceStart, const UTF32* sourceEnd,
|
||||
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
|
||||
|
||||
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
#endif // COMMON_CONVERT_UTF_H_
|
||||
181
externals/breakpad/src/common/dwarf/bytereader-inl.h
vendored
Normal file
181
externals/breakpad/src/common/dwarf/bytereader-inl.h
vendored
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
// Copyright 2006 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef UTIL_DEBUGINFO_BYTEREADER_INL_H__
|
||||
#define UTIL_DEBUGINFO_BYTEREADER_INL_H__
|
||||
|
||||
#include "common/dwarf/bytereader.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
inline uint8_t ByteReader::ReadOneByte(const uint8_t* buffer) const {
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
inline uint16_t ByteReader::ReadTwoBytes(const uint8_t* buffer) const {
|
||||
const uint16_t buffer0 = buffer[0];
|
||||
const uint16_t buffer1 = buffer[1];
|
||||
if (endian_ == ENDIANNESS_LITTLE) {
|
||||
return buffer0 | buffer1 << 8;
|
||||
} else {
|
||||
return buffer1 | buffer0 << 8;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint64_t ByteReader::ReadThreeBytes(const uint8_t* buffer) const {
|
||||
const uint32_t buffer0 = buffer[0];
|
||||
const uint32_t buffer1 = buffer[1];
|
||||
const uint32_t buffer2 = buffer[2];
|
||||
if (endian_ == ENDIANNESS_LITTLE) {
|
||||
return buffer0 | buffer1 << 8 | buffer2 << 16;
|
||||
} else {
|
||||
return buffer2 | buffer1 << 8 | buffer0 << 16;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint64_t ByteReader::ReadFourBytes(const uint8_t* buffer) const {
|
||||
const uint32_t buffer0 = buffer[0];
|
||||
const uint32_t buffer1 = buffer[1];
|
||||
const uint32_t buffer2 = buffer[2];
|
||||
const uint32_t buffer3 = buffer[3];
|
||||
if (endian_ == ENDIANNESS_LITTLE) {
|
||||
return buffer0 | buffer1 << 8 | buffer2 << 16 | buffer3 << 24;
|
||||
} else {
|
||||
return buffer3 | buffer2 << 8 | buffer1 << 16 | buffer0 << 24;
|
||||
}
|
||||
}
|
||||
|
||||
inline uint64_t ByteReader::ReadEightBytes(const uint8_t* buffer) const {
|
||||
const uint64_t buffer0 = buffer[0];
|
||||
const uint64_t buffer1 = buffer[1];
|
||||
const uint64_t buffer2 = buffer[2];
|
||||
const uint64_t buffer3 = buffer[3];
|
||||
const uint64_t buffer4 = buffer[4];
|
||||
const uint64_t buffer5 = buffer[5];
|
||||
const uint64_t buffer6 = buffer[6];
|
||||
const uint64_t buffer7 = buffer[7];
|
||||
if (endian_ == ENDIANNESS_LITTLE) {
|
||||
return buffer0 | buffer1 << 8 | buffer2 << 16 | buffer3 << 24 |
|
||||
buffer4 << 32 | buffer5 << 40 | buffer6 << 48 | buffer7 << 56;
|
||||
} else {
|
||||
return buffer7 | buffer6 << 8 | buffer5 << 16 | buffer4 << 24 |
|
||||
buffer3 << 32 | buffer2 << 40 | buffer1 << 48 | buffer0 << 56;
|
||||
}
|
||||
}
|
||||
|
||||
// Read an unsigned LEB128 number. Each byte contains 7 bits of
|
||||
// information, plus one bit saying whether the number continues or
|
||||
// not.
|
||||
|
||||
inline uint64_t ByteReader::ReadUnsignedLEB128(const uint8_t* buffer,
|
||||
size_t* len) const {
|
||||
uint64_t result = 0;
|
||||
size_t num_read = 0;
|
||||
unsigned int shift = 0;
|
||||
uint8_t byte;
|
||||
|
||||
do {
|
||||
byte = *buffer++;
|
||||
num_read++;
|
||||
|
||||
result |= (static_cast<uint64_t>(byte & 0x7f)) << shift;
|
||||
|
||||
shift += 7;
|
||||
|
||||
} while (byte & 0x80);
|
||||
|
||||
*len = num_read;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read a signed LEB128 number. These are like regular LEB128
|
||||
// numbers, except the last byte may have a sign bit set.
|
||||
|
||||
inline int64_t ByteReader::ReadSignedLEB128(const uint8_t* buffer,
|
||||
size_t* len) const {
|
||||
int64_t result = 0;
|
||||
unsigned int shift = 0;
|
||||
size_t num_read = 0;
|
||||
uint8_t byte;
|
||||
|
||||
do {
|
||||
byte = *buffer++;
|
||||
num_read++;
|
||||
result |= (static_cast<uint64_t>(byte & 0x7f) << shift);
|
||||
shift += 7;
|
||||
} while (byte & 0x80);
|
||||
|
||||
if ((shift < 8 * sizeof (result)) && (byte & 0x40))
|
||||
result |= -((static_cast<int64_t>(1)) << shift);
|
||||
*len = num_read;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline uint64_t ByteReader::ReadOffset(const uint8_t* buffer) const {
|
||||
assert(this->offset_reader_);
|
||||
return (this->*offset_reader_)(buffer);
|
||||
}
|
||||
|
||||
inline uint64_t ByteReader::ReadAddress(const uint8_t* buffer) const {
|
||||
assert(this->address_reader_);
|
||||
return (this->*address_reader_)(buffer);
|
||||
}
|
||||
|
||||
inline void ByteReader::SetCFIDataBase(uint64_t section_base,
|
||||
const uint8_t* buffer_base) {
|
||||
section_base_ = section_base;
|
||||
buffer_base_ = buffer_base;
|
||||
have_section_base_ = true;
|
||||
}
|
||||
|
||||
inline void ByteReader::SetTextBase(uint64_t text_base) {
|
||||
text_base_ = text_base;
|
||||
have_text_base_ = true;
|
||||
}
|
||||
|
||||
inline void ByteReader::SetDataBase(uint64_t data_base) {
|
||||
data_base_ = data_base;
|
||||
have_data_base_ = true;
|
||||
}
|
||||
|
||||
inline void ByteReader::SetFunctionBase(uint64_t function_base) {
|
||||
function_base_ = function_base;
|
||||
have_function_base_ = true;
|
||||
}
|
||||
|
||||
inline void ByteReader::ClearFunctionBase() {
|
||||
have_function_base_ = false;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // UTIL_DEBUGINFO_BYTEREADER_INL_H__
|
||||
254
externals/breakpad/src/common/dwarf/bytereader.cc
vendored
Normal file
254
externals/breakpad/src/common/dwarf/bytereader.cc
vendored
Normal file
|
|
@ -0,0 +1,254 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common/dwarf/bytereader-inl.h"
|
||||
#include "common/dwarf/bytereader.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
ByteReader::ByteReader(enum Endianness endian)
|
||||
:offset_reader_(NULL), address_reader_(NULL), endian_(endian),
|
||||
address_size_(0), offset_size_(0),
|
||||
have_section_base_(), have_text_base_(), have_data_base_(),
|
||||
have_function_base_() { }
|
||||
|
||||
ByteReader::~ByteReader() { }
|
||||
|
||||
void ByteReader::SetOffsetSize(uint8_t size) {
|
||||
offset_size_ = size;
|
||||
assert(size == 4 || size == 8);
|
||||
if (size == 4) {
|
||||
this->offset_reader_ = &ByteReader::ReadFourBytes;
|
||||
} else {
|
||||
this->offset_reader_ = &ByteReader::ReadEightBytes;
|
||||
}
|
||||
}
|
||||
|
||||
void ByteReader::SetAddressSize(uint8_t size) {
|
||||
address_size_ = size;
|
||||
assert(size == 4 || size == 8);
|
||||
if (size == 4) {
|
||||
this->address_reader_ = &ByteReader::ReadFourBytes;
|
||||
} else {
|
||||
this->address_reader_ = &ByteReader::ReadEightBytes;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ByteReader::ReadInitialLength(const uint8_t* start, size_t* len) {
|
||||
const uint64_t initial_length = ReadFourBytes(start);
|
||||
start += 4;
|
||||
|
||||
// In DWARF2/3, if the initial length is all 1 bits, then the offset
|
||||
// size is 8 and we need to read the next 8 bytes for the real length.
|
||||
if (initial_length == 0xffffffff) {
|
||||
SetOffsetSize(8);
|
||||
*len = 12;
|
||||
return ReadOffset(start);
|
||||
} else {
|
||||
SetOffsetSize(4);
|
||||
*len = 4;
|
||||
}
|
||||
return initial_length;
|
||||
}
|
||||
|
||||
bool ByteReader::ValidEncoding(DwarfPointerEncoding encoding) const {
|
||||
if (encoding == DW_EH_PE_omit) return true;
|
||||
if (encoding == DW_EH_PE_aligned) return true;
|
||||
if ((encoding & 0x7) > DW_EH_PE_udata8)
|
||||
return false;
|
||||
if ((encoding & 0x70) > DW_EH_PE_funcrel)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ByteReader::UsableEncoding(DwarfPointerEncoding encoding) const {
|
||||
switch (encoding & 0x70) {
|
||||
case DW_EH_PE_absptr: return true;
|
||||
case DW_EH_PE_pcrel: return have_section_base_;
|
||||
case DW_EH_PE_textrel: return have_text_base_;
|
||||
case DW_EH_PE_datarel: return have_data_base_;
|
||||
case DW_EH_PE_funcrel: return have_function_base_;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ByteReader::ReadEncodedPointer(const uint8_t* buffer,
|
||||
DwarfPointerEncoding encoding,
|
||||
size_t* len) const {
|
||||
// UsableEncoding doesn't approve of DW_EH_PE_omit, so we shouldn't
|
||||
// see it here.
|
||||
assert(encoding != DW_EH_PE_omit);
|
||||
|
||||
// The Linux Standards Base 4.0 does not make this clear, but the
|
||||
// GNU tools (gcc/unwind-pe.h; readelf/dwarf.c; gdb/dwarf2-frame.c)
|
||||
// agree that aligned pointers are always absolute, machine-sized,
|
||||
// machine-signed pointers.
|
||||
if (encoding == DW_EH_PE_aligned) {
|
||||
assert(have_section_base_);
|
||||
|
||||
// We don't need to align BUFFER in *our* address space. Rather, we
|
||||
// need to find the next position in our buffer that would be aligned
|
||||
// when the .eh_frame section the buffer contains is loaded into the
|
||||
// program's memory. So align assuming that buffer_base_ gets loaded at
|
||||
// address section_base_, where section_base_ itself may or may not be
|
||||
// aligned.
|
||||
|
||||
// First, find the offset to START from the closest prior aligned
|
||||
// address.
|
||||
uint64_t skew = section_base_ & (AddressSize() - 1);
|
||||
// Now find the offset from that aligned address to buffer.
|
||||
uint64_t offset = skew + (buffer - buffer_base_);
|
||||
// Round up to the next boundary.
|
||||
uint64_t aligned = (offset + AddressSize() - 1) & -AddressSize();
|
||||
// Convert back to a pointer.
|
||||
const uint8_t* aligned_buffer = buffer_base_ + (aligned - skew);
|
||||
// Finally, store the length and actually fetch the pointer.
|
||||
*len = aligned_buffer - buffer + AddressSize();
|
||||
return ReadAddress(aligned_buffer);
|
||||
}
|
||||
|
||||
// Extract the value first, ignoring whether it's a pointer or an
|
||||
// offset relative to some base.
|
||||
uint64_t offset;
|
||||
switch (encoding & 0x0f) {
|
||||
case DW_EH_PE_absptr:
|
||||
// DW_EH_PE_absptr is weird, as it is used as a meaningful value for
|
||||
// both the high and low nybble of encoding bytes. When it appears in
|
||||
// the high nybble, it means that the pointer is absolute, not an
|
||||
// offset from some base address. When it appears in the low nybble,
|
||||
// as here, it means that the pointer is stored as a normal
|
||||
// machine-sized and machine-signed address. A low nybble of
|
||||
// DW_EH_PE_absptr does not imply that the pointer is absolute; it is
|
||||
// correct for us to treat the value as an offset from a base address
|
||||
// if the upper nybble is not DW_EH_PE_absptr.
|
||||
offset = ReadAddress(buffer);
|
||||
*len = AddressSize();
|
||||
break;
|
||||
|
||||
case DW_EH_PE_uleb128:
|
||||
offset = ReadUnsignedLEB128(buffer, len);
|
||||
break;
|
||||
|
||||
case DW_EH_PE_udata2:
|
||||
offset = ReadTwoBytes(buffer);
|
||||
*len = 2;
|
||||
break;
|
||||
|
||||
case DW_EH_PE_udata4:
|
||||
offset = ReadFourBytes(buffer);
|
||||
*len = 4;
|
||||
break;
|
||||
|
||||
case DW_EH_PE_udata8:
|
||||
offset = ReadEightBytes(buffer);
|
||||
*len = 8;
|
||||
break;
|
||||
|
||||
case DW_EH_PE_sleb128:
|
||||
offset = ReadSignedLEB128(buffer, len);
|
||||
break;
|
||||
|
||||
case DW_EH_PE_sdata2:
|
||||
offset = ReadTwoBytes(buffer);
|
||||
// Sign-extend from 16 bits.
|
||||
offset = (offset ^ 0x8000) - 0x8000;
|
||||
*len = 2;
|
||||
break;
|
||||
|
||||
case DW_EH_PE_sdata4:
|
||||
offset = ReadFourBytes(buffer);
|
||||
// Sign-extend from 32 bits.
|
||||
offset = (offset ^ 0x80000000ULL) - 0x80000000ULL;
|
||||
*len = 4;
|
||||
break;
|
||||
|
||||
case DW_EH_PE_sdata8:
|
||||
// No need to sign-extend; this is the full width of our type.
|
||||
offset = ReadEightBytes(buffer);
|
||||
*len = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
// Find the appropriate base address.
|
||||
uint64_t base;
|
||||
switch (encoding & 0x70) {
|
||||
case DW_EH_PE_absptr:
|
||||
base = 0;
|
||||
break;
|
||||
|
||||
case DW_EH_PE_pcrel:
|
||||
assert(have_section_base_);
|
||||
base = section_base_ + (buffer - buffer_base_);
|
||||
break;
|
||||
|
||||
case DW_EH_PE_textrel:
|
||||
assert(have_text_base_);
|
||||
base = text_base_;
|
||||
break;
|
||||
|
||||
case DW_EH_PE_datarel:
|
||||
assert(have_data_base_);
|
||||
base = data_base_;
|
||||
break;
|
||||
|
||||
case DW_EH_PE_funcrel:
|
||||
assert(have_function_base_);
|
||||
base = function_base_;
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
uint64_t pointer = base + offset;
|
||||
|
||||
// Remove inappropriate upper bits.
|
||||
if (AddressSize() == 4)
|
||||
pointer = pointer & 0xffffffff;
|
||||
else
|
||||
assert(AddressSize() == sizeof(uint64_t));
|
||||
|
||||
return pointer;
|
||||
}
|
||||
|
||||
Endianness ByteReader::GetEndianness() const {
|
||||
return endian_;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
320
externals/breakpad/src/common/dwarf/bytereader.h
vendored
Normal file
320
externals/breakpad/src/common/dwarf/bytereader.h
vendored
Normal file
|
|
@ -0,0 +1,320 @@
|
|||
// -*- mode: C++ -*-
|
||||
|
||||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef COMMON_DWARF_BYTEREADER_H__
|
||||
#define COMMON_DWARF_BYTEREADER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/dwarf/types.h"
|
||||
#include "common/dwarf/dwarf2enums.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// We can't use the obvious name of LITTLE_ENDIAN and BIG_ENDIAN
|
||||
// because it conflicts with a macro
|
||||
enum Endianness {
|
||||
ENDIANNESS_BIG,
|
||||
ENDIANNESS_LITTLE
|
||||
};
|
||||
|
||||
// A ByteReader knows how to read single- and multi-byte values of
|
||||
// various endiannesses, sizes, and encodings, as used in DWARF
|
||||
// debugging information and Linux C++ exception handling data.
|
||||
class ByteReader {
|
||||
public:
|
||||
// Construct a ByteReader capable of reading one-, two-, four-, and
|
||||
// eight-byte values according to ENDIANNESS, absolute machine-sized
|
||||
// addresses, DWARF-style "initial length" values, signed and
|
||||
// unsigned LEB128 numbers, and Linux C++ exception handling data's
|
||||
// encoded pointers.
|
||||
explicit ByteReader(enum Endianness endianness);
|
||||
virtual ~ByteReader();
|
||||
|
||||
// Read a single byte from BUFFER and return it as an unsigned 8 bit
|
||||
// number.
|
||||
uint8_t ReadOneByte(const uint8_t* buffer) const;
|
||||
|
||||
// Read two bytes from BUFFER and return them as an unsigned 16 bit
|
||||
// number, using this ByteReader's endianness.
|
||||
uint16_t ReadTwoBytes(const uint8_t* buffer) const;
|
||||
|
||||
// Read three bytes from BUFFER and return them as an unsigned 64 bit
|
||||
// number, using this ByteReader's endianness. DWARF 5 uses this encoding
|
||||
// for various index-related DW_FORMs.
|
||||
uint64_t ReadThreeBytes(const uint8_t* buffer) const;
|
||||
|
||||
// Read four bytes from BUFFER and return them as an unsigned 32 bit
|
||||
// number, using this ByteReader's endianness. This function returns
|
||||
// a uint64_t so that it is compatible with ReadAddress and
|
||||
// ReadOffset. The number it returns will never be outside the range
|
||||
// of an unsigned 32 bit integer.
|
||||
uint64_t ReadFourBytes(const uint8_t* buffer) const;
|
||||
|
||||
// Read eight bytes from BUFFER and return them as an unsigned 64
|
||||
// bit number, using this ByteReader's endianness.
|
||||
uint64_t ReadEightBytes(const uint8_t* buffer) const;
|
||||
|
||||
// Read an unsigned LEB128 (Little Endian Base 128) number from
|
||||
// BUFFER and return it as an unsigned 64 bit integer. Set LEN to
|
||||
// the number of bytes read.
|
||||
//
|
||||
// The unsigned LEB128 representation of an integer N is a variable
|
||||
// number of bytes:
|
||||
//
|
||||
// - If N is between 0 and 0x7f, then its unsigned LEB128
|
||||
// representation is a single byte whose value is N.
|
||||
//
|
||||
// - Otherwise, its unsigned LEB128 representation is (N & 0x7f) |
|
||||
// 0x80, followed by the unsigned LEB128 representation of N /
|
||||
// 128, rounded towards negative infinity.
|
||||
//
|
||||
// In other words, we break VALUE into groups of seven bits, put
|
||||
// them in little-endian order, and then write them as eight-bit
|
||||
// bytes with the high bit on all but the last.
|
||||
uint64_t ReadUnsignedLEB128(const uint8_t* buffer, size_t* len) const;
|
||||
|
||||
// Read a signed LEB128 number from BUFFER and return it as an
|
||||
// signed 64 bit integer. Set LEN to the number of bytes read.
|
||||
//
|
||||
// The signed LEB128 representation of an integer N is a variable
|
||||
// number of bytes:
|
||||
//
|
||||
// - If N is between -0x40 and 0x3f, then its signed LEB128
|
||||
// representation is a single byte whose value is N in two's
|
||||
// complement.
|
||||
//
|
||||
// - Otherwise, its signed LEB128 representation is (N & 0x7f) |
|
||||
// 0x80, followed by the signed LEB128 representation of N / 128,
|
||||
// rounded towards negative infinity.
|
||||
//
|
||||
// In other words, we break VALUE into groups of seven bits, put
|
||||
// them in little-endian order, and then write them as eight-bit
|
||||
// bytes with the high bit on all but the last.
|
||||
int64_t ReadSignedLEB128(const uint8_t* buffer, size_t* len) const;
|
||||
|
||||
// Indicate that addresses on this architecture are SIZE bytes long. SIZE
|
||||
// must be either 4 or 8. (DWARF allows addresses to be any number of
|
||||
// bytes in length from 1 to 255, but we only support 32- and 64-bit
|
||||
// addresses at the moment.) You must call this before using the
|
||||
// ReadAddress member function.
|
||||
//
|
||||
// For data in a .debug_info section, or something that .debug_info
|
||||
// refers to like line number or macro data, the compilation unit
|
||||
// header's address_size field indicates the address size to use. Call
|
||||
// frame information doesn't indicate its address size (a shortcoming of
|
||||
// the spec); you must supply the appropriate size based on the
|
||||
// architecture of the target machine.
|
||||
void SetAddressSize(uint8_t size);
|
||||
|
||||
// Return the current address size, in bytes. This is either 4,
|
||||
// indicating 32-bit addresses, or 8, indicating 64-bit addresses.
|
||||
uint8_t AddressSize() const { return address_size_; }
|
||||
|
||||
// Read an address from BUFFER and return it as an unsigned 64 bit
|
||||
// integer, respecting this ByteReader's endianness and address size. You
|
||||
// must call SetAddressSize before calling this function.
|
||||
uint64_t ReadAddress(const uint8_t* buffer) const;
|
||||
|
||||
// DWARF actually defines two slightly different formats: 32-bit DWARF
|
||||
// and 64-bit DWARF. This is *not* related to the size of registers or
|
||||
// addresses on the target machine; it refers only to the size of section
|
||||
// offsets and data lengths appearing in the DWARF data. One only needs
|
||||
// 64-bit DWARF when the debugging data itself is larger than 4GiB.
|
||||
// 32-bit DWARF can handle x86_64 or PPC64 code just fine, unless the
|
||||
// debugging data itself is very large.
|
||||
//
|
||||
// DWARF information identifies itself as 32-bit or 64-bit DWARF: each
|
||||
// compilation unit and call frame information entry begins with an
|
||||
// "initial length" field, which, in addition to giving the length of the
|
||||
// data, also indicates the size of section offsets and lengths appearing
|
||||
// in that data. The ReadInitialLength member function, below, reads an
|
||||
// initial length and sets the ByteReader's offset size as a side effect.
|
||||
// Thus, in the normal process of reading DWARF data, the appropriate
|
||||
// offset size is set automatically. So, you should only need to call
|
||||
// SetOffsetSize if you are using the same ByteReader to jump from the
|
||||
// midst of one block of DWARF data into another.
|
||||
|
||||
// Read a DWARF "initial length" field from START, and return it as
|
||||
// an unsigned 64 bit integer, respecting this ByteReader's
|
||||
// endianness. Set *LEN to the length of the initial length in
|
||||
// bytes, either four or twelve. As a side effect, set this
|
||||
// ByteReader's offset size to either 4 (if we see a 32-bit DWARF
|
||||
// initial length) or 8 (if we see a 64-bit DWARF initial length).
|
||||
//
|
||||
// A DWARF initial length is either:
|
||||
//
|
||||
// - a byte count stored as an unsigned 32-bit value less than
|
||||
// 0xffffff00, indicating that the data whose length is being
|
||||
// measured uses the 32-bit DWARF format, or
|
||||
//
|
||||
// - The 32-bit value 0xffffffff, followed by a 64-bit byte count,
|
||||
// indicating that the data whose length is being measured uses
|
||||
// the 64-bit DWARF format.
|
||||
uint64_t ReadInitialLength(const uint8_t* start, size_t* len);
|
||||
|
||||
// Read an offset from BUFFER and return it as an unsigned 64 bit
|
||||
// integer, respecting the ByteReader's endianness. In 32-bit DWARF, the
|
||||
// offset is 4 bytes long; in 64-bit DWARF, the offset is eight bytes
|
||||
// long. You must call ReadInitialLength or SetOffsetSize before calling
|
||||
// this function; see the comments above for details.
|
||||
uint64_t ReadOffset(const uint8_t* buffer) const;
|
||||
|
||||
// Return the current offset size, in bytes.
|
||||
// A return value of 4 indicates that we are reading 32-bit DWARF.
|
||||
// A return value of 8 indicates that we are reading 64-bit DWARF.
|
||||
uint8_t OffsetSize() const { return offset_size_; }
|
||||
|
||||
// Indicate that section offsets and lengths are SIZE bytes long. SIZE
|
||||
// must be either 4 (meaning 32-bit DWARF) or 8 (meaning 64-bit DWARF).
|
||||
// Usually, you should not call this function yourself; instead, let a
|
||||
// call to ReadInitialLength establish the data's offset size
|
||||
// automatically.
|
||||
void SetOffsetSize(uint8_t size);
|
||||
|
||||
// The Linux C++ ABI uses a variant of DWARF call frame information
|
||||
// for exception handling. This data is included in the program's
|
||||
// address space as the ".eh_frame" section, and intepreted at
|
||||
// runtime to walk the stack, find exception handlers, and run
|
||||
// cleanup code. The format is mostly the same as DWARF CFI, with
|
||||
// some adjustments made to provide the additional
|
||||
// exception-handling data, and to make the data easier to work with
|
||||
// in memory --- for example, to allow it to be placed in read-only
|
||||
// memory even when describing position-independent code.
|
||||
//
|
||||
// In particular, exception handling data can select a number of
|
||||
// different encodings for pointers that appear in the data, as
|
||||
// described by the DwarfPointerEncoding enum. There are actually
|
||||
// four axes(!) to the encoding:
|
||||
//
|
||||
// - The pointer size: pointers can be 2, 4, or 8 bytes long, or use
|
||||
// the DWARF LEB128 encoding.
|
||||
//
|
||||
// - The pointer's signedness: pointers can be signed or unsigned.
|
||||
//
|
||||
// - The pointer's base address: the data stored in the exception
|
||||
// handling data can be the actual address (that is, an absolute
|
||||
// pointer), or relative to one of a number of different base
|
||||
// addreses --- including that of the encoded pointer itself, for
|
||||
// a form of "pc-relative" addressing.
|
||||
//
|
||||
// - The pointer may be indirect: it may be the address where the
|
||||
// true pointer is stored. (This is used to refer to things via
|
||||
// global offset table entries, program linkage table entries, or
|
||||
// other tricks used in position-independent code.)
|
||||
//
|
||||
// There are also two options that fall outside that matrix
|
||||
// altogether: the pointer may be omitted, or it may have padding to
|
||||
// align it on an appropriate address boundary. (That last option
|
||||
// may seem like it should be just another axis, but it is not.)
|
||||
|
||||
// Indicate that the exception handling data is loaded starting at
|
||||
// SECTION_BASE, and that the start of its buffer in our own memory
|
||||
// is BUFFER_BASE. This allows us to find the address that a given
|
||||
// byte in our buffer would have when loaded into the program the
|
||||
// data describes. We need this to resolve DW_EH_PE_pcrel pointers.
|
||||
void SetCFIDataBase(uint64_t section_base, const uint8_t* buffer_base);
|
||||
|
||||
// Indicate that the base address of the program's ".text" section
|
||||
// is TEXT_BASE. We need this to resolve DW_EH_PE_textrel pointers.
|
||||
void SetTextBase(uint64_t text_base);
|
||||
|
||||
// Indicate that the base address for DW_EH_PE_datarel pointers is
|
||||
// DATA_BASE. The proper value depends on the ABI; it is usually the
|
||||
// address of the global offset table, held in a designated register in
|
||||
// position-independent code. You will need to look at the startup code
|
||||
// for the target system to be sure. I tried; my eyes bled.
|
||||
void SetDataBase(uint64_t data_base);
|
||||
|
||||
// Indicate that the base address for the FDE we are processing is
|
||||
// FUNCTION_BASE. This is the start address of DW_EH_PE_funcrel
|
||||
// pointers. (This encoding does not seem to be used by the GNU
|
||||
// toolchain.)
|
||||
void SetFunctionBase(uint64_t function_base);
|
||||
|
||||
// Indicate that we are no longer processing any FDE, so any use of
|
||||
// a DW_EH_PE_funcrel encoding is an error.
|
||||
void ClearFunctionBase();
|
||||
|
||||
// Return true if ENCODING is a valid pointer encoding.
|
||||
bool ValidEncoding(DwarfPointerEncoding encoding) const;
|
||||
|
||||
// Return true if we have all the information we need to read a
|
||||
// pointer that uses ENCODING. This checks that the appropriate
|
||||
// SetFooBase function for ENCODING has been called.
|
||||
bool UsableEncoding(DwarfPointerEncoding encoding) const;
|
||||
|
||||
// Read an encoded pointer from BUFFER using ENCODING; return the
|
||||
// absolute address it represents, and set *LEN to the pointer's
|
||||
// length in bytes, including any padding for aligned pointers.
|
||||
//
|
||||
// This function calls 'abort' if ENCODING is invalid or refers to a
|
||||
// base address this reader hasn't been given, so you should check
|
||||
// with ValidEncoding and UsableEncoding first if you would rather
|
||||
// die in a more helpful way.
|
||||
uint64_t ReadEncodedPointer(const uint8_t* buffer,
|
||||
DwarfPointerEncoding encoding,
|
||||
size_t* len) const;
|
||||
|
||||
Endianness GetEndianness() const;
|
||||
private:
|
||||
|
||||
// Function pointer type for our address and offset readers.
|
||||
typedef uint64_t (ByteReader::*AddressReader)(const uint8_t*) const;
|
||||
|
||||
// Read an offset from BUFFER and return it as an unsigned 64 bit
|
||||
// integer. DWARF2/3 define offsets as either 4 or 8 bytes,
|
||||
// generally depending on the amount of DWARF2/3 info present.
|
||||
// This function pointer gets set by SetOffsetSize.
|
||||
AddressReader offset_reader_;
|
||||
|
||||
// Read an address from BUFFER and return it as an unsigned 64 bit
|
||||
// integer. DWARF2/3 allow addresses to be any size from 0-255
|
||||
// bytes currently. Internally we support 4 and 8 byte addresses,
|
||||
// and will CHECK on anything else.
|
||||
// This function pointer gets set by SetAddressSize.
|
||||
AddressReader address_reader_;
|
||||
|
||||
Endianness endian_;
|
||||
uint8_t address_size_;
|
||||
uint8_t offset_size_;
|
||||
|
||||
// Base addresses for Linux C++ exception handling data's encoded pointers.
|
||||
bool have_section_base_, have_text_base_, have_data_base_;
|
||||
bool have_function_base_;
|
||||
uint64_t section_base_, text_base_, data_base_, function_base_;
|
||||
const uint8_t* buffer_base_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_DWARF_BYTEREADER_H__
|
||||
710
externals/breakpad/src/common/dwarf/bytereader_unittest.cc
vendored
Normal file
710
externals/breakpad/src/common/dwarf/bytereader_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,710 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// bytereader_unittest.cc: Unit tests for google_breakpad::ByteReader
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/dwarf/bytereader.h"
|
||||
#include "common/dwarf/bytereader-inl.h"
|
||||
#include "common/dwarf/cfi_assembler.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using google_breakpad::ByteReader;
|
||||
using google_breakpad::DwarfPointerEncoding;
|
||||
using google_breakpad::ENDIANNESS_BIG;
|
||||
using google_breakpad::ENDIANNESS_LITTLE;
|
||||
using google_breakpad::CFISection;
|
||||
using google_breakpad::test_assembler::Label;
|
||||
using google_breakpad::test_assembler::kBigEndian;
|
||||
using google_breakpad::test_assembler::kLittleEndian;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
using testing::Test;
|
||||
|
||||
struct ReaderFixture {
|
||||
string contents;
|
||||
size_t pointer_size;
|
||||
};
|
||||
|
||||
class Reader: public ReaderFixture, public Test { };
|
||||
class ReaderDeathTest: public ReaderFixture, public Test { };
|
||||
|
||||
TEST_F(Reader, SimpleConstructor) {
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetAddressSize(4);
|
||||
CFISection section(kBigEndian, 4);
|
||||
section
|
||||
.D8(0xc0)
|
||||
.D16(0xcf0d)
|
||||
.D32(0x96fdd219)
|
||||
.D64(0xbbf55fef0825f117ULL)
|
||||
.ULEB128(0xa0927048ba8121afULL)
|
||||
.LEB128(-0x4f337badf4483f83LL)
|
||||
.D32(0xfec319c9);
|
||||
ASSERT_TRUE(section.GetContents(&contents));
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(contents.data());
|
||||
EXPECT_EQ(0xc0U, reader.ReadOneByte(data));
|
||||
EXPECT_EQ(0xcf0dU, reader.ReadTwoBytes(data + 1));
|
||||
EXPECT_EQ(0x96fdd219U, reader.ReadFourBytes(data + 3));
|
||||
EXPECT_EQ(0xbbf55fef0825f117ULL, reader.ReadEightBytes(data + 7));
|
||||
size_t leb128_size;
|
||||
EXPECT_EQ(0xa0927048ba8121afULL,
|
||||
reader.ReadUnsignedLEB128(data + 15, &leb128_size));
|
||||
EXPECT_EQ(10U, leb128_size);
|
||||
EXPECT_EQ(-0x4f337badf4483f83LL,
|
||||
reader.ReadSignedLEB128(data + 25, &leb128_size));
|
||||
EXPECT_EQ(10U, leb128_size);
|
||||
EXPECT_EQ(0xfec319c9, reader.ReadAddress(data + 35));
|
||||
}
|
||||
|
||||
TEST_F(Reader, ValidEncodings) {
|
||||
ByteReader reader(ENDIANNESS_LITTLE);
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_omit)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_aligned)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_absptr |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_uleb128 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata2 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata4 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_udata8 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sleb128 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata2 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata4 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_sdata8 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_absptr |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_uleb128 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_udata2 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_udata4 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_udata8 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sleb128 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sdata2 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sdata4 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sdata8 |
|
||||
google_breakpad::DW_EH_PE_pcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_absptr |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_uleb128 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_udata2 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_udata4 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_udata8 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sleb128 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sdata2 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sdata4 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sdata8 |
|
||||
google_breakpad::DW_EH_PE_textrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_absptr |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_uleb128 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_udata2 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_udata4 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_udata8 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sleb128 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sdata2 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sdata4 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sdata8 |
|
||||
google_breakpad::DW_EH_PE_datarel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_absptr |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_uleb128 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_udata2 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_udata4 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_udata8 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sleb128 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sdata2 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sdata4 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
EXPECT_TRUE(reader.ValidEncoding(
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_indirect |
|
||||
google_breakpad::DW_EH_PE_sdata8 |
|
||||
google_breakpad::DW_EH_PE_funcrel)));
|
||||
|
||||
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x05)));
|
||||
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x07)));
|
||||
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x0d)));
|
||||
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x0f)));
|
||||
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x51)));
|
||||
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x60)));
|
||||
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0x70)));
|
||||
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0xf0)));
|
||||
EXPECT_FALSE(reader.ValidEncoding(DwarfPointerEncoding(0xd0)));
|
||||
}
|
||||
|
||||
TEST_F(ReaderDeathTest, DW_EH_PE_omit) {
|
||||
static const uint8_t data[] = { 42 };
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetAddressSize(4);
|
||||
EXPECT_DEATH(reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_omit,
|
||||
&pointer_size),
|
||||
"encoding != DW_EH_PE_omit");
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_absptr4) {
|
||||
static const uint8_t data[] = { 0x27, 0x57, 0xea, 0x40 };
|
||||
ByteReader reader(ENDIANNESS_LITTLE);
|
||||
reader.SetAddressSize(4);
|
||||
EXPECT_EQ(0x40ea5727U,
|
||||
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_absptr,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(4U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_absptr8) {
|
||||
static const uint8_t data[] = {
|
||||
0x60, 0x27, 0x57, 0xea, 0x40, 0xc2, 0x98, 0x05, 0x01, 0x50
|
||||
};
|
||||
ByteReader reader(ENDIANNESS_LITTLE);
|
||||
reader.SetAddressSize(8);
|
||||
EXPECT_EQ(0x010598c240ea5727ULL,
|
||||
reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_absptr,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(8U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_uleb128) {
|
||||
static const uint8_t data[] = { 0x81, 0x84, 0x4c };
|
||||
ByteReader reader(ENDIANNESS_LITTLE);
|
||||
reader.SetAddressSize(4);
|
||||
EXPECT_EQ(0x130201U,
|
||||
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_uleb128,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(3U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_udata2) {
|
||||
static const uint8_t data[] = { 0xf4, 0x8d };
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetAddressSize(4);
|
||||
EXPECT_EQ(0xf48dU,
|
||||
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_udata2,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(2U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_udata4) {
|
||||
static const uint8_t data[] = { 0xb2, 0x68, 0xa5, 0x62, 0x8f, 0x8b };
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetAddressSize(8);
|
||||
EXPECT_EQ(0xa5628f8b,
|
||||
reader.ReadEncodedPointer(data + 2, google_breakpad::DW_EH_PE_udata4,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(4U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_udata8Addr8) {
|
||||
static const uint8_t data[] = {
|
||||
0x27, 0x04, 0x73, 0x04, 0x69, 0x9f, 0x19, 0xed, 0x8f, 0xfe
|
||||
};
|
||||
ByteReader reader(ENDIANNESS_LITTLE);
|
||||
reader.SetAddressSize(8);
|
||||
EXPECT_EQ(0x8fed199f69047304ULL,
|
||||
reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_udata8,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(8U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_udata8Addr4) {
|
||||
static const uint8_t data[] = {
|
||||
0x27, 0x04, 0x73, 0x04, 0x69, 0x9f, 0x19, 0xed, 0x8f, 0xfe
|
||||
};
|
||||
ByteReader reader(ENDIANNESS_LITTLE);
|
||||
reader.SetAddressSize(4);
|
||||
EXPECT_EQ(0x69047304ULL,
|
||||
reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_udata8,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(8U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_sleb128) {
|
||||
static const uint8_t data[] = { 0x42, 0xff, 0xfb, 0x73 };
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetAddressSize(4);
|
||||
EXPECT_EQ(-0x030201U & 0xffffffff,
|
||||
reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_sleb128,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(3U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_sdata2) {
|
||||
static const uint8_t data[] = { 0xb9, 0xbf };
|
||||
ByteReader reader(ENDIANNESS_LITTLE);
|
||||
reader.SetAddressSize(8);
|
||||
EXPECT_EQ(0xffffffffffffbfb9ULL,
|
||||
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_sdata2,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(2U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_sdata4) {
|
||||
static const uint8_t data[] = { 0xa0, 0xca, 0xf2, 0xb8, 0xc2, 0xad };
|
||||
ByteReader reader(ENDIANNESS_LITTLE);
|
||||
reader.SetAddressSize(8);
|
||||
EXPECT_EQ(0xffffffffadc2b8f2ULL,
|
||||
reader.ReadEncodedPointer(data + 2, google_breakpad::DW_EH_PE_sdata4,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(4U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_sdata8) {
|
||||
static const uint8_t data[] = {
|
||||
0xf6, 0x66, 0x57, 0x79, 0xe0, 0x0c, 0x9b, 0x26, 0x87
|
||||
};
|
||||
ByteReader reader(ENDIANNESS_LITTLE);
|
||||
reader.SetAddressSize(8);
|
||||
EXPECT_EQ(0x87269b0ce0795766ULL,
|
||||
reader.ReadEncodedPointer(data + 1, google_breakpad::DW_EH_PE_sdata8,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(8U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_pcrel) {
|
||||
static const uint8_t data[] = {
|
||||
0x4a, 0x8b, 0x1b, 0x14, 0xc8, 0xc4, 0x02, 0xce
|
||||
};
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetAddressSize(4);
|
||||
DwarfPointerEncoding encoding =
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_pcrel
|
||||
| google_breakpad::DW_EH_PE_absptr);
|
||||
reader.SetCFIDataBase(0x89951377, data);
|
||||
EXPECT_EQ(0x89951377 + 3 + 0x14c8c402,
|
||||
reader.ReadEncodedPointer(data + 3, encoding, &pointer_size));
|
||||
EXPECT_EQ(4U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_textrel) {
|
||||
static const uint8_t data[] = {
|
||||
0xd9, 0x0d, 0x05, 0x17, 0xc9, 0x7a, 0x42, 0x1e
|
||||
};
|
||||
ByteReader reader(ENDIANNESS_LITTLE);
|
||||
reader.SetAddressSize(4);
|
||||
reader.SetTextBase(0xb91beaf0);
|
||||
DwarfPointerEncoding encoding =
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_textrel
|
||||
| google_breakpad::DW_EH_PE_sdata2);
|
||||
EXPECT_EQ((0xb91beaf0 + 0xffffc917) & 0xffffffff,
|
||||
reader.ReadEncodedPointer(data + 3, encoding, &pointer_size));
|
||||
EXPECT_EQ(2U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_datarel) {
|
||||
static const uint8_t data[] = {
|
||||
0x16, 0xf2, 0xbb, 0x82, 0x68, 0xa7, 0xbc, 0x39
|
||||
};
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetAddressSize(8);
|
||||
reader.SetDataBase(0xbef308bd25ce74f0ULL);
|
||||
DwarfPointerEncoding encoding =
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_datarel
|
||||
| google_breakpad::DW_EH_PE_sleb128);
|
||||
EXPECT_EQ(0xbef308bd25ce74f0ULL + 0xfffffffffffa013bULL,
|
||||
reader.ReadEncodedPointer(data + 2, encoding, &pointer_size));
|
||||
EXPECT_EQ(3U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Reader, DW_EH_PE_funcrel) {
|
||||
static const uint8_t data[] = {
|
||||
0x84, 0xf8, 0x14, 0x01, 0x61, 0xd1, 0x48, 0xc9
|
||||
};
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetAddressSize(4);
|
||||
reader.SetFunctionBase(0x823c3520);
|
||||
DwarfPointerEncoding encoding =
|
||||
DwarfPointerEncoding(google_breakpad::DW_EH_PE_funcrel
|
||||
| google_breakpad::DW_EH_PE_udata2);
|
||||
EXPECT_EQ(0x823c3520 + 0xd148,
|
||||
reader.ReadEncodedPointer(data + 5, encoding, &pointer_size));
|
||||
EXPECT_EQ(2U, pointer_size);
|
||||
}
|
||||
|
||||
TEST(UsableBase, CFI) {
|
||||
static const uint8_t data[] = { 0x42 };
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetCFIDataBase(0xb31cbd20, data);
|
||||
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
|
||||
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
|
||||
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
|
||||
}
|
||||
|
||||
TEST(UsableBase, Text) {
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetTextBase(0xa899ccb9);
|
||||
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
|
||||
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
|
||||
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
|
||||
}
|
||||
|
||||
TEST(UsableBase, Data) {
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetDataBase(0xf7b10bcd);
|
||||
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
|
||||
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
|
||||
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
|
||||
}
|
||||
|
||||
TEST(UsableBase, Function) {
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetFunctionBase(0xc2c0ed81);
|
||||
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
|
||||
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
|
||||
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
|
||||
}
|
||||
|
||||
TEST(UsableBase, ClearFunction) {
|
||||
ByteReader reader(ENDIANNESS_BIG);
|
||||
reader.SetFunctionBase(0xc2c0ed81);
|
||||
reader.ClearFunctionBase();
|
||||
EXPECT_TRUE(reader.UsableEncoding(google_breakpad::DW_EH_PE_absptr));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_pcrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_textrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_datarel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_funcrel));
|
||||
EXPECT_FALSE(reader.UsableEncoding(google_breakpad::DW_EH_PE_omit));
|
||||
EXPECT_FALSE(reader.UsableEncoding(DwarfPointerEncoding(0x60)));
|
||||
}
|
||||
|
||||
struct AlignedFixture {
|
||||
AlignedFixture() : reader(ENDIANNESS_BIG) { reader.SetAddressSize(4); }
|
||||
static const uint8_t data[10];
|
||||
ByteReader reader;
|
||||
size_t pointer_size;
|
||||
};
|
||||
|
||||
const uint8_t AlignedFixture::data[10] = {
|
||||
0xfe, 0x6e, 0x93, 0xd8, 0x34, 0xd5, 0x1c, 0xd3, 0xac, 0x2b
|
||||
};
|
||||
|
||||
class Aligned: public AlignedFixture, public Test { };
|
||||
|
||||
TEST_F(Aligned, DW_EH_PE_aligned0) {
|
||||
reader.SetCFIDataBase(0xb440305c, data);
|
||||
EXPECT_EQ(0xfe6e93d8U,
|
||||
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(4U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Aligned, DW_EH_PE_aligned1) {
|
||||
reader.SetCFIDataBase(0xb440305d, data);
|
||||
EXPECT_EQ(0xd834d51cU,
|
||||
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(7U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Aligned, DW_EH_PE_aligned2) {
|
||||
reader.SetCFIDataBase(0xb440305e, data);
|
||||
EXPECT_EQ(0x93d834d5U,
|
||||
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(6U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Aligned, DW_EH_PE_aligned3) {
|
||||
reader.SetCFIDataBase(0xb440305f, data);
|
||||
EXPECT_EQ(0x6e93d834U,
|
||||
reader.ReadEncodedPointer(data, google_breakpad::DW_EH_PE_aligned,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(5U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Aligned, DW_EH_PE_aligned11) {
|
||||
reader.SetCFIDataBase(0xb4403061, data);
|
||||
EXPECT_EQ(0xd834d51cU,
|
||||
reader.ReadEncodedPointer(data + 1,
|
||||
google_breakpad::DW_EH_PE_aligned,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(6U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Aligned, DW_EH_PE_aligned30) {
|
||||
reader.SetCFIDataBase(0xb4403063, data);
|
||||
EXPECT_EQ(0x6e93d834U,
|
||||
reader.ReadEncodedPointer(data + 1,
|
||||
google_breakpad::DW_EH_PE_aligned,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(4U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Aligned, DW_EH_PE_aligned23) {
|
||||
reader.SetCFIDataBase(0xb4403062, data);
|
||||
EXPECT_EQ(0x1cd3ac2bU,
|
||||
reader.ReadEncodedPointer(data + 3,
|
||||
google_breakpad::DW_EH_PE_aligned,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(7U, pointer_size);
|
||||
}
|
||||
|
||||
TEST_F(Aligned, DW_EH_PE_aligned03) {
|
||||
reader.SetCFIDataBase(0xb4403064, data);
|
||||
EXPECT_EQ(0x34d51cd3U,
|
||||
reader.ReadEncodedPointer(data + 3,
|
||||
google_breakpad::DW_EH_PE_aligned,
|
||||
&pointer_size));
|
||||
EXPECT_EQ(5U, pointer_size);
|
||||
}
|
||||
205
externals/breakpad/src/common/dwarf/cfi_assembler.cc
vendored
Normal file
205
externals/breakpad/src/common/dwarf/cfi_assembler.cc
vendored
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// cfi_assembler.cc: Implementation of google_breakpad::CFISection class.
|
||||
// See cfi_assembler.h for details.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/dwarf/cfi_assembler.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
CFISection& CFISection::CIEHeader(uint64_t code_alignment_factor,
|
||||
int data_alignment_factor,
|
||||
unsigned return_address_register,
|
||||
uint8_t version,
|
||||
const string& augmentation,
|
||||
bool dwarf64,
|
||||
uint8_t address_size,
|
||||
uint8_t segment_size) {
|
||||
assert(!entry_length_);
|
||||
entry_length_ = new PendingLength();
|
||||
in_fde_ = false;
|
||||
|
||||
if (dwarf64) {
|
||||
D32(kDwarf64InitialLengthMarker);
|
||||
D64(entry_length_->length);
|
||||
entry_length_->start = Here();
|
||||
D64(eh_frame_ ? kEHFrame64CIEIdentifier : kDwarf64CIEIdentifier);
|
||||
} else {
|
||||
D32(entry_length_->length);
|
||||
entry_length_->start = Here();
|
||||
D32(eh_frame_ ? kEHFrame32CIEIdentifier : kDwarf32CIEIdentifier);
|
||||
}
|
||||
D8(version);
|
||||
AppendCString(augmentation);
|
||||
if (version >= 4) {
|
||||
D8(address_size);
|
||||
D8(segment_size);
|
||||
}
|
||||
ULEB128(code_alignment_factor);
|
||||
LEB128(data_alignment_factor);
|
||||
if (version == 1)
|
||||
D8(return_address_register);
|
||||
else
|
||||
ULEB128(return_address_register);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CFISection& CFISection::FDEHeader(Label cie_pointer,
|
||||
uint64_t initial_location,
|
||||
uint64_t address_range,
|
||||
bool dwarf64) {
|
||||
assert(!entry_length_);
|
||||
entry_length_ = new PendingLength();
|
||||
in_fde_ = true;
|
||||
fde_start_address_ = initial_location;
|
||||
|
||||
if (dwarf64) {
|
||||
D32(0xffffffff);
|
||||
D64(entry_length_->length);
|
||||
entry_length_->start = Here();
|
||||
if (eh_frame_)
|
||||
D64(Here() - cie_pointer);
|
||||
else
|
||||
D64(cie_pointer);
|
||||
} else {
|
||||
D32(entry_length_->length);
|
||||
entry_length_->start = Here();
|
||||
if (eh_frame_)
|
||||
D32(Here() - cie_pointer);
|
||||
else
|
||||
D32(cie_pointer);
|
||||
}
|
||||
EncodedPointer(initial_location);
|
||||
// The FDE length in an .eh_frame section uses the same encoding as the
|
||||
// initial location, but ignores the base address (selected by the upper
|
||||
// nybble of the encoding), as it's a length, not an address that can be
|
||||
// made relative.
|
||||
EncodedPointer(address_range,
|
||||
DwarfPointerEncoding(pointer_encoding_ & 0x0f));
|
||||
return *this;
|
||||
}
|
||||
|
||||
CFISection& CFISection::FinishEntry() {
|
||||
assert(entry_length_);
|
||||
Align(address_size_, DW_CFA_nop);
|
||||
entry_length_->length = Here() - entry_length_->start;
|
||||
delete entry_length_;
|
||||
entry_length_ = NULL;
|
||||
in_fde_ = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CFISection& CFISection::EncodedPointer(uint64_t address,
|
||||
DwarfPointerEncoding encoding,
|
||||
const EncodedPointerBases& bases) {
|
||||
// Omitted data is extremely easy to emit.
|
||||
if (encoding == DW_EH_PE_omit)
|
||||
return *this;
|
||||
|
||||
// If (encoding & DW_EH_PE_indirect) != 0, then we assume
|
||||
// that ADDRESS is the address at which the pointer is stored --- in
|
||||
// other words, that bit has no effect on how we write the pointer.
|
||||
encoding = DwarfPointerEncoding(encoding & ~DW_EH_PE_indirect);
|
||||
|
||||
// Find the base address to which this pointer is relative. The upper
|
||||
// nybble of the encoding specifies this.
|
||||
uint64_t base;
|
||||
switch (encoding & 0xf0) {
|
||||
case DW_EH_PE_absptr: base = 0; break;
|
||||
case DW_EH_PE_pcrel: base = bases.cfi + Size(); break;
|
||||
case DW_EH_PE_textrel: base = bases.text; break;
|
||||
case DW_EH_PE_datarel: base = bases.data; break;
|
||||
case DW_EH_PE_funcrel: base = fde_start_address_; break;
|
||||
case DW_EH_PE_aligned: base = 0; break;
|
||||
default: abort();
|
||||
};
|
||||
|
||||
// Make ADDRESS relative. Yes, this is appropriate even for "absptr"
|
||||
// values; see gcc/unwind-pe.h.
|
||||
address -= base;
|
||||
|
||||
// Align the pointer, if required.
|
||||
if ((encoding & 0xf0) == DW_EH_PE_aligned)
|
||||
Align(AddressSize());
|
||||
|
||||
// Append ADDRESS to this section in the appropriate form. For the
|
||||
// fixed-width forms, we don't need to differentiate between signed and
|
||||
// unsigned encodings, because ADDRESS has already been extended to 64
|
||||
// bits before it was passed to us.
|
||||
switch (encoding & 0x0f) {
|
||||
case DW_EH_PE_absptr:
|
||||
Address(address);
|
||||
break;
|
||||
|
||||
case DW_EH_PE_uleb128:
|
||||
ULEB128(address);
|
||||
break;
|
||||
|
||||
case DW_EH_PE_sleb128:
|
||||
LEB128(address);
|
||||
break;
|
||||
|
||||
case DW_EH_PE_udata2:
|
||||
case DW_EH_PE_sdata2:
|
||||
D16(address);
|
||||
break;
|
||||
|
||||
case DW_EH_PE_udata4:
|
||||
case DW_EH_PE_sdata4:
|
||||
D32(address);
|
||||
break;
|
||||
|
||||
case DW_EH_PE_udata8:
|
||||
case DW_EH_PE_sdata8:
|
||||
D64(address);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
return *this;
|
||||
};
|
||||
|
||||
const uint32_t CFISection::kDwarf64InitialLengthMarker;
|
||||
const uint32_t CFISection::kDwarf32CIEIdentifier;
|
||||
const uint64_t CFISection::kDwarf64CIEIdentifier;
|
||||
const uint32_t CFISection::kEHFrame32CIEIdentifier;
|
||||
const uint64_t CFISection::kEHFrame64CIEIdentifier;
|
||||
|
||||
} // namespace google_breakpad
|
||||
268
externals/breakpad/src/common/dwarf/cfi_assembler.h
vendored
Normal file
268
externals/breakpad/src/common/dwarf/cfi_assembler.h
vendored
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
// -*- mode: C++ -*-
|
||||
|
||||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// cfi_assembler.h: Define CFISection, a class for creating properly
|
||||
// (and improperly) formatted DWARF CFI data for unit tests.
|
||||
|
||||
#ifndef PROCESSOR_CFI_ASSEMBLER_H_
|
||||
#define PROCESSOR_CFI_ASSEMBLER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/dwarf/dwarf2enums.h"
|
||||
#include "common/test_assembler.h"
|
||||
#include "common/using_std_string.h"
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using google_breakpad::test_assembler::Label;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
|
||||
class CFISection: public Section {
|
||||
public:
|
||||
|
||||
// CFI augmentation strings beginning with 'z', defined by the
|
||||
// Linux/IA-64 C++ ABI, can specify interesting encodings for
|
||||
// addresses appearing in FDE headers and call frame instructions (and
|
||||
// for additional fields whose presence the augmentation string
|
||||
// specifies). In particular, pointers can be specified to be relative
|
||||
// to various base address: the start of the .text section, the
|
||||
// location holding the address itself, and so on. These allow the
|
||||
// frame data to be position-independent even when they live in
|
||||
// write-protected pages. These variants are specified at the
|
||||
// following two URLs:
|
||||
//
|
||||
// http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/dwarfext.html
|
||||
// http://refspecs.linux-foundation.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
|
||||
//
|
||||
// CFISection leaves the production of well-formed 'z'-augmented CIEs and
|
||||
// FDEs to the user, but does provide EncodedPointer, to emit
|
||||
// properly-encoded addresses for a given pointer encoding.
|
||||
// EncodedPointer uses an instance of this structure to find the base
|
||||
// addresses it should use; you can establish a default for all encoded
|
||||
// pointers appended to this section with SetEncodedPointerBases.
|
||||
struct EncodedPointerBases {
|
||||
EncodedPointerBases() : cfi(), text(), data() { }
|
||||
|
||||
// The starting address of this CFI section in memory, for
|
||||
// DW_EH_PE_pcrel. DW_EH_PE_pcrel pointers may only be used in data
|
||||
// that has is loaded into the program's address space.
|
||||
uint64_t cfi;
|
||||
|
||||
// The starting address of this file's .text section, for DW_EH_PE_textrel.
|
||||
uint64_t text;
|
||||
|
||||
// The starting address of this file's .got or .eh_frame_hdr section,
|
||||
// for DW_EH_PE_datarel.
|
||||
uint64_t data;
|
||||
};
|
||||
|
||||
// Create a CFISection whose endianness is ENDIANNESS, and where
|
||||
// machine addresses are ADDRESS_SIZE bytes long. If EH_FRAME is
|
||||
// true, use the .eh_frame format, as described by the Linux
|
||||
// Standards Base Core Specification, instead of the DWARF CFI
|
||||
// format.
|
||||
CFISection(google_breakpad::test_assembler::Endianness endianness, size_t address_size,
|
||||
bool eh_frame = false)
|
||||
: Section(endianness), address_size_(address_size), eh_frame_(eh_frame),
|
||||
pointer_encoding_(DW_EH_PE_absptr),
|
||||
encoded_pointer_bases_(), entry_length_(NULL), in_fde_(false) {
|
||||
// The 'start', 'Here', and 'Mark' members of a CFISection all refer
|
||||
// to section offsets.
|
||||
start() = 0;
|
||||
}
|
||||
|
||||
// Return this CFISection's address size.
|
||||
size_t AddressSize() const { return address_size_; }
|
||||
|
||||
// Return true if this CFISection uses the .eh_frame format, or
|
||||
// false if it contains ordinary DWARF CFI data.
|
||||
bool ContainsEHFrame() const { return eh_frame_; }
|
||||
|
||||
// Use ENCODING for pointers in calls to FDEHeader and EncodedPointer.
|
||||
void SetPointerEncoding(DwarfPointerEncoding encoding) {
|
||||
pointer_encoding_ = encoding;
|
||||
}
|
||||
|
||||
// Use the addresses in BASES as the base addresses for encoded
|
||||
// pointers in subsequent calls to FDEHeader or EncodedPointer.
|
||||
// This function makes a copy of BASES.
|
||||
void SetEncodedPointerBases(const EncodedPointerBases& bases) {
|
||||
encoded_pointer_bases_ = bases;
|
||||
}
|
||||
|
||||
// Append a Common Information Entry header to this section with the
|
||||
// given values. If dwarf64 is true, use the 64-bit DWARF initial
|
||||
// length format for the CIE's initial length. Return a reference to
|
||||
// this section. You should call FinishEntry after writing the last
|
||||
// instruction for the CIE.
|
||||
//
|
||||
// Before calling this function, you will typically want to use Mark
|
||||
// or Here to make a label to pass to FDEHeader that refers to this
|
||||
// CIE's position in the section.
|
||||
CFISection& CIEHeader(uint64_t code_alignment_factor,
|
||||
int data_alignment_factor,
|
||||
unsigned return_address_register,
|
||||
uint8_t version = 3,
|
||||
const string& augmentation = "",
|
||||
bool dwarf64 = false,
|
||||
uint8_t address_size = 8,
|
||||
uint8_t segment_size = 0);
|
||||
|
||||
// Append a Frame Description Entry header to this section with the
|
||||
// given values. If dwarf64 is true, use the 64-bit DWARF initial
|
||||
// length format for the CIE's initial length. Return a reference to
|
||||
// this section. You should call FinishEntry after writing the last
|
||||
// instruction for the CIE.
|
||||
//
|
||||
// This function doesn't support entries that are longer than
|
||||
// 0xffffff00 bytes. (The "initial length" is always a 32-bit
|
||||
// value.) Nor does it support .debug_frame sections longer than
|
||||
// 0xffffff00 bytes.
|
||||
CFISection& FDEHeader(Label cie_pointer,
|
||||
uint64_t initial_location,
|
||||
uint64_t address_range,
|
||||
bool dwarf64 = false);
|
||||
|
||||
// Note the current position as the end of the last CIE or FDE we
|
||||
// started, after padding with DW_CFA_nops for alignment. This
|
||||
// defines the label representing the entry's length, cited in the
|
||||
// entry's header. Return a reference to this section.
|
||||
CFISection& FinishEntry();
|
||||
|
||||
// Append the contents of BLOCK as a DW_FORM_block value: an
|
||||
// unsigned LEB128 length, followed by that many bytes of data.
|
||||
CFISection& Block(const string& block) {
|
||||
ULEB128(block.size());
|
||||
Append(block);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Append ADDRESS to this section, in the appropriate size and
|
||||
// endianness. Return a reference to this section.
|
||||
CFISection& Address(uint64_t address) {
|
||||
Section::Append(endianness(), address_size_, address);
|
||||
return *this;
|
||||
}
|
||||
CFISection& Address(Label address) {
|
||||
Section::Append(endianness(), address_size_, address);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Append ADDRESS to this section, using ENCODING and BASES. ENCODING
|
||||
// defaults to this section's default encoding, established by
|
||||
// SetPointerEncoding. BASES defaults to this section's bases, set by
|
||||
// SetEncodedPointerBases. If the DW_EH_PE_indirect bit is set in the
|
||||
// encoding, assume that ADDRESS is where the true address is stored.
|
||||
// Return a reference to this section.
|
||||
//
|
||||
// (C++ doesn't let me use default arguments here, because I want to
|
||||
// refer to members of *this in the default argument expression.)
|
||||
CFISection& EncodedPointer(uint64_t address) {
|
||||
return EncodedPointer(address, pointer_encoding_, encoded_pointer_bases_);
|
||||
}
|
||||
CFISection& EncodedPointer(uint64_t address, DwarfPointerEncoding encoding) {
|
||||
return EncodedPointer(address, encoding, encoded_pointer_bases_);
|
||||
}
|
||||
CFISection& EncodedPointer(uint64_t address, DwarfPointerEncoding encoding,
|
||||
const EncodedPointerBases& bases);
|
||||
|
||||
// Restate some member functions, to keep chaining working nicely.
|
||||
CFISection& Mark(Label* label) { Section::Mark(label); return *this; }
|
||||
CFISection& D8(uint8_t v) { Section::D8(v); return *this; }
|
||||
CFISection& D16(uint16_t v) { Section::D16(v); return *this; }
|
||||
CFISection& D16(Label v) { Section::D16(v); return *this; }
|
||||
CFISection& D32(uint32_t v) { Section::D32(v); return *this; }
|
||||
CFISection& D32(const Label& v) { Section::D32(v); return *this; }
|
||||
CFISection& D64(uint64_t v) { Section::D64(v); return *this; }
|
||||
CFISection& D64(const Label& v) { Section::D64(v); return *this; }
|
||||
CFISection& LEB128(long long v) { Section::LEB128(v); return *this; }
|
||||
CFISection& ULEB128(uint64_t v) { Section::ULEB128(v); return *this; }
|
||||
|
||||
private:
|
||||
// A length value that we've appended to the section, but is not yet
|
||||
// known. LENGTH is the appended value; START is a label referring
|
||||
// to the start of the data whose length was cited.
|
||||
struct PendingLength {
|
||||
Label length;
|
||||
Label start;
|
||||
};
|
||||
|
||||
// Constants used in CFI/.eh_frame data:
|
||||
|
||||
// If the first four bytes of an "initial length" are this constant, then
|
||||
// the data uses the 64-bit DWARF format, and the length itself is the
|
||||
// subsequent eight bytes.
|
||||
static const uint32_t kDwarf64InitialLengthMarker = 0xffffffffU;
|
||||
|
||||
// The CIE identifier for 32- and 64-bit DWARF CFI and .eh_frame data.
|
||||
static const uint32_t kDwarf32CIEIdentifier = ~(uint32_t)0;
|
||||
static const uint64_t kDwarf64CIEIdentifier = ~(uint64_t)0;
|
||||
static const uint32_t kEHFrame32CIEIdentifier = 0;
|
||||
static const uint64_t kEHFrame64CIEIdentifier = 0;
|
||||
|
||||
// The size of a machine address for the data in this section.
|
||||
size_t address_size_;
|
||||
|
||||
// If true, we are generating a Linux .eh_frame section, instead of
|
||||
// a standard DWARF .debug_frame section.
|
||||
bool eh_frame_;
|
||||
|
||||
// The encoding to use for FDE pointers.
|
||||
DwarfPointerEncoding pointer_encoding_;
|
||||
|
||||
// The base addresses to use when emitting encoded pointers.
|
||||
EncodedPointerBases encoded_pointer_bases_;
|
||||
|
||||
// The length value for the current entry.
|
||||
//
|
||||
// Oddly, this must be dynamically allocated. Labels never get new
|
||||
// values; they only acquire constraints on the value they already
|
||||
// have, or assert if you assign them something incompatible. So
|
||||
// each header needs truly fresh Label objects to cite in their
|
||||
// headers and track their positions. The alternative is explicit
|
||||
// destructor invocation and a placement new. Ick.
|
||||
PendingLength *entry_length_;
|
||||
|
||||
// True if we are currently emitting an FDE --- that is, we have
|
||||
// called FDEHeader but have not yet called FinishEntry.
|
||||
bool in_fde_;
|
||||
|
||||
// If in_fde_ is true, this is its starting address. We use this for
|
||||
// emitting DW_EH_PE_funcrel pointers.
|
||||
uint64_t fde_start_address_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // PROCESSOR_CFI_ASSEMBLER_H_
|
||||
203
externals/breakpad/src/common/dwarf/dwarf2diehandler.cc
vendored
Normal file
203
externals/breakpad/src/common/dwarf/dwarf2diehandler.cc
vendored
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dwarf2diehandler.cc: Implement the dwarf2reader::DieDispatcher class.
|
||||
// See dwarf2diehandler.h for details.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/dwarf/dwarf2diehandler.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
DIEDispatcher::~DIEDispatcher() {
|
||||
while (!die_handlers_.empty()) {
|
||||
HandlerStack& entry = die_handlers_.top();
|
||||
if (entry.handler_ != root_handler_)
|
||||
delete entry.handler_;
|
||||
die_handlers_.pop();
|
||||
}
|
||||
}
|
||||
|
||||
bool DIEDispatcher::StartCompilationUnit(uint64_t offset, uint8_t address_size,
|
||||
uint8_t offset_size, uint64_t cu_length,
|
||||
uint8_t dwarf_version) {
|
||||
return root_handler_->StartCompilationUnit(offset, address_size,
|
||||
offset_size, cu_length,
|
||||
dwarf_version);
|
||||
}
|
||||
|
||||
bool DIEDispatcher::StartDIE(uint64_t offset, enum DwarfTag tag) {
|
||||
// The stack entry for the parent of this DIE, if there is one.
|
||||
HandlerStack* parent = die_handlers_.empty() ? NULL : &die_handlers_.top();
|
||||
|
||||
// Does this call indicate that we're done receiving the parent's
|
||||
// attributes' values? If so, call its EndAttributes member function.
|
||||
if (parent && parent->handler_ && !parent->reported_attributes_end_) {
|
||||
parent->reported_attributes_end_ = true;
|
||||
if (!parent->handler_->EndAttributes()) {
|
||||
// Finish off this handler now. and edit *PARENT to indicate that
|
||||
// we don't want to visit any of the children.
|
||||
parent->handler_->Finish();
|
||||
if (parent->handler_ != root_handler_)
|
||||
delete parent->handler_;
|
||||
parent->handler_ = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Find a handler for this DIE.
|
||||
DIEHandler* handler;
|
||||
if (parent) {
|
||||
if (parent->handler_)
|
||||
// Ask the parent to find a handler.
|
||||
handler = parent->handler_->FindChildHandler(offset, tag);
|
||||
else
|
||||
// No parent handler means we're not interested in any of our
|
||||
// children.
|
||||
handler = NULL;
|
||||
} else {
|
||||
// This is the root DIE. For a non-root DIE, the parent's handler
|
||||
// decides whether to visit it, but the root DIE has no parent
|
||||
// handler, so we have a special method on the root DIE handler
|
||||
// itself to decide.
|
||||
if (root_handler_->StartRootDIE(offset, tag))
|
||||
handler = root_handler_;
|
||||
else
|
||||
handler = NULL;
|
||||
}
|
||||
|
||||
// Push a handler stack entry for this new handler. As an
|
||||
// optimization, we don't push NULL-handler entries on top of other
|
||||
// NULL-handler entries; we just let the oldest such entry stand for
|
||||
// the whole subtree.
|
||||
if (handler || !parent || parent->handler_) {
|
||||
HandlerStack entry;
|
||||
entry.offset_ = offset;
|
||||
entry.handler_ = handler;
|
||||
entry.reported_attributes_end_ = false;
|
||||
die_handlers_.push(entry);
|
||||
}
|
||||
|
||||
return handler != NULL;
|
||||
}
|
||||
|
||||
void DIEDispatcher::EndDIE(uint64_t offset) {
|
||||
assert(!die_handlers_.empty());
|
||||
HandlerStack* entry = &die_handlers_.top();
|
||||
if (entry->handler_) {
|
||||
// This entry had better be the handler for this DIE.
|
||||
assert(entry->offset_ == offset);
|
||||
// If a DIE has no children, this EndDIE call indicates that we're
|
||||
// done receiving its attributes' values.
|
||||
if (!entry->reported_attributes_end_)
|
||||
entry->handler_->EndAttributes(); // Ignore return value: no children.
|
||||
entry->handler_->Finish();
|
||||
if (entry->handler_ != root_handler_)
|
||||
delete entry->handler_;
|
||||
} else {
|
||||
// If this DIE is within a tree we're ignoring, then don't pop the
|
||||
// handler stack: that entry stands for the whole tree.
|
||||
if (entry->offset_ != offset)
|
||||
return;
|
||||
}
|
||||
die_handlers_.pop();
|
||||
}
|
||||
|
||||
void DIEDispatcher::ProcessAttributeUnsigned(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data) {
|
||||
HandlerStack& current = die_handlers_.top();
|
||||
// This had better be an attribute of the DIE we were meant to handle.
|
||||
assert(offset == current.offset_);
|
||||
current.handler_->ProcessAttributeUnsigned(attr, form, data);
|
||||
}
|
||||
|
||||
void DIEDispatcher::ProcessAttributeSigned(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
int64_t data) {
|
||||
HandlerStack& current = die_handlers_.top();
|
||||
// This had better be an attribute of the DIE we were meant to handle.
|
||||
assert(offset == current.offset_);
|
||||
current.handler_->ProcessAttributeSigned(attr, form, data);
|
||||
}
|
||||
|
||||
void DIEDispatcher::ProcessAttributeReference(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data) {
|
||||
HandlerStack& current = die_handlers_.top();
|
||||
// This had better be an attribute of the DIE we were meant to handle.
|
||||
assert(offset == current.offset_);
|
||||
current.handler_->ProcessAttributeReference(attr, form, data);
|
||||
}
|
||||
|
||||
void DIEDispatcher::ProcessAttributeBuffer(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const uint8_t* data,
|
||||
uint64_t len) {
|
||||
HandlerStack& current = die_handlers_.top();
|
||||
// This had better be an attribute of the DIE we were meant to handle.
|
||||
assert(offset == current.offset_);
|
||||
current.handler_->ProcessAttributeBuffer(attr, form, data, len);
|
||||
}
|
||||
|
||||
void DIEDispatcher::ProcessAttributeString(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string& data) {
|
||||
HandlerStack& current = die_handlers_.top();
|
||||
// This had better be an attribute of the DIE we were meant to handle.
|
||||
assert(offset == current.offset_);
|
||||
current.handler_->ProcessAttributeString(attr, form, data);
|
||||
}
|
||||
|
||||
void DIEDispatcher::ProcessAttributeSignature(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t signature) {
|
||||
HandlerStack& current = die_handlers_.top();
|
||||
// This had better be an attribute of the DIE we were meant to handle.
|
||||
assert(offset == current.offset_);
|
||||
current.handler_->ProcessAttributeSignature(attr, form, signature);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
368
externals/breakpad/src/common/dwarf/dwarf2diehandler.h
vendored
Normal file
368
externals/breakpad/src/common/dwarf/dwarf2diehandler.h
vendored
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dwarf2reader::CompilationUnit is a simple and direct parser for
|
||||
// DWARF data, but its handler interface is not convenient to use. In
|
||||
// particular:
|
||||
//
|
||||
// - CompilationUnit calls Dwarf2Handler's member functions to report
|
||||
// every attribute's value, regardless of what sort of DIE it is.
|
||||
// As a result, the ProcessAttributeX functions end up looking like
|
||||
// this:
|
||||
//
|
||||
// switch (parent_die_tag) {
|
||||
// case DW_TAG_x:
|
||||
// switch (attribute_name) {
|
||||
// case DW_AT_y:
|
||||
// handle attribute y of DIE type x
|
||||
// ...
|
||||
// } break;
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// In C++ it's much nicer to use virtual function dispatch to find
|
||||
// the right code for a given case than to switch on the DIE tag
|
||||
// like this.
|
||||
//
|
||||
// - Processing different kinds of DIEs requires different sets of
|
||||
// data: lexical block DIEs have start and end addresses, but struct
|
||||
// type DIEs don't. It would be nice to be able to have separate
|
||||
// handler classes for separate kinds of DIEs, each with the members
|
||||
// appropriate to its role, instead of having one handler class that
|
||||
// needs to hold data for every DIE type.
|
||||
//
|
||||
// - There should be a separate instance of the appropriate handler
|
||||
// class for each DIE, instead of a single object with tables
|
||||
// tracking all the dies in the compilation unit.
|
||||
//
|
||||
// - It's not convenient to take some action after all a DIE's
|
||||
// attributes have been seen, but before visiting any of its
|
||||
// children. The only indication you have that a DIE's attribute
|
||||
// list is complete is that you get either a StartDIE or an EndDIE
|
||||
// call.
|
||||
//
|
||||
// - It's not convenient to make use of the tree structure of the
|
||||
// DIEs. Skipping all the children of a given die requires
|
||||
// maintaining state and returning false from StartDIE until we get
|
||||
// an EndDIE call with the appropriate offset.
|
||||
//
|
||||
// This interface tries to take care of all that. (You're shocked, I'm sure.)
|
||||
//
|
||||
// Using the classes here, you provide an initial handler for the root
|
||||
// DIE of the compilation unit. Each handler receives its DIE's
|
||||
// attributes, and provides fresh handler objects for children of
|
||||
// interest, if any. The three classes are:
|
||||
//
|
||||
// - DIEHandler: the base class for your DIE-type-specific handler
|
||||
// classes.
|
||||
//
|
||||
// - RootDIEHandler: derived from DIEHandler, the base class for your
|
||||
// root DIE handler class.
|
||||
//
|
||||
// - DIEDispatcher: derived from Dwarf2Handler, an instance of this
|
||||
// invokes your DIE-type-specific handler objects.
|
||||
//
|
||||
// In detail:
|
||||
//
|
||||
// - Define handler classes specialized for the DIE types you're
|
||||
// interested in. These handler classes must inherit from
|
||||
// DIEHandler. Thus:
|
||||
//
|
||||
// class My_DW_TAG_X_Handler: public DIEHandler { ... };
|
||||
// class My_DW_TAG_Y_Handler: public DIEHandler { ... };
|
||||
//
|
||||
// DIEHandler subclasses needn't correspond exactly to single DIE
|
||||
// types, as shown here; the point is that you can have several
|
||||
// different classes appropriate to different kinds of DIEs.
|
||||
//
|
||||
// - In particular, define a handler class for the compilation
|
||||
// unit's root DIE, that inherits from RootDIEHandler:
|
||||
//
|
||||
// class My_DW_TAG_compile_unit_Handler: public RootDIEHandler { ... };
|
||||
//
|
||||
// RootDIEHandler inherits from DIEHandler, adding a few additional
|
||||
// member functions for examining the compilation unit as a whole,
|
||||
// and other quirks of rootness.
|
||||
//
|
||||
// - Then, create a DIEDispatcher instance, passing it an instance of
|
||||
// your root DIE handler class, and use that DIEDispatcher as the
|
||||
// dwarf2reader::CompilationUnit's handler:
|
||||
//
|
||||
// My_DW_TAG_compile_unit_Handler root_die_handler(...);
|
||||
// DIEDispatcher die_dispatcher(&root_die_handler);
|
||||
// CompilationUnit reader(sections, offset, bytereader, &die_dispatcher);
|
||||
//
|
||||
// Here, 'die_dispatcher' acts as a shim between 'reader' and the
|
||||
// various DIE-specific handlers you have defined.
|
||||
//
|
||||
// - When you call reader.Start(), die_dispatcher behaves as follows,
|
||||
// starting with your root die handler and the compilation unit's
|
||||
// root DIE:
|
||||
//
|
||||
// - It calls the handler's ProcessAttributeX member functions for
|
||||
// each of the DIE's attributes.
|
||||
//
|
||||
// - It calls the handler's EndAttributes member function. This
|
||||
// should return true if any of the DIE's children should be
|
||||
// visited, in which case:
|
||||
//
|
||||
// - For each of the DIE's children, die_dispatcher calls the
|
||||
// DIE's handler's FindChildHandler member function. If that
|
||||
// returns a pointer to a DIEHandler instance, then
|
||||
// die_dispatcher uses that handler to process the child, using
|
||||
// this procedure recursively. Alternatively, if
|
||||
// FindChildHandler returns NULL, die_dispatcher ignores that
|
||||
// child and its descendants.
|
||||
//
|
||||
// - When die_dispatcher has finished processing all the DIE's
|
||||
// children, it invokes the handler's Finish() member function,
|
||||
// and destroys the handler. (As a special case, it doesn't
|
||||
// destroy the root DIE handler.)
|
||||
//
|
||||
// This allows the code for handling a particular kind of DIE to be
|
||||
// gathered together in a single class, makes it easy to skip all the
|
||||
// children or individual children of a particular DIE, and provides
|
||||
// appropriate parental context for each die.
|
||||
|
||||
#ifndef COMMON_DWARF_DWARF2DIEHANDLER_H__
|
||||
#define COMMON_DWARF_DWARF2DIEHANDLER_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <stack>
|
||||
#include <string>
|
||||
|
||||
#include "common/dwarf/types.h"
|
||||
#include "common/dwarf/dwarf2enums.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A base class for handlers for specific DIE types. The series of
|
||||
// calls made on a DIE handler is as follows:
|
||||
//
|
||||
// - for each attribute of the DIE:
|
||||
// - ProcessAttributeX()
|
||||
// - EndAttributes()
|
||||
// - if that returned true, then for each child:
|
||||
// - FindChildHandler()
|
||||
// - if that returns a non-NULL pointer to a new handler:
|
||||
// - recurse, with the new handler and the child die
|
||||
// - Finish()
|
||||
// - destruction
|
||||
class DIEHandler {
|
||||
public:
|
||||
DIEHandler() { }
|
||||
virtual ~DIEHandler() { }
|
||||
|
||||
// When we visit a DIE, we first use these member functions to
|
||||
// report the DIE's attributes and their values. These have the
|
||||
// same restrictions as the corresponding member functions of
|
||||
// dwarf2reader::Dwarf2Handler.
|
||||
//
|
||||
// Since DWARF does not specify in what order attributes must
|
||||
// appear, avoid making decisions in these functions that would be
|
||||
// affected by the presence of other attributes. The EndAttributes
|
||||
// function is a more appropriate place for such work, as all the
|
||||
// DIE's attributes have been seen at that point.
|
||||
//
|
||||
// The default definitions ignore the values they are passed.
|
||||
virtual void ProcessAttributeUnsigned(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data) { }
|
||||
virtual void ProcessAttributeSigned(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
int64_t data) { }
|
||||
virtual void ProcessAttributeReference(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data) { }
|
||||
virtual void ProcessAttributeBuffer(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const uint8_t* data,
|
||||
uint64_t len) { }
|
||||
virtual void ProcessAttributeString(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string& data) { }
|
||||
virtual void ProcessAttributeSignature(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t signture) { }
|
||||
|
||||
// Once we have reported all the DIE's attributes' values, we call
|
||||
// this member function. If it returns false, we skip all the DIE's
|
||||
// children. If it returns true, we call FindChildHandler on each
|
||||
// child. If that returns a handler object, we use that to visit
|
||||
// the child; otherwise, we skip the child.
|
||||
//
|
||||
// This is a good place to make decisions that depend on more than
|
||||
// one attribute. DWARF does not specify in what order attributes
|
||||
// must appear, so only when the EndAttributes function is called
|
||||
// does the handler have a complete picture of the DIE's attributes.
|
||||
//
|
||||
// The default definition elects to ignore the DIE's children.
|
||||
// You'll need to override this if you override FindChildHandler,
|
||||
// but at least the default behavior isn't to pass the children to
|
||||
// FindChildHandler, which then ignores them all.
|
||||
virtual bool EndAttributes() { return false; }
|
||||
|
||||
// If EndAttributes returns true to indicate that some of the DIE's
|
||||
// children might be of interest, then we apply this function to
|
||||
// each of the DIE's children. If it returns a handler object, then
|
||||
// we use that to visit the child DIE. If it returns NULL, we skip
|
||||
// that child DIE (and all its descendants).
|
||||
//
|
||||
// OFFSET is the offset of the child; TAG indicates what kind of DIE
|
||||
// it is.
|
||||
//
|
||||
// The default definition skips all children.
|
||||
virtual DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// When we are done processing a DIE, we call this member function.
|
||||
// This happens after the EndAttributes call, all FindChildHandler
|
||||
// calls (if any), and all operations on the children themselves (if
|
||||
// any). We call Finish on every handler --- even if EndAttributes
|
||||
// returns false.
|
||||
virtual void Finish() { };
|
||||
};
|
||||
|
||||
// A subclass of DIEHandler, with additional kludges for handling the
|
||||
// compilation unit's root die.
|
||||
class RootDIEHandler : public DIEHandler {
|
||||
public:
|
||||
bool handle_inline;
|
||||
|
||||
explicit RootDIEHandler(bool handle_inline = false)
|
||||
: handle_inline(handle_inline) {}
|
||||
virtual ~RootDIEHandler() {}
|
||||
|
||||
// We pass the values reported via Dwarf2Handler::StartCompilationUnit
|
||||
// to this member function, and skip the entire compilation unit if it
|
||||
// returns false. So the root DIE handler is actually also
|
||||
// responsible for handling the compilation unit metadata.
|
||||
// The default definition always visits the compilation unit.
|
||||
virtual bool StartCompilationUnit(uint64_t offset, uint8_t address_size,
|
||||
uint8_t offset_size, uint64_t cu_length,
|
||||
uint8_t dwarf_version) { return true; }
|
||||
|
||||
// For the root DIE handler only, we pass the offset, tag and
|
||||
// attributes of the compilation unit's root DIE. This is the only
|
||||
// way the root DIE handler can find the root DIE's tag. If this
|
||||
// function returns true, we will visit the root DIE using the usual
|
||||
// DIEHandler methods; otherwise, we skip the entire compilation
|
||||
// unit.
|
||||
//
|
||||
// The default definition elects to visit the root DIE.
|
||||
virtual bool StartRootDIE(uint64_t offset, enum DwarfTag tag) { return true; }
|
||||
};
|
||||
|
||||
class DIEDispatcher: public Dwarf2Handler {
|
||||
public:
|
||||
// Create a Dwarf2Handler which uses ROOT_HANDLER as the handler for
|
||||
// the compilation unit's root die, as described for the DIEHandler
|
||||
// class.
|
||||
DIEDispatcher(RootDIEHandler* root_handler) : root_handler_(root_handler) { }
|
||||
// Destroying a DIEDispatcher destroys all active handler objects
|
||||
// except the root handler.
|
||||
~DIEDispatcher();
|
||||
bool StartCompilationUnit(uint64_t offset, uint8_t address_size,
|
||||
uint8_t offset_size, uint64_t cu_length,
|
||||
uint8_t dwarf_version);
|
||||
bool StartDIE(uint64_t offset, enum DwarfTag tag);
|
||||
void ProcessAttributeUnsigned(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data);
|
||||
void ProcessAttributeSigned(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
int64_t data);
|
||||
void ProcessAttributeReference(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data);
|
||||
void ProcessAttributeBuffer(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const uint8_t* data,
|
||||
uint64_t len);
|
||||
void ProcessAttributeString(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string& data);
|
||||
void ProcessAttributeSignature(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t signature);
|
||||
void EndDIE(uint64_t offset);
|
||||
|
||||
private:
|
||||
|
||||
// The type of a handler stack entry. This includes some fields
|
||||
// which don't really need to be on the stack --- they could just be
|
||||
// single data members of DIEDispatcher --- but putting them here
|
||||
// makes it easier to see that the code is correct.
|
||||
struct HandlerStack {
|
||||
// The offset of the DIE for this handler stack entry.
|
||||
uint64_t offset_;
|
||||
|
||||
// The handler object interested in this DIE's attributes and
|
||||
// children. If NULL, we're not interested in either.
|
||||
DIEHandler* handler_;
|
||||
|
||||
// Have we reported the end of this DIE's attributes to the handler?
|
||||
bool reported_attributes_end_;
|
||||
};
|
||||
|
||||
// Stack of DIE attribute handlers. At StartDIE(D), the top of the
|
||||
// stack is the handler of D's parent, whom we may ask for a handler
|
||||
// for D itself. At EndDIE(D), the top of the stack is D's handler.
|
||||
// Special cases:
|
||||
//
|
||||
// - Before we've seen the compilation unit's root DIE, the stack is
|
||||
// empty; we'll call root_handler_'s special member functions, and
|
||||
// perhaps push root_handler_ on the stack to look at the root's
|
||||
// immediate children.
|
||||
//
|
||||
// - When we decide to ignore a subtree, we only push an entry on
|
||||
// the stack for the root of the tree being ignored, rather than
|
||||
// pushing lots of stack entries with handler_ set to NULL.
|
||||
std::stack<HandlerStack> die_handlers_;
|
||||
|
||||
// The root handler. We don't push it on die_handlers_ until we
|
||||
// actually get the StartDIE call for the root.
|
||||
RootDIEHandler* root_handler_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
#endif // COMMON_DWARF_DWARF2DIEHANDLER_H__
|
||||
532
externals/breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc
vendored
Normal file
532
externals/breakpad/src/common/dwarf/dwarf2diehandler_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,532 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dwarf2diehander_unittest.cc: Unit tests for google_breakpad::DIEDispatcher.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
|
||||
#include "common/dwarf/dwarf2diehandler.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using std::make_pair;
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::ContainerEq;
|
||||
using ::testing::ElementsAreArray;
|
||||
using ::testing::Eq;
|
||||
using ::testing::InSequence;
|
||||
using ::testing::Return;
|
||||
using ::testing::Sequence;
|
||||
using ::testing::StrEq;
|
||||
|
||||
using google_breakpad::DIEDispatcher;
|
||||
using google_breakpad::DIEHandler;
|
||||
using google_breakpad::DwarfAttribute;
|
||||
using google_breakpad::DwarfForm;
|
||||
using google_breakpad::DwarfTag;
|
||||
using google_breakpad::RootDIEHandler;
|
||||
|
||||
class MockDIEHandler: public DIEHandler {
|
||||
public:
|
||||
MOCK_METHOD3(ProcessAttributeUnsigned,
|
||||
void(DwarfAttribute, DwarfForm, uint64_t));
|
||||
MOCK_METHOD3(ProcessAttributeSigned,
|
||||
void(DwarfAttribute, DwarfForm, int64_t));
|
||||
MOCK_METHOD3(ProcessAttributeReference,
|
||||
void(DwarfAttribute, DwarfForm, uint64_t));
|
||||
MOCK_METHOD4(ProcessAttributeBuffer,
|
||||
void(DwarfAttribute, DwarfForm, const uint8_t*, uint64_t));
|
||||
MOCK_METHOD3(ProcessAttributeString,
|
||||
void(DwarfAttribute, DwarfForm, const string&));
|
||||
MOCK_METHOD3(ProcessAttributeSignature,
|
||||
void(DwarfAttribute, DwarfForm, uint64_t));
|
||||
MOCK_METHOD0(EndAttributes, bool());
|
||||
MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64_t, DwarfTag));
|
||||
MOCK_METHOD0(Finish, void());
|
||||
};
|
||||
|
||||
class MockRootDIEHandler: public RootDIEHandler {
|
||||
public:
|
||||
MOCK_METHOD3(ProcessAttributeUnsigned,
|
||||
void(DwarfAttribute, DwarfForm, uint64_t));
|
||||
MOCK_METHOD3(ProcessAttributeSigned,
|
||||
void(DwarfAttribute, DwarfForm, int64_t));
|
||||
MOCK_METHOD3(ProcessAttributeReference,
|
||||
void(DwarfAttribute, DwarfForm, uint64_t));
|
||||
MOCK_METHOD4(ProcessAttributeBuffer,
|
||||
void(DwarfAttribute, DwarfForm, const uint8_t*, uint64_t));
|
||||
MOCK_METHOD3(ProcessAttributeString,
|
||||
void(DwarfAttribute, DwarfForm, const string&));
|
||||
MOCK_METHOD3(ProcessAttributeSignature,
|
||||
void(DwarfAttribute, DwarfForm, uint64_t));
|
||||
MOCK_METHOD0(EndAttributes, bool());
|
||||
MOCK_METHOD2(FindChildHandler, DIEHandler *(uint64_t, DwarfTag));
|
||||
MOCK_METHOD0(Finish, void());
|
||||
MOCK_METHOD5(StartCompilationUnit, bool(uint64_t, uint8_t, uint8_t, uint64_t,
|
||||
uint8_t));
|
||||
MOCK_METHOD2(StartRootDIE, bool(uint64_t, DwarfTag));
|
||||
};
|
||||
|
||||
// If the handler elects to skip the compilation unit, the dispatcher
|
||||
// should tell the reader so.
|
||||
TEST(Dwarf2DIEHandler, SkipCompilationUnit) {
|
||||
Sequence s;
|
||||
MockRootDIEHandler mock_root_handler;
|
||||
DIEDispatcher die_dispatcher(&mock_root_handler);
|
||||
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartCompilationUnit(0x8d42aed77cfccf3eLL,
|
||||
0x89, 0xdc,
|
||||
0x2ecb4dc778a80f21LL,
|
||||
0x66))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return(false));
|
||||
|
||||
EXPECT_FALSE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL,
|
||||
0x89, 0xdc,
|
||||
0x2ecb4dc778a80f21LL,
|
||||
0x66));
|
||||
}
|
||||
|
||||
// If the handler elects to skip the root DIE, the dispatcher should
|
||||
// tell the reader so.
|
||||
TEST(Dwarf2DIEHandler, SkipRootDIE) {
|
||||
Sequence s;
|
||||
MockRootDIEHandler mock_root_handler;
|
||||
DIEDispatcher die_dispatcher(&mock_root_handler);
|
||||
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartCompilationUnit(0xde8994029fc8b999LL, 0xf4, 0x02,
|
||||
0xb00febffa76e2b2bLL, 0x5c))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return(false));
|
||||
|
||||
EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0xde8994029fc8b999LL,
|
||||
0xf4, 0x02,
|
||||
0xb00febffa76e2b2bLL, 0x5c));
|
||||
EXPECT_FALSE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL,
|
||||
(DwarfTag) 0xb4f98da6));
|
||||
die_dispatcher.EndDIE(0x7d08242b4b510cf2LL);
|
||||
}
|
||||
|
||||
// If the handler elects to skip the root DIE's children, the
|
||||
// dispatcher should tell the reader so --- and avoid deleting the
|
||||
// root handler.
|
||||
TEST(Dwarf2DIEHandler, SkipRootDIEChildren) {
|
||||
MockRootDIEHandler mock_root_handler;
|
||||
DIEDispatcher die_dispatcher(&mock_root_handler);
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartCompilationUnit(0x15d6897480cc65a7LL, 0x26, 0xa0,
|
||||
0x09f8bf0767f91675LL, 0xdb))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartRootDIE(0x7d08242b4b510cf2LL, (DwarfTag) 0xb4f98da6))
|
||||
.WillOnce(Return(true));
|
||||
// Please don't tell me about my children.
|
||||
EXPECT_CALL(mock_root_handler, EndAttributes())
|
||||
.WillOnce(Return(false));
|
||||
EXPECT_CALL(mock_root_handler, Finish())
|
||||
.WillOnce(Return());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x15d6897480cc65a7LL,
|
||||
0x26, 0xa0,
|
||||
0x09f8bf0767f91675LL, 0xdb));
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0x7d08242b4b510cf2LL,
|
||||
(DwarfTag) 0xb4f98da6));
|
||||
EXPECT_FALSE(die_dispatcher.StartDIE(0x435150ceedccda18LL,
|
||||
(DwarfTag) 0xc3a17bba));
|
||||
die_dispatcher.EndDIE(0x435150ceedccda18LL);
|
||||
die_dispatcher.EndDIE(0x7d08242b4b510cf2LL);
|
||||
}
|
||||
|
||||
// The dispatcher should pass attribute values through to the die
|
||||
// handler accurately.
|
||||
TEST(Dwarf2DIEHandler, PassAttributeValues) {
|
||||
MockRootDIEHandler mock_root_handler;
|
||||
DIEDispatcher die_dispatcher(&mock_root_handler);
|
||||
|
||||
const uint8_t buffer[10] = {
|
||||
0x24, 0x24, 0x35, 0x9a, 0xca, 0xcf, 0xa8, 0x84, 0xa7, 0x18
|
||||
};
|
||||
string str = "\xc8\x26\x2e\x0d\xa4\x9c\x37\xd6\xfb\x1d";
|
||||
|
||||
// Set expectations.
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
// We'll like the compilation unit header.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartCompilationUnit(0x8d42aed77cfccf3eLL, 0x89, 0xdc,
|
||||
0x2ecb4dc778a80f21LL, 0x66))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// We'll like the root DIE.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartRootDIE(0xe2222da01e29f2a9LL, (DwarfTag) 0x9829445c))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// Expect some attribute values.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
ProcessAttributeUnsigned((DwarfAttribute) 0x1cc0bfed,
|
||||
(DwarfForm) 0x424f1468,
|
||||
0xa592571997facda1ULL))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
ProcessAttributeSigned((DwarfAttribute) 0x43694dc9,
|
||||
(DwarfForm) 0xf6f78901L,
|
||||
0x92602a4e3bf1f446LL))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
ProcessAttributeReference((DwarfAttribute) 0x4033e8cL,
|
||||
(DwarfForm) 0xf66fbe0bL,
|
||||
0x50fddef44734fdecULL))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
ProcessAttributeBuffer((DwarfAttribute) 0x25d7e0af,
|
||||
(DwarfForm) 0xe99a539a,
|
||||
buffer, sizeof(buffer)))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
ProcessAttributeString((DwarfAttribute) 0x310ed065,
|
||||
(DwarfForm) 0x15762fec,
|
||||
StrEq(str)))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
ProcessAttributeSignature((DwarfAttribute) 0x58790d72,
|
||||
(DwarfForm) 0x4159f138,
|
||||
0x94682463613e6a5fULL))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(mock_root_handler, EndAttributes())
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_root_handler, FindChildHandler(_, _))
|
||||
.Times(0);
|
||||
EXPECT_CALL(mock_root_handler, Finish())
|
||||
.WillOnce(Return());
|
||||
}
|
||||
|
||||
// Drive the dispatcher.
|
||||
|
||||
// Report the CU header.
|
||||
EXPECT_TRUE(die_dispatcher.StartCompilationUnit(0x8d42aed77cfccf3eLL,
|
||||
0x89, 0xdc,
|
||||
0x2ecb4dc778a80f21LL,
|
||||
0x66));
|
||||
// Report the root DIE.
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0xe2222da01e29f2a9LL,
|
||||
(DwarfTag) 0x9829445c));
|
||||
|
||||
// Report some attribute values.
|
||||
die_dispatcher.ProcessAttributeUnsigned(0xe2222da01e29f2a9LL,
|
||||
(DwarfAttribute) 0x1cc0bfed,
|
||||
(DwarfForm) 0x424f1468,
|
||||
0xa592571997facda1ULL);
|
||||
die_dispatcher.ProcessAttributeSigned(0xe2222da01e29f2a9LL,
|
||||
(DwarfAttribute) 0x43694dc9,
|
||||
(DwarfForm) 0xf6f78901,
|
||||
0x92602a4e3bf1f446LL);
|
||||
die_dispatcher.ProcessAttributeReference(0xe2222da01e29f2a9LL,
|
||||
(DwarfAttribute) 0x4033e8c,
|
||||
(DwarfForm) 0xf66fbe0b,
|
||||
0x50fddef44734fdecULL);
|
||||
die_dispatcher.ProcessAttributeBuffer(0xe2222da01e29f2a9LL,
|
||||
(DwarfAttribute) 0x25d7e0af,
|
||||
(DwarfForm) 0xe99a539a,
|
||||
buffer, sizeof(buffer));
|
||||
die_dispatcher.ProcessAttributeString(0xe2222da01e29f2a9LL,
|
||||
(DwarfAttribute) 0x310ed065,
|
||||
(DwarfForm) 0x15762fec,
|
||||
str);
|
||||
die_dispatcher.ProcessAttributeSignature(0xe2222da01e29f2a9LL,
|
||||
(DwarfAttribute) 0x58790d72,
|
||||
(DwarfForm) 0x4159f138,
|
||||
0x94682463613e6a5fULL);
|
||||
|
||||
// Finish the root DIE (and thus the CU).
|
||||
die_dispatcher.EndDIE(0xe2222da01e29f2a9LL);
|
||||
}
|
||||
|
||||
TEST(Dwarf2DIEHandler, FindAndSkipChildren) {
|
||||
MockRootDIEHandler mock_root_handler;
|
||||
MockDIEHandler *mock_child1_handler = new(MockDIEHandler);
|
||||
MockDIEHandler *mock_child3_handler = new(MockDIEHandler);
|
||||
DIEDispatcher die_dispatcher(&mock_root_handler);
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
// We'll like the compilation unit header.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21,
|
||||
0x47dd3c764275a216LL, 0xa5))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// Root DIE.
|
||||
{
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartRootDIE(0x15f0e06bdfe3c372LL, (DwarfTag) 0xf5d60c59))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
ProcessAttributeSigned((DwarfAttribute) 0xf779a642,
|
||||
(DwarfForm) 0x2cb63027,
|
||||
0x18e744661769d08fLL))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(mock_root_handler, EndAttributes())
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// First child DIE.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
FindChildHandler(0x149f644f8116fe8cLL,
|
||||
(DwarfTag) 0xac2cbd8c))
|
||||
.WillOnce(Return(mock_child1_handler));
|
||||
{
|
||||
EXPECT_CALL(*mock_child1_handler,
|
||||
ProcessAttributeSigned((DwarfAttribute) 0xa6fd6f65,
|
||||
(DwarfForm) 0xe4f64c41,
|
||||
0x1b04e5444a55fe67LL))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(*mock_child1_handler, EndAttributes())
|
||||
.WillOnce(Return(false));
|
||||
// Skip first grandchild DIE and first great-grandchild DIE.
|
||||
EXPECT_CALL(*mock_child1_handler, Finish())
|
||||
.WillOnce(Return());
|
||||
}
|
||||
|
||||
// Second child DIE. Root handler will decline to return a handler
|
||||
// for this child.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
FindChildHandler(0x97412be24875de9dLL,
|
||||
(DwarfTag) 0x505a068b))
|
||||
.WillOnce(Return((DIEHandler*) NULL));
|
||||
|
||||
// Third child DIE.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
FindChildHandler(0x753c964c8ab538aeLL,
|
||||
(DwarfTag) 0x8c22970e))
|
||||
.WillOnce(Return(mock_child3_handler));
|
||||
{
|
||||
EXPECT_CALL(*mock_child3_handler,
|
||||
ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb,
|
||||
(DwarfForm) 0x610b7ae1,
|
||||
0x3ea5c609d7d7560fLL))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(*mock_child3_handler, EndAttributes())
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(*mock_child3_handler, Finish())
|
||||
.WillOnce(Return());
|
||||
}
|
||||
|
||||
EXPECT_CALL(mock_root_handler, Finish())
|
||||
.WillOnce(Return());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Drive the dispatcher.
|
||||
|
||||
// Report the CU header.
|
||||
EXPECT_TRUE(die_dispatcher
|
||||
.StartCompilationUnit(0x9ec1e6d05e434a0eLL, 0xeb, 0x21,
|
||||
0x47dd3c764275a216LL, 0xa5));
|
||||
// Report the root DIE.
|
||||
{
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0x15f0e06bdfe3c372LL,
|
||||
(DwarfTag) 0xf5d60c59));
|
||||
die_dispatcher.ProcessAttributeSigned(0x15f0e06bdfe3c372LL,
|
||||
(DwarfAttribute) 0xf779a642,
|
||||
(DwarfForm) 0x2cb63027,
|
||||
0x18e744661769d08fLL);
|
||||
|
||||
// First child DIE.
|
||||
{
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0x149f644f8116fe8cLL,
|
||||
(DwarfTag) 0xac2cbd8c));
|
||||
die_dispatcher.ProcessAttributeSigned(0x149f644f8116fe8cLL,
|
||||
(DwarfAttribute) 0xa6fd6f65,
|
||||
(DwarfForm) 0xe4f64c41,
|
||||
0x1b04e5444a55fe67LL);
|
||||
|
||||
// First grandchild DIE. Will be skipped.
|
||||
{
|
||||
EXPECT_FALSE(die_dispatcher.StartDIE(0xd68de1ee0bd29419LL,
|
||||
(DwarfTag) 0x22f05a15));
|
||||
// First great-grandchild DIE. Will be skipped without being
|
||||
// mentioned to any handler.
|
||||
{
|
||||
EXPECT_FALSE(die_dispatcher
|
||||
.StartDIE(0xb3076285d25cac25LL,
|
||||
(DwarfTag) 0xcff4061b));
|
||||
die_dispatcher.EndDIE(0xb3076285d25cac25LL);
|
||||
}
|
||||
die_dispatcher.EndDIE(0xd68de1ee0bd29419LL);
|
||||
}
|
||||
die_dispatcher.EndDIE(0x149f644f8116fe8cLL);
|
||||
}
|
||||
|
||||
// Second child DIE. Root handler will decline to find a handler for it.
|
||||
{
|
||||
EXPECT_FALSE(die_dispatcher.StartDIE(0x97412be24875de9dLL,
|
||||
(DwarfTag) 0x505a068b));
|
||||
die_dispatcher.EndDIE(0x97412be24875de9dLL);
|
||||
}
|
||||
|
||||
// Third child DIE.
|
||||
{
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0x753c964c8ab538aeLL,
|
||||
(DwarfTag) 0x8c22970e));
|
||||
die_dispatcher.ProcessAttributeSigned(0x753c964c8ab538aeLL,
|
||||
(DwarfAttribute) 0x4e2b7cfb,
|
||||
(DwarfForm) 0x610b7ae1,
|
||||
0x3ea5c609d7d7560fLL);
|
||||
die_dispatcher.EndDIE(0x753c964c8ab538aeLL);
|
||||
}
|
||||
|
||||
// Finish the root DIE (and thus the CU).
|
||||
die_dispatcher.EndDIE(0x15f0e06bdfe3c372LL);
|
||||
}
|
||||
}
|
||||
|
||||
// The DIEDispatcher destructor is supposed to delete all handlers on
|
||||
// the stack, except for the root.
|
||||
TEST(Dwarf2DIEHandler, FreeHandlersOnStack) {
|
||||
MockRootDIEHandler mock_root_handler;
|
||||
MockDIEHandler *mock_child_handler = new(MockDIEHandler);
|
||||
MockDIEHandler *mock_grandchild_handler = new(MockDIEHandler);
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
// We'll like the compilation unit header.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89,
|
||||
0x76d392ff393ddda2LL, 0xbf))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// Root DIE.
|
||||
{
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
StartRootDIE(0xbf13b761691ddc91LL, (DwarfTag) 0x98980361))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(mock_root_handler, EndAttributes())
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// Child DIE.
|
||||
EXPECT_CALL(mock_root_handler,
|
||||
FindChildHandler(0x058f09240c5fc8c9LL,
|
||||
(DwarfTag) 0x898bf0d0))
|
||||
.WillOnce(Return(mock_child_handler));
|
||||
{
|
||||
EXPECT_CALL(*mock_child_handler, EndAttributes())
|
||||
.WillOnce(Return(true));
|
||||
|
||||
// Grandchild DIE.
|
||||
EXPECT_CALL(*mock_child_handler,
|
||||
FindChildHandler(0x32dc00c9945dc0c8LL,
|
||||
(DwarfTag) 0x2802d007))
|
||||
.WillOnce(Return(mock_grandchild_handler));
|
||||
{
|
||||
EXPECT_CALL(*mock_grandchild_handler,
|
||||
ProcessAttributeSigned((DwarfAttribute) 0x4e2b7cfb,
|
||||
(DwarfForm) 0x610b7ae1,
|
||||
0x3ea5c609d7d7560fLL))
|
||||
.WillOnce(Return());
|
||||
|
||||
// At this point, we abandon the traversal, so none of the
|
||||
// usual stuff should get called.
|
||||
EXPECT_CALL(*mock_grandchild_handler, EndAttributes())
|
||||
.Times(0);
|
||||
EXPECT_CALL(*mock_grandchild_handler, Finish())
|
||||
.Times(0);
|
||||
}
|
||||
|
||||
EXPECT_CALL(*mock_child_handler, Finish())
|
||||
.Times(0);
|
||||
}
|
||||
|
||||
EXPECT_CALL(mock_root_handler, Finish())
|
||||
.Times(0);
|
||||
}
|
||||
}
|
||||
|
||||
// The dispatcher.
|
||||
DIEDispatcher die_dispatcher(&mock_root_handler);
|
||||
|
||||
// Report the CU header.
|
||||
EXPECT_TRUE(die_dispatcher
|
||||
.StartCompilationUnit(0x87b41ba8381cd71cLL, 0xff, 0x89,
|
||||
0x76d392ff393ddda2LL, 0xbf));
|
||||
// Report the root DIE.
|
||||
{
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0xbf13b761691ddc91LL,
|
||||
(DwarfTag) 0x98980361));
|
||||
|
||||
// Child DIE.
|
||||
{
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0x058f09240c5fc8c9LL,
|
||||
(DwarfTag) 0x898bf0d0));
|
||||
|
||||
// Grandchild DIE.
|
||||
{
|
||||
EXPECT_TRUE(die_dispatcher.StartDIE(0x32dc00c9945dc0c8LL,
|
||||
(DwarfTag) 0x2802d007));
|
||||
die_dispatcher.ProcessAttributeSigned(0x32dc00c9945dc0c8LL,
|
||||
(DwarfAttribute) 0x4e2b7cfb,
|
||||
(DwarfForm) 0x610b7ae1,
|
||||
0x3ea5c609d7d7560fLL);
|
||||
|
||||
// Stop the traversal abruptly, so that there will still be
|
||||
// handlers on the stack when the dispatcher is destructed.
|
||||
|
||||
// No EndDIE call...
|
||||
}
|
||||
// No EndDIE call...
|
||||
}
|
||||
// No EndDIE call...
|
||||
}
|
||||
}
|
||||
744
externals/breakpad/src/common/dwarf/dwarf2enums.h
vendored
Normal file
744
externals/breakpad/src/common/dwarf/dwarf2enums.h
vendored
Normal file
|
|
@ -0,0 +1,744 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef COMMON_DWARF_DWARF2ENUMS_H__
|
||||
#define COMMON_DWARF_DWARF2ENUMS_H__
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// These enums do not follow the google3 style only because they are
|
||||
// known universally (specs, other implementations) by the names in
|
||||
// exactly this capitalization.
|
||||
// Tag names and codes.
|
||||
enum DwarfTag {
|
||||
DW_TAG_padding = 0x00,
|
||||
DW_TAG_array_type = 0x01,
|
||||
DW_TAG_class_type = 0x02,
|
||||
DW_TAG_entry_point = 0x03,
|
||||
DW_TAG_enumeration_type = 0x04,
|
||||
DW_TAG_formal_parameter = 0x05,
|
||||
DW_TAG_imported_declaration = 0x08,
|
||||
DW_TAG_label = 0x0a,
|
||||
DW_TAG_lexical_block = 0x0b,
|
||||
DW_TAG_member = 0x0d,
|
||||
DW_TAG_pointer_type = 0x0f,
|
||||
DW_TAG_reference_type = 0x10,
|
||||
DW_TAG_compile_unit = 0x11,
|
||||
DW_TAG_string_type = 0x12,
|
||||
DW_TAG_structure_type = 0x13,
|
||||
DW_TAG_subroutine_type = 0x15,
|
||||
DW_TAG_typedef = 0x16,
|
||||
DW_TAG_union_type = 0x17,
|
||||
DW_TAG_unspecified_parameters = 0x18,
|
||||
DW_TAG_variant = 0x19,
|
||||
DW_TAG_common_block = 0x1a,
|
||||
DW_TAG_common_inclusion = 0x1b,
|
||||
DW_TAG_inheritance = 0x1c,
|
||||
DW_TAG_inlined_subroutine = 0x1d,
|
||||
DW_TAG_module = 0x1e,
|
||||
DW_TAG_ptr_to_member_type = 0x1f,
|
||||
DW_TAG_set_type = 0x20,
|
||||
DW_TAG_subrange_type = 0x21,
|
||||
DW_TAG_with_stmt = 0x22,
|
||||
DW_TAG_access_declaration = 0x23,
|
||||
DW_TAG_base_type = 0x24,
|
||||
DW_TAG_catch_block = 0x25,
|
||||
DW_TAG_const_type = 0x26,
|
||||
DW_TAG_constant = 0x27,
|
||||
DW_TAG_enumerator = 0x28,
|
||||
DW_TAG_file_type = 0x29,
|
||||
DW_TAG_friend = 0x2a,
|
||||
DW_TAG_namelist = 0x2b,
|
||||
DW_TAG_namelist_item = 0x2c,
|
||||
DW_TAG_packed_type = 0x2d,
|
||||
DW_TAG_subprogram = 0x2e,
|
||||
DW_TAG_template_type_param = 0x2f,
|
||||
DW_TAG_template_value_param = 0x30,
|
||||
DW_TAG_thrown_type = 0x31,
|
||||
DW_TAG_try_block = 0x32,
|
||||
DW_TAG_variant_part = 0x33,
|
||||
DW_TAG_variable = 0x34,
|
||||
DW_TAG_volatile_type = 0x35,
|
||||
// DWARF 3.
|
||||
DW_TAG_dwarf_procedure = 0x36,
|
||||
DW_TAG_restrict_type = 0x37,
|
||||
DW_TAG_interface_type = 0x38,
|
||||
DW_TAG_namespace = 0x39,
|
||||
DW_TAG_imported_module = 0x3a,
|
||||
DW_TAG_unspecified_type = 0x3b,
|
||||
DW_TAG_partial_unit = 0x3c,
|
||||
DW_TAG_imported_unit = 0x3d,
|
||||
// DWARF 4.
|
||||
DW_TAG_type_unit = 0x41,
|
||||
// DWARF 5.
|
||||
DW_TAG_skeleton_unit = 0x4a,
|
||||
// SGI/MIPS Extensions.
|
||||
DW_TAG_MIPS_loop = 0x4081,
|
||||
// HP extensions. See:
|
||||
// ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz
|
||||
DW_TAG_HP_array_descriptor = 0x4090,
|
||||
// GNU extensions.
|
||||
DW_TAG_format_label = 0x4101, // For FORTRAN 77 and Fortran 90.
|
||||
DW_TAG_function_template = 0x4102, // For C++.
|
||||
DW_TAG_class_template = 0x4103, // For C++.
|
||||
DW_TAG_GNU_BINCL = 0x4104,
|
||||
DW_TAG_GNU_EINCL = 0x4105,
|
||||
// Extensions for UPC. See: http://upc.gwu.edu/~upc.
|
||||
DW_TAG_upc_shared_type = 0x8765,
|
||||
DW_TAG_upc_strict_type = 0x8766,
|
||||
DW_TAG_upc_relaxed_type = 0x8767,
|
||||
// PGI (STMicroelectronics) extensions. No documentation available.
|
||||
DW_TAG_PGI_kanji_type = 0xA000,
|
||||
DW_TAG_PGI_interface_block = 0xA020
|
||||
};
|
||||
|
||||
enum DwarfUnitHeader {
|
||||
DW_UT_compile = 0x01,
|
||||
DW_UT_type = 0x02,
|
||||
DW_UT_partial = 0x03,
|
||||
DW_UT_skeleton = 0x04,
|
||||
DW_UT_split_compile = 0x05,
|
||||
DW_UT_split_type = 0x06,
|
||||
DW_UT_lo_user = 0x80,
|
||||
DW_UT_hi_user = 0xFF
|
||||
};
|
||||
|
||||
enum DwarfHasChild {
|
||||
DW_children_no = 0,
|
||||
DW_children_yes = 1
|
||||
};
|
||||
|
||||
// Form names and codes.
|
||||
enum DwarfForm {
|
||||
DW_FORM_addr = 0x01,
|
||||
DW_FORM_block2 = 0x03,
|
||||
DW_FORM_block4 = 0x04,
|
||||
DW_FORM_data2 = 0x05,
|
||||
DW_FORM_data4 = 0x06,
|
||||
DW_FORM_data8 = 0x07,
|
||||
DW_FORM_string = 0x08,
|
||||
DW_FORM_block = 0x09,
|
||||
DW_FORM_block1 = 0x0a,
|
||||
DW_FORM_data1 = 0x0b,
|
||||
DW_FORM_flag = 0x0c,
|
||||
DW_FORM_sdata = 0x0d,
|
||||
DW_FORM_strp = 0x0e,
|
||||
DW_FORM_udata = 0x0f,
|
||||
DW_FORM_ref_addr = 0x10,
|
||||
DW_FORM_ref1 = 0x11,
|
||||
DW_FORM_ref2 = 0x12,
|
||||
DW_FORM_ref4 = 0x13,
|
||||
DW_FORM_ref8 = 0x14,
|
||||
DW_FORM_ref_udata = 0x15,
|
||||
DW_FORM_indirect = 0x16,
|
||||
|
||||
// Added in DWARF 4:
|
||||
DW_FORM_sec_offset = 0x17,
|
||||
DW_FORM_exprloc = 0x18,
|
||||
DW_FORM_flag_present = 0x19,
|
||||
|
||||
// Added in DWARF 5:
|
||||
DW_FORM_strx = 0x1a,
|
||||
DW_FORM_addrx = 0x1b,
|
||||
DW_FORM_ref_sup4 = 0x1c,
|
||||
DW_FORM_strp_sup = 0x1d,
|
||||
DW_FORM_data16 = 0x1e,
|
||||
DW_FORM_line_strp = 0x1f,
|
||||
|
||||
// DWARF 4, but value out of order.
|
||||
DW_FORM_ref_sig8 = 0x20,
|
||||
|
||||
// Added in DWARF 5:
|
||||
DW_FORM_implicit_const = 0x21,
|
||||
DW_FORM_loclistx = 0x22,
|
||||
DW_FORM_rnglistx = 0x23,
|
||||
DW_FORM_ref_sup8 = 0x24,
|
||||
DW_FORM_strx1 = 0x25,
|
||||
DW_FORM_strx2 = 0x26,
|
||||
DW_FORM_strx3 = 0x27,
|
||||
DW_FORM_strx4 = 0x28,
|
||||
|
||||
DW_FORM_addrx1 = 0x29,
|
||||
DW_FORM_addrx2 = 0x2a,
|
||||
DW_FORM_addrx3 = 0x2b,
|
||||
DW_FORM_addrx4 = 0x2c,
|
||||
|
||||
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
|
||||
DW_FORM_GNU_addr_index = 0x1f01,
|
||||
DW_FORM_GNU_str_index = 0x1f02
|
||||
};
|
||||
|
||||
// Attribute names and codes
|
||||
enum DwarfAttribute {
|
||||
DW_AT_sibling = 0x01,
|
||||
DW_AT_location = 0x02,
|
||||
DW_AT_name = 0x03,
|
||||
DW_AT_ordering = 0x09,
|
||||
DW_AT_subscr_data = 0x0a,
|
||||
DW_AT_byte_size = 0x0b,
|
||||
DW_AT_bit_offset = 0x0c,
|
||||
DW_AT_bit_size = 0x0d,
|
||||
DW_AT_element_list = 0x0f,
|
||||
DW_AT_stmt_list = 0x10,
|
||||
DW_AT_low_pc = 0x11,
|
||||
DW_AT_high_pc = 0x12,
|
||||
DW_AT_language = 0x13,
|
||||
DW_AT_member = 0x14,
|
||||
DW_AT_discr = 0x15,
|
||||
DW_AT_discr_value = 0x16,
|
||||
DW_AT_visibility = 0x17,
|
||||
DW_AT_import = 0x18,
|
||||
DW_AT_string_length = 0x19,
|
||||
DW_AT_common_reference = 0x1a,
|
||||
DW_AT_comp_dir = 0x1b,
|
||||
DW_AT_const_value = 0x1c,
|
||||
DW_AT_containing_type = 0x1d,
|
||||
DW_AT_default_value = 0x1e,
|
||||
DW_AT_inline = 0x20,
|
||||
DW_AT_is_optional = 0x21,
|
||||
DW_AT_lower_bound = 0x22,
|
||||
DW_AT_producer = 0x25,
|
||||
DW_AT_prototyped = 0x27,
|
||||
DW_AT_return_addr = 0x2a,
|
||||
DW_AT_start_scope = 0x2c,
|
||||
DW_AT_stride_size = 0x2e,
|
||||
DW_AT_upper_bound = 0x2f,
|
||||
DW_AT_abstract_origin = 0x31,
|
||||
DW_AT_accessibility = 0x32,
|
||||
DW_AT_address_class = 0x33,
|
||||
DW_AT_artificial = 0x34,
|
||||
DW_AT_base_types = 0x35,
|
||||
DW_AT_calling_convention = 0x36,
|
||||
DW_AT_count = 0x37,
|
||||
DW_AT_data_member_location = 0x38,
|
||||
DW_AT_decl_column = 0x39,
|
||||
DW_AT_decl_file = 0x3a,
|
||||
DW_AT_decl_line = 0x3b,
|
||||
DW_AT_declaration = 0x3c,
|
||||
DW_AT_discr_list = 0x3d,
|
||||
DW_AT_encoding = 0x3e,
|
||||
DW_AT_external = 0x3f,
|
||||
DW_AT_frame_base = 0x40,
|
||||
DW_AT_friend = 0x41,
|
||||
DW_AT_identifier_case = 0x42,
|
||||
DW_AT_macro_info = 0x43,
|
||||
DW_AT_namelist_items = 0x44,
|
||||
DW_AT_priority = 0x45,
|
||||
DW_AT_segment = 0x46,
|
||||
DW_AT_specification = 0x47,
|
||||
DW_AT_static_link = 0x48,
|
||||
DW_AT_type = 0x49,
|
||||
DW_AT_use_location = 0x4a,
|
||||
DW_AT_variable_parameter = 0x4b,
|
||||
DW_AT_virtuality = 0x4c,
|
||||
DW_AT_vtable_elem_location = 0x4d,
|
||||
// DWARF 3 values.
|
||||
DW_AT_allocated = 0x4e,
|
||||
DW_AT_associated = 0x4f,
|
||||
DW_AT_data_location = 0x50,
|
||||
DW_AT_stride = 0x51,
|
||||
DW_AT_entry_pc = 0x52,
|
||||
DW_AT_use_UTF8 = 0x53,
|
||||
DW_AT_extension = 0x54,
|
||||
DW_AT_ranges = 0x55,
|
||||
DW_AT_trampoline = 0x56,
|
||||
DW_AT_call_column = 0x57,
|
||||
DW_AT_call_file = 0x58,
|
||||
DW_AT_call_line = 0x59,
|
||||
// DWARF 4
|
||||
DW_AT_linkage_name = 0x6e,
|
||||
// DWARF 5
|
||||
DW_AT_str_offsets_base = 0x72,
|
||||
DW_AT_addr_base = 0x73,
|
||||
DW_AT_rnglists_base = 0x74,
|
||||
DW_AT_dwo_name = 0x76,
|
||||
// SGI/MIPS extensions.
|
||||
DW_AT_MIPS_fde = 0x2001,
|
||||
DW_AT_MIPS_loop_begin = 0x2002,
|
||||
DW_AT_MIPS_tail_loop_begin = 0x2003,
|
||||
DW_AT_MIPS_epilog_begin = 0x2004,
|
||||
DW_AT_MIPS_loop_unroll_factor = 0x2005,
|
||||
DW_AT_MIPS_software_pipeline_depth = 0x2006,
|
||||
DW_AT_MIPS_linkage_name = 0x2007,
|
||||
DW_AT_MIPS_stride = 0x2008,
|
||||
DW_AT_MIPS_abstract_name = 0x2009,
|
||||
DW_AT_MIPS_clone_origin = 0x200a,
|
||||
DW_AT_MIPS_has_inlines = 0x200b,
|
||||
// HP extensions.
|
||||
DW_AT_HP_block_index = 0x2000,
|
||||
DW_AT_HP_unmodifiable = 0x2001, // Same as DW_AT_MIPS_fde.
|
||||
DW_AT_HP_actuals_stmt_list = 0x2010,
|
||||
DW_AT_HP_proc_per_section = 0x2011,
|
||||
DW_AT_HP_raw_data_ptr = 0x2012,
|
||||
DW_AT_HP_pass_by_reference = 0x2013,
|
||||
DW_AT_HP_opt_level = 0x2014,
|
||||
DW_AT_HP_prof_version_id = 0x2015,
|
||||
DW_AT_HP_opt_flags = 0x2016,
|
||||
DW_AT_HP_cold_region_low_pc = 0x2017,
|
||||
DW_AT_HP_cold_region_high_pc = 0x2018,
|
||||
DW_AT_HP_all_variables_modifiable = 0x2019,
|
||||
DW_AT_HP_linkage_name = 0x201a,
|
||||
DW_AT_HP_prof_flags = 0x201b, // In comp unit of procs_info for -g.
|
||||
// GNU extensions.
|
||||
DW_AT_sf_names = 0x2101,
|
||||
DW_AT_src_info = 0x2102,
|
||||
DW_AT_mac_info = 0x2103,
|
||||
DW_AT_src_coords = 0x2104,
|
||||
DW_AT_body_begin = 0x2105,
|
||||
DW_AT_body_end = 0x2106,
|
||||
DW_AT_GNU_vector = 0x2107,
|
||||
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
|
||||
DW_AT_GNU_dwo_name = 0x2130,
|
||||
DW_AT_GNU_dwo_id = 0x2131,
|
||||
DW_AT_GNU_ranges_base = 0x2132,
|
||||
DW_AT_GNU_addr_base = 0x2133,
|
||||
DW_AT_GNU_pubnames = 0x2134,
|
||||
DW_AT_GNU_pubtypes = 0x2135,
|
||||
// VMS extensions.
|
||||
DW_AT_VMS_rtnbeg_pd_address = 0x2201,
|
||||
// UPC extension.
|
||||
DW_AT_upc_threads_scaled = 0x3210,
|
||||
// PGI (STMicroelectronics) extensions.
|
||||
DW_AT_PGI_lbase = 0x3a00,
|
||||
DW_AT_PGI_soffset = 0x3a01,
|
||||
DW_AT_PGI_lstride = 0x3a02
|
||||
};
|
||||
|
||||
// .debug_rngslist entry types
|
||||
enum DwarfRngListEntry {
|
||||
DW_RLE_end_of_list = 0,
|
||||
DW_RLE_base_addressx = 1,
|
||||
DW_RLE_startx_endx = 2,
|
||||
DW_RLE_startx_length = 3,
|
||||
DW_RLE_offset_pair = 4,
|
||||
DW_RLE_base_address = 5,
|
||||
DW_RLE_start_end = 6,
|
||||
DW_RLE_start_length = 7,
|
||||
};
|
||||
|
||||
// Line number content type codes (DWARF 5).
|
||||
enum DwarfLineNumberContentType {
|
||||
DW_LNCT_path = 1,
|
||||
DW_LNCT_directory_index = 2,
|
||||
DW_LNCT_timestamp = 3,
|
||||
DW_LNCT_size = 4,
|
||||
DW_LNCT_MD5 = 5,
|
||||
};
|
||||
|
||||
// Line number opcodes.
|
||||
enum DwarfLineNumberOps {
|
||||
DW_LNS_extended_op = 0,
|
||||
DW_LNS_copy = 1,
|
||||
DW_LNS_advance_pc = 2,
|
||||
DW_LNS_advance_line = 3,
|
||||
DW_LNS_set_file = 4,
|
||||
DW_LNS_set_column = 5,
|
||||
DW_LNS_negate_stmt = 6,
|
||||
DW_LNS_set_basic_block = 7,
|
||||
DW_LNS_const_add_pc = 8,
|
||||
DW_LNS_fixed_advance_pc = 9,
|
||||
// DWARF 3.
|
||||
DW_LNS_set_prologue_end = 10,
|
||||
DW_LNS_set_epilogue_begin = 11,
|
||||
DW_LNS_set_isa = 12
|
||||
};
|
||||
|
||||
// Line number extended opcodes.
|
||||
enum DwarfLineNumberExtendedOps {
|
||||
DW_LNE_end_sequence = 1,
|
||||
DW_LNE_set_address = 2,
|
||||
DW_LNE_define_file = 3,
|
||||
// HP extensions.
|
||||
DW_LNE_HP_negate_is_UV_update = 0x11,
|
||||
DW_LNE_HP_push_context = 0x12,
|
||||
DW_LNE_HP_pop_context = 0x13,
|
||||
DW_LNE_HP_set_file_line_column = 0x14,
|
||||
DW_LNE_HP_set_routine_name = 0x15,
|
||||
DW_LNE_HP_set_sequence = 0x16,
|
||||
DW_LNE_HP_negate_post_semantics = 0x17,
|
||||
DW_LNE_HP_negate_function_exit = 0x18,
|
||||
DW_LNE_HP_negate_front_end_logical = 0x19,
|
||||
DW_LNE_HP_define_proc = 0x20
|
||||
};
|
||||
|
||||
// Type encoding names and codes
|
||||
enum DwarfEncoding {
|
||||
DW_ATE_address =0x1,
|
||||
DW_ATE_boolean =0x2,
|
||||
DW_ATE_complex_float =0x3,
|
||||
DW_ATE_float =0x4,
|
||||
DW_ATE_signed =0x5,
|
||||
DW_ATE_signed_char =0x6,
|
||||
DW_ATE_unsigned =0x7,
|
||||
DW_ATE_unsigned_char =0x8,
|
||||
// DWARF3/DWARF3f
|
||||
DW_ATE_imaginary_float =0x9,
|
||||
DW_ATE_packed_decimal =0xa,
|
||||
DW_ATE_numeric_string =0xb,
|
||||
DW_ATE_edited =0xc,
|
||||
DW_ATE_signed_fixed =0xd,
|
||||
DW_ATE_unsigned_fixed =0xe,
|
||||
DW_ATE_decimal_float =0xf,
|
||||
DW_ATE_lo_user =0x80,
|
||||
DW_ATE_hi_user =0xff
|
||||
};
|
||||
|
||||
// Location virtual machine opcodes
|
||||
enum DwarfOpcode {
|
||||
DW_OP_addr =0x03,
|
||||
DW_OP_deref =0x06,
|
||||
DW_OP_const1u =0x08,
|
||||
DW_OP_const1s =0x09,
|
||||
DW_OP_const2u =0x0a,
|
||||
DW_OP_const2s =0x0b,
|
||||
DW_OP_const4u =0x0c,
|
||||
DW_OP_const4s =0x0d,
|
||||
DW_OP_const8u =0x0e,
|
||||
DW_OP_const8s =0x0f,
|
||||
DW_OP_constu =0x10,
|
||||
DW_OP_consts =0x11,
|
||||
DW_OP_dup =0x12,
|
||||
DW_OP_drop =0x13,
|
||||
DW_OP_over =0x14,
|
||||
DW_OP_pick =0x15,
|
||||
DW_OP_swap =0x16,
|
||||
DW_OP_rot =0x17,
|
||||
DW_OP_xderef =0x18,
|
||||
DW_OP_abs =0x19,
|
||||
DW_OP_and =0x1a,
|
||||
DW_OP_div =0x1b,
|
||||
DW_OP_minus =0x1c,
|
||||
DW_OP_mod =0x1d,
|
||||
DW_OP_mul =0x1e,
|
||||
DW_OP_neg =0x1f,
|
||||
DW_OP_not =0x20,
|
||||
DW_OP_or =0x21,
|
||||
DW_OP_plus =0x22,
|
||||
DW_OP_plus_uconst =0x23,
|
||||
DW_OP_shl =0x24,
|
||||
DW_OP_shr =0x25,
|
||||
DW_OP_shra =0x26,
|
||||
DW_OP_xor =0x27,
|
||||
DW_OP_bra =0x28,
|
||||
DW_OP_eq =0x29,
|
||||
DW_OP_ge =0x2a,
|
||||
DW_OP_gt =0x2b,
|
||||
DW_OP_le =0x2c,
|
||||
DW_OP_lt =0x2d,
|
||||
DW_OP_ne =0x2e,
|
||||
DW_OP_skip =0x2f,
|
||||
DW_OP_lit0 =0x30,
|
||||
DW_OP_lit1 =0x31,
|
||||
DW_OP_lit2 =0x32,
|
||||
DW_OP_lit3 =0x33,
|
||||
DW_OP_lit4 =0x34,
|
||||
DW_OP_lit5 =0x35,
|
||||
DW_OP_lit6 =0x36,
|
||||
DW_OP_lit7 =0x37,
|
||||
DW_OP_lit8 =0x38,
|
||||
DW_OP_lit9 =0x39,
|
||||
DW_OP_lit10 =0x3a,
|
||||
DW_OP_lit11 =0x3b,
|
||||
DW_OP_lit12 =0x3c,
|
||||
DW_OP_lit13 =0x3d,
|
||||
DW_OP_lit14 =0x3e,
|
||||
DW_OP_lit15 =0x3f,
|
||||
DW_OP_lit16 =0x40,
|
||||
DW_OP_lit17 =0x41,
|
||||
DW_OP_lit18 =0x42,
|
||||
DW_OP_lit19 =0x43,
|
||||
DW_OP_lit20 =0x44,
|
||||
DW_OP_lit21 =0x45,
|
||||
DW_OP_lit22 =0x46,
|
||||
DW_OP_lit23 =0x47,
|
||||
DW_OP_lit24 =0x48,
|
||||
DW_OP_lit25 =0x49,
|
||||
DW_OP_lit26 =0x4a,
|
||||
DW_OP_lit27 =0x4b,
|
||||
DW_OP_lit28 =0x4c,
|
||||
DW_OP_lit29 =0x4d,
|
||||
DW_OP_lit30 =0x4e,
|
||||
DW_OP_lit31 =0x4f,
|
||||
DW_OP_reg0 =0x50,
|
||||
DW_OP_reg1 =0x51,
|
||||
DW_OP_reg2 =0x52,
|
||||
DW_OP_reg3 =0x53,
|
||||
DW_OP_reg4 =0x54,
|
||||
DW_OP_reg5 =0x55,
|
||||
DW_OP_reg6 =0x56,
|
||||
DW_OP_reg7 =0x57,
|
||||
DW_OP_reg8 =0x58,
|
||||
DW_OP_reg9 =0x59,
|
||||
DW_OP_reg10 =0x5a,
|
||||
DW_OP_reg11 =0x5b,
|
||||
DW_OP_reg12 =0x5c,
|
||||
DW_OP_reg13 =0x5d,
|
||||
DW_OP_reg14 =0x5e,
|
||||
DW_OP_reg15 =0x5f,
|
||||
DW_OP_reg16 =0x60,
|
||||
DW_OP_reg17 =0x61,
|
||||
DW_OP_reg18 =0x62,
|
||||
DW_OP_reg19 =0x63,
|
||||
DW_OP_reg20 =0x64,
|
||||
DW_OP_reg21 =0x65,
|
||||
DW_OP_reg22 =0x66,
|
||||
DW_OP_reg23 =0x67,
|
||||
DW_OP_reg24 =0x68,
|
||||
DW_OP_reg25 =0x69,
|
||||
DW_OP_reg26 =0x6a,
|
||||
DW_OP_reg27 =0x6b,
|
||||
DW_OP_reg28 =0x6c,
|
||||
DW_OP_reg29 =0x6d,
|
||||
DW_OP_reg30 =0x6e,
|
||||
DW_OP_reg31 =0x6f,
|
||||
DW_OP_breg0 =0x70,
|
||||
DW_OP_breg1 =0x71,
|
||||
DW_OP_breg2 =0x72,
|
||||
DW_OP_breg3 =0x73,
|
||||
DW_OP_breg4 =0x74,
|
||||
DW_OP_breg5 =0x75,
|
||||
DW_OP_breg6 =0x76,
|
||||
DW_OP_breg7 =0x77,
|
||||
DW_OP_breg8 =0x78,
|
||||
DW_OP_breg9 =0x79,
|
||||
DW_OP_breg10 =0x7a,
|
||||
DW_OP_breg11 =0x7b,
|
||||
DW_OP_breg12 =0x7c,
|
||||
DW_OP_breg13 =0x7d,
|
||||
DW_OP_breg14 =0x7e,
|
||||
DW_OP_breg15 =0x7f,
|
||||
DW_OP_breg16 =0x80,
|
||||
DW_OP_breg17 =0x81,
|
||||
DW_OP_breg18 =0x82,
|
||||
DW_OP_breg19 =0x83,
|
||||
DW_OP_breg20 =0x84,
|
||||
DW_OP_breg21 =0x85,
|
||||
DW_OP_breg22 =0x86,
|
||||
DW_OP_breg23 =0x87,
|
||||
DW_OP_breg24 =0x88,
|
||||
DW_OP_breg25 =0x89,
|
||||
DW_OP_breg26 =0x8a,
|
||||
DW_OP_breg27 =0x8b,
|
||||
DW_OP_breg28 =0x8c,
|
||||
DW_OP_breg29 =0x8d,
|
||||
DW_OP_breg30 =0x8e,
|
||||
DW_OP_breg31 =0x8f,
|
||||
DW_OP_regX =0x90,
|
||||
DW_OP_fbreg =0x91,
|
||||
DW_OP_bregX =0x92,
|
||||
DW_OP_piece =0x93,
|
||||
DW_OP_deref_size =0x94,
|
||||
DW_OP_xderef_size =0x95,
|
||||
DW_OP_nop =0x96,
|
||||
// DWARF3/DWARF3f
|
||||
DW_OP_push_object_address =0x97,
|
||||
DW_OP_call2 =0x98,
|
||||
DW_OP_call4 =0x99,
|
||||
DW_OP_call_ref =0x9a,
|
||||
DW_OP_form_tls_address =0x9b,
|
||||
DW_OP_call_frame_cfa =0x9c,
|
||||
DW_OP_bit_piece =0x9d,
|
||||
DW_OP_lo_user =0xe0,
|
||||
DW_OP_hi_user =0xff,
|
||||
// GNU extensions
|
||||
DW_OP_GNU_push_tls_address =0xe0,
|
||||
// Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission.
|
||||
DW_OP_GNU_addr_index =0xfb,
|
||||
DW_OP_GNU_const_index =0xfc
|
||||
};
|
||||
|
||||
// Section identifiers for DWP files
|
||||
enum DwarfSectionId {
|
||||
DW_SECT_INFO = 1,
|
||||
DW_SECT_TYPES = 2,
|
||||
DW_SECT_ABBREV = 3,
|
||||
DW_SECT_LINE = 4,
|
||||
DW_SECT_LOCLISTS = 5,
|
||||
DW_SECT_STR_OFFSETS = 6,
|
||||
DW_SECT_MACRO = 7,
|
||||
DW_SECT_RNGLISTS = 8
|
||||
};
|
||||
|
||||
// Source languages. These are values for DW_AT_language.
|
||||
enum DwarfLanguage
|
||||
{
|
||||
DW_LANG_none =0x0000,
|
||||
DW_LANG_C89 =0x0001,
|
||||
DW_LANG_C =0x0002,
|
||||
DW_LANG_Ada83 =0x0003,
|
||||
DW_LANG_C_plus_plus =0x0004,
|
||||
DW_LANG_Cobol74 =0x0005,
|
||||
DW_LANG_Cobol85 =0x0006,
|
||||
DW_LANG_Fortran77 =0x0007,
|
||||
DW_LANG_Fortran90 =0x0008,
|
||||
DW_LANG_Pascal83 =0x0009,
|
||||
DW_LANG_Modula2 =0x000a,
|
||||
DW_LANG_Java =0x000b,
|
||||
DW_LANG_C99 =0x000c,
|
||||
DW_LANG_Ada95 =0x000d,
|
||||
DW_LANG_Fortran95 =0x000e,
|
||||
DW_LANG_PLI =0x000f,
|
||||
DW_LANG_ObjC =0x0010,
|
||||
DW_LANG_ObjC_plus_plus =0x0011,
|
||||
DW_LANG_UPC =0x0012,
|
||||
DW_LANG_D =0x0013,
|
||||
DW_LANG_Rust =0x001c,
|
||||
DW_LANG_Swift =0x001e,
|
||||
// Implementation-defined language code range.
|
||||
DW_LANG_lo_user = 0x8000,
|
||||
DW_LANG_hi_user = 0xffff,
|
||||
|
||||
// Extensions.
|
||||
|
||||
// MIPS assembly language. The GNU toolchain uses this for all
|
||||
// assembly languages, since there's no generic DW_LANG_ value for that.
|
||||
// See include/dwarf2.h in the binutils, gdb, or gcc source trees.
|
||||
DW_LANG_Mips_Assembler =0x8001,
|
||||
DW_LANG_Upc =0x8765 // Unified Parallel C
|
||||
};
|
||||
|
||||
// Inline codes. These are values for DW_AT_inline.
|
||||
enum DwarfInline {
|
||||
DW_INL_not_inlined =0x0,
|
||||
DW_INL_inlined =0x1,
|
||||
DW_INL_declared_not_inlined =0x2,
|
||||
DW_INL_declared_inlined =0x3
|
||||
};
|
||||
|
||||
// Call Frame Info instructions.
|
||||
enum DwarfCFI
|
||||
{
|
||||
DW_CFA_advance_loc = 0x40,
|
||||
DW_CFA_offset = 0x80,
|
||||
DW_CFA_restore = 0xc0,
|
||||
DW_CFA_nop = 0x00,
|
||||
DW_CFA_set_loc = 0x01,
|
||||
DW_CFA_advance_loc1 = 0x02,
|
||||
DW_CFA_advance_loc2 = 0x03,
|
||||
DW_CFA_advance_loc4 = 0x04,
|
||||
DW_CFA_offset_extended = 0x05,
|
||||
DW_CFA_restore_extended = 0x06,
|
||||
DW_CFA_undefined = 0x07,
|
||||
DW_CFA_same_value = 0x08,
|
||||
DW_CFA_register = 0x09,
|
||||
DW_CFA_remember_state = 0x0a,
|
||||
DW_CFA_restore_state = 0x0b,
|
||||
DW_CFA_def_cfa = 0x0c,
|
||||
DW_CFA_def_cfa_register = 0x0d,
|
||||
DW_CFA_def_cfa_offset = 0x0e,
|
||||
DW_CFA_def_cfa_expression = 0x0f,
|
||||
DW_CFA_expression = 0x10,
|
||||
DW_CFA_offset_extended_sf = 0x11,
|
||||
DW_CFA_def_cfa_sf = 0x12,
|
||||
DW_CFA_def_cfa_offset_sf = 0x13,
|
||||
DW_CFA_val_offset = 0x14,
|
||||
DW_CFA_val_offset_sf = 0x15,
|
||||
DW_CFA_val_expression = 0x16,
|
||||
|
||||
// Opcodes in this range are reserved for user extensions.
|
||||
DW_CFA_lo_user = 0x1c,
|
||||
DW_CFA_hi_user = 0x3f,
|
||||
|
||||
// SGI/MIPS specific.
|
||||
DW_CFA_MIPS_advance_loc8 = 0x1d,
|
||||
|
||||
// GNU extensions.
|
||||
DW_CFA_GNU_window_save = 0x2d,
|
||||
DW_CFA_GNU_args_size = 0x2e,
|
||||
DW_CFA_GNU_negative_offset_extended = 0x2f
|
||||
};
|
||||
|
||||
// Exception handling 'z' augmentation letters.
|
||||
enum DwarfZAugmentationCodes {
|
||||
// If the CFI augmentation string begins with 'z', then the CIE and FDE
|
||||
// have an augmentation data area just before the instructions, whose
|
||||
// contents are determined by the subsequent augmentation letters.
|
||||
DW_Z_augmentation_start = 'z',
|
||||
|
||||
// If this letter is present in a 'z' augmentation string, the CIE
|
||||
// augmentation data includes a pointer encoding, and the FDE
|
||||
// augmentation data includes a language-specific data area pointer,
|
||||
// represented using that encoding.
|
||||
DW_Z_has_LSDA = 'L',
|
||||
|
||||
// If this letter is present in a 'z' augmentation string, the CIE
|
||||
// augmentation data includes a pointer encoding, followed by a pointer
|
||||
// to a personality routine, represented using that encoding.
|
||||
DW_Z_has_personality_routine = 'P',
|
||||
|
||||
// If this letter is present in a 'z' augmentation string, the CIE
|
||||
// augmentation data includes a pointer encoding describing how the FDE's
|
||||
// initial location, address range, and DW_CFA_set_loc operands are
|
||||
// encoded.
|
||||
DW_Z_has_FDE_address_encoding = 'R',
|
||||
|
||||
// If this letter is present in a 'z' augmentation string, then code
|
||||
// addresses covered by FDEs that cite this CIE are signal delivery
|
||||
// trampolines. Return addresses of frames in trampolines should not be
|
||||
// adjusted as described in section 6.4.4 of the DWARF 3 spec.
|
||||
DW_Z_is_signal_trampoline = 'S'
|
||||
};
|
||||
|
||||
// Exception handling frame description pointer formats, as described
|
||||
// by the Linux Standard Base Core Specification 4.0, section 11.5,
|
||||
// DWARF Extensions.
|
||||
enum DwarfPointerEncoding
|
||||
{
|
||||
DW_EH_PE_absptr = 0x00,
|
||||
DW_EH_PE_omit = 0xff,
|
||||
DW_EH_PE_uleb128 = 0x01,
|
||||
DW_EH_PE_udata2 = 0x02,
|
||||
DW_EH_PE_udata4 = 0x03,
|
||||
DW_EH_PE_udata8 = 0x04,
|
||||
DW_EH_PE_sleb128 = 0x09,
|
||||
DW_EH_PE_sdata2 = 0x0A,
|
||||
DW_EH_PE_sdata4 = 0x0B,
|
||||
DW_EH_PE_sdata8 = 0x0C,
|
||||
DW_EH_PE_pcrel = 0x10,
|
||||
DW_EH_PE_textrel = 0x20,
|
||||
DW_EH_PE_datarel = 0x30,
|
||||
DW_EH_PE_funcrel = 0x40,
|
||||
DW_EH_PE_aligned = 0x50,
|
||||
|
||||
// The GNU toolchain sources define this enum value as well,
|
||||
// simply to help classify the lower nybble values into signed and
|
||||
// unsigned groups.
|
||||
DW_EH_PE_signed = 0x08,
|
||||
|
||||
// This is not documented in LSB 4.0, but it is used in both the
|
||||
// Linux and OS X toolchains. It can be added to any other
|
||||
// encoding (except DW_EH_PE_aligned), and indicates that the
|
||||
// encoded value represents the address at which the true address
|
||||
// is stored, not the true address itself.
|
||||
DW_EH_PE_indirect = 0x80
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
#endif // COMMON_DWARF_DWARF2ENUMS_H__
|
||||
3487
externals/breakpad/src/common/dwarf/dwarf2reader.cc
vendored
Normal file
3487
externals/breakpad/src/common/dwarf/dwarf2reader.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
1527
externals/breakpad/src/common/dwarf/dwarf2reader.h
vendored
Normal file
1527
externals/breakpad/src/common/dwarf/dwarf2reader.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
2590
externals/breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc
vendored
Normal file
2590
externals/breakpad/src/common/dwarf/dwarf2reader_cfi_unittest.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
968
externals/breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc
vendored
Normal file
968
externals/breakpad/src/common/dwarf/dwarf2reader_die_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,968 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dwarf2reader_die_unittest.cc: Unit tests for google_breakpad::CompilationUnit
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/dwarf/bytereader-inl.h"
|
||||
#include "common/dwarf/dwarf2reader_test_common.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
#include "common/using_std_string.h"
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
using google_breakpad::test_assembler::Endianness;
|
||||
using google_breakpad::test_assembler::Label;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
using google_breakpad::test_assembler::kBigEndian;
|
||||
using google_breakpad::test_assembler::kLittleEndian;
|
||||
|
||||
using google_breakpad::ByteReader;
|
||||
using google_breakpad::CompilationUnit;
|
||||
using google_breakpad::Dwarf2Handler;
|
||||
using google_breakpad::DwarfAttribute;
|
||||
using google_breakpad::DwarfForm;
|
||||
using google_breakpad::DwarfHasChild;
|
||||
using google_breakpad::DwarfTag;
|
||||
using google_breakpad::ENDIANNESS_BIG;
|
||||
using google_breakpad::ENDIANNESS_LITTLE;
|
||||
using google_breakpad::SectionMap;
|
||||
|
||||
using std::vector;
|
||||
using testing::InSequence;
|
||||
using testing::Pointee;
|
||||
using testing::Return;
|
||||
using testing::Sequence;
|
||||
using testing::Test;
|
||||
using testing::TestWithParam;
|
||||
using testing::_;
|
||||
|
||||
class MockDwarf2Handler: public Dwarf2Handler {
|
||||
public:
|
||||
MOCK_METHOD5(StartCompilationUnit, bool(uint64_t offset, uint8_t address_size,
|
||||
uint8_t offset_size,
|
||||
uint64_t cu_length,
|
||||
uint8_t dwarf_version));
|
||||
MOCK_METHOD2(StartDIE, bool(uint64_t offset, enum DwarfTag tag));
|
||||
MOCK_METHOD4(ProcessAttributeUnsigned, void(uint64_t offset,
|
||||
DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data));
|
||||
MOCK_METHOD4(ProcessAttributeSigned, void(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
int64_t data));
|
||||
MOCK_METHOD4(ProcessAttributeReference, void(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data));
|
||||
MOCK_METHOD5(ProcessAttributeBuffer, void(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const uint8_t* data,
|
||||
uint64_t len));
|
||||
MOCK_METHOD4(ProcessAttributeString, void(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string& data));
|
||||
MOCK_METHOD4(ProcessAttributeSignature, void(uint64_t offset,
|
||||
DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t signature));
|
||||
MOCK_METHOD1(EndDIE, void(uint64_t offset));
|
||||
};
|
||||
|
||||
struct DIEFixture {
|
||||
|
||||
DIEFixture() {
|
||||
// Fix the initial offset of the .debug_info and .debug_abbrev sections.
|
||||
info.start() = 0;
|
||||
abbrevs.start() = 0;
|
||||
|
||||
// Default expectations for the data handler.
|
||||
EXPECT_CALL(handler, StartCompilationUnit(_, _, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, StartDIE(_, _)).Times(0);
|
||||
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, ProcessAttributeSigned(_, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, ProcessAttributeReference(_, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, ProcessAttributeBuffer(_, _, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, ProcessAttributeString(_, _, _, _)).Times(0);
|
||||
EXPECT_CALL(handler, EndDIE(_)).Times(0);
|
||||
}
|
||||
|
||||
// Return a reference to a section map whose .debug_info section refers
|
||||
// to |info|, and whose .debug_abbrev section refers to |abbrevs|. This
|
||||
// function returns a reference to the same SectionMap each time; new
|
||||
// calls wipe out maps established by earlier calls.
|
||||
const SectionMap& MakeSectionMap() {
|
||||
// Copy the sections' contents into strings that will live as long as
|
||||
// the map itself.
|
||||
assert(info.GetContents(&info_contents));
|
||||
assert(abbrevs.GetContents(&abbrevs_contents));
|
||||
section_map.clear();
|
||||
section_map[".debug_info"].first
|
||||
= reinterpret_cast<const uint8_t*>(info_contents.data());
|
||||
section_map[".debug_info"].second = info_contents.size();
|
||||
section_map[".debug_abbrev"].first
|
||||
= reinterpret_cast<const uint8_t*>(abbrevs_contents.data());
|
||||
section_map[".debug_abbrev"].second = abbrevs_contents.size();
|
||||
return section_map;
|
||||
}
|
||||
|
||||
TestCompilationUnit info;
|
||||
TestAbbrevTable abbrevs;
|
||||
MockDwarf2Handler handler;
|
||||
string abbrevs_contents, info_contents;
|
||||
SectionMap section_map;
|
||||
};
|
||||
|
||||
struct DwarfHeaderParams {
|
||||
DwarfHeaderParams(Endianness endianness, size_t format_size,
|
||||
int version, size_t address_size, int header_type)
|
||||
: endianness(endianness), format_size(format_size),
|
||||
version(version), address_size(address_size), header_type(header_type)
|
||||
{ }
|
||||
Endianness endianness;
|
||||
size_t format_size; // 4-byte or 8-byte DWARF offsets
|
||||
int version;
|
||||
size_t address_size;
|
||||
int header_type; // DW_UT_{compile, type, partial, skeleton, etc}
|
||||
};
|
||||
|
||||
class DwarfHeader: public DIEFixture,
|
||||
public TestWithParam<DwarfHeaderParams> { };
|
||||
|
||||
TEST_P(DwarfHeader, Header) {
|
||||
Label abbrev_table = abbrevs.Here();
|
||||
abbrevs.Abbrev(1, google_breakpad::DW_TAG_compile_unit,
|
||||
google_breakpad::DW_children_yes)
|
||||
.Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_string)
|
||||
.EndAbbrev()
|
||||
.EndTable();
|
||||
|
||||
info.set_format_size(GetParam().format_size);
|
||||
info.set_endianness(GetParam().endianness);
|
||||
|
||||
info.Header(GetParam().version, abbrev_table, GetParam().address_size,
|
||||
google_breakpad::DW_UT_compile)
|
||||
.ULEB128(1) // DW_TAG_compile_unit, with children
|
||||
.AppendCString("sam") // DW_AT_name, DW_FORM_string
|
||||
.D8(0); // end of children
|
||||
info.Finish();
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
EXPECT_CALL(handler,
|
||||
StartCompilationUnit(0, GetParam().address_size,
|
||||
GetParam().format_size, _,
|
||||
GetParam().version))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_compile_unit))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name,
|
||||
google_breakpad::DW_FORM_string,
|
||||
"sam"))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(handler, EndDIE(_))
|
||||
.WillOnce(Return());
|
||||
}
|
||||
|
||||
ByteReader byte_reader(GetParam().endianness == kLittleEndian ?
|
||||
ENDIANNESS_LITTLE : ENDIANNESS_BIG);
|
||||
CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler);
|
||||
EXPECT_EQ(parser.Start(), info_contents.size());
|
||||
}
|
||||
|
||||
TEST_P(DwarfHeader, TypeUnitHeader) {
|
||||
Label abbrev_table = abbrevs.Here();
|
||||
int version = 5;
|
||||
abbrevs.Abbrev(1, google_breakpad::DW_TAG_type_unit,
|
||||
google_breakpad::DW_children_yes)
|
||||
.Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_string)
|
||||
.EndAbbrev()
|
||||
.EndTable();
|
||||
|
||||
info.set_format_size(GetParam().format_size);
|
||||
info.set_endianness(GetParam().endianness);
|
||||
|
||||
info.Header(version, abbrev_table, GetParam().address_size,
|
||||
google_breakpad::DW_UT_type)
|
||||
.ULEB128(0x41) // DW_TAG_type_unit, with children
|
||||
.AppendCString("sam") // DW_AT_name, DW_FORM_string
|
||||
.D8(0); // end of children
|
||||
info.Finish();
|
||||
|
||||
{
|
||||
InSequence s;
|
||||
EXPECT_CALL(handler,
|
||||
StartCompilationUnit(0, GetParam().address_size,
|
||||
GetParam().format_size, _,
|
||||
version))
|
||||
.WillOnce(Return(true));
|
||||
// If the type unit is handled properly, these calls will be skipped.
|
||||
EXPECT_CALL(handler, StartDIE(_, google_breakpad::DW_TAG_type_unit))
|
||||
.Times(0);
|
||||
EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name,
|
||||
google_breakpad::DW_FORM_string,
|
||||
"sam"))
|
||||
.Times(0);
|
||||
EXPECT_CALL(handler, EndDIE(_))
|
||||
.Times(0);
|
||||
}
|
||||
|
||||
ByteReader byte_reader(GetParam().endianness == kLittleEndian ?
|
||||
ENDIANNESS_LITTLE : ENDIANNESS_BIG);
|
||||
CompilationUnit parser("", MakeSectionMap(), 0, &byte_reader, &handler);
|
||||
EXPECT_EQ(parser.Start(), info_contents.size());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
HeaderVariants, DwarfHeader,
|
||||
::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 2, 8, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 3, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 3, 8, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 4, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 4, 8, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 2, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 2, 8, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 3, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 3, 8, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 4, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 4, 8, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 5, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 5, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 4, 2, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 4, 2, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 4, 3, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 4, 3, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 4, 4, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 4, 4, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 2, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 2, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 3, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 3, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 4, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 4, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 5, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 5, 8, 1)));
|
||||
|
||||
struct DwarfFormsFixture: public DIEFixture {
|
||||
// Start a compilation unit, as directed by |params|, containing one
|
||||
// childless DIE of the given tag, with one attribute of the given name
|
||||
// and form. The 'info' fixture member is left just after the abbrev
|
||||
// code, waiting for the attribute value to be appended.
|
||||
void StartSingleAttributeDIE(const DwarfHeaderParams& params,
|
||||
DwarfTag tag, DwarfAttribute name,
|
||||
DwarfForm form) {
|
||||
// Create the abbreviation table.
|
||||
Label abbrev_table = abbrevs.Here();
|
||||
abbrevs.Abbrev(1, tag, google_breakpad::DW_children_no)
|
||||
.Attribute(name, form)
|
||||
.EndAbbrev()
|
||||
.EndTable();
|
||||
|
||||
// Create the compilation unit, up to the attribute value.
|
||||
info.set_format_size(params.format_size);
|
||||
info.set_endianness(params.endianness);
|
||||
info.Header(params.version, abbrev_table, params.address_size,
|
||||
google_breakpad::DW_UT_compile)
|
||||
.ULEB128(1); // abbrev code
|
||||
}
|
||||
|
||||
// Set up handler to expect a compilation unit matching |params|,
|
||||
// containing one childless DIE of the given tag, in the sequence s. Stop
|
||||
// just before the expectations.
|
||||
void ExpectBeginCompilationUnit(const DwarfHeaderParams& params,
|
||||
DwarfTag tag, uint64_t offset=0) {
|
||||
EXPECT_CALL(handler,
|
||||
StartCompilationUnit(offset, params.address_size,
|
||||
params.format_size, _,
|
||||
params.version))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(handler, StartDIE(_, tag))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
void ExpectEndCompilationUnit() {
|
||||
EXPECT_CALL(handler, EndDIE(_))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
}
|
||||
|
||||
void ParseCompilationUnit(const DwarfHeaderParams& params,
|
||||
uint64_t offset=0) {
|
||||
ByteReader byte_reader(params.endianness == kLittleEndian ?
|
||||
ENDIANNESS_LITTLE : ENDIANNESS_BIG);
|
||||
CompilationUnit parser("", MakeSectionMap(), offset, &byte_reader,
|
||||
&handler);
|
||||
EXPECT_EQ(offset + parser.Start(), info_contents.size());
|
||||
}
|
||||
|
||||
// The sequence to which the fixture's methods append expectations.
|
||||
Sequence s;
|
||||
};
|
||||
|
||||
struct DwarfForms: public DwarfFormsFixture,
|
||||
public TestWithParam<DwarfHeaderParams> { };
|
||||
|
||||
TEST_P(DwarfForms, addr) {
|
||||
StartSingleAttributeDIE(GetParam(), google_breakpad::DW_TAG_compile_unit,
|
||||
google_breakpad::DW_AT_low_pc,
|
||||
google_breakpad::DW_FORM_addr);
|
||||
uint64_t value;
|
||||
if (GetParam().address_size == 4) {
|
||||
value = 0xc8e9ffcc;
|
||||
info.D32(value);
|
||||
} else {
|
||||
value = 0xe942517fc2768564ULL;
|
||||
info.D64(value);
|
||||
}
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), google_breakpad::DW_TAG_compile_unit);
|
||||
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc,
|
||||
google_breakpad::DW_FORM_addr,
|
||||
value))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, strx1) {
|
||||
if (GetParam().version != 5) {
|
||||
return;
|
||||
}
|
||||
Label abbrev_table = abbrevs.Here();
|
||||
abbrevs.Abbrev(1, google_breakpad::DW_TAG_compile_unit,
|
||||
google_breakpad::DW_children_no)
|
||||
.Attribute(google_breakpad::DW_AT_name, google_breakpad::DW_FORM_strx1)
|
||||
.Attribute(google_breakpad::DW_AT_low_pc, google_breakpad::DW_FORM_addr)
|
||||
.Attribute(google_breakpad::DW_AT_str_offsets_base,
|
||||
google_breakpad::DW_FORM_sec_offset)
|
||||
.EndAbbrev()
|
||||
.EndTable();
|
||||
|
||||
info.set_format_size(GetParam().format_size);
|
||||
info.set_endianness(GetParam().endianness);
|
||||
info.Header(GetParam().version, abbrev_table, GetParam().address_size,
|
||||
google_breakpad::DW_UT_compile)
|
||||
.ULEB128(1) // abbrev index
|
||||
.D8(2); // string index
|
||||
|
||||
uint64_t value;
|
||||
uint64_t offsets_base;
|
||||
if (GetParam().address_size == 4) {
|
||||
value = 0xc8e9ffcc;
|
||||
offsets_base = 8;
|
||||
info.D32(value); // low pc
|
||||
info.D32(offsets_base); // str_offsets_base
|
||||
} else {
|
||||
value = 0xe942517fc2768564ULL;
|
||||
offsets_base = 16;
|
||||
info.D64(value); // low_pc
|
||||
info.D64(offsets_base); // str_offsets_base
|
||||
}
|
||||
info.Finish();
|
||||
|
||||
Section debug_strings;
|
||||
// no header, just a series of null-terminated strings.
|
||||
debug_strings.AppendCString("apple"); // offset = 0
|
||||
debug_strings.AppendCString("bird"); // offset = 6
|
||||
debug_strings.AppendCString("canary"); // offset = 11
|
||||
debug_strings.AppendCString("dinosaur"); // offset = 18
|
||||
|
||||
Section str_offsets;
|
||||
str_offsets.set_endianness(GetParam().endianness);
|
||||
// Header for .debug_str_offsets
|
||||
if (GetParam().address_size == 4) {
|
||||
str_offsets.D32(24); // section length (4 bytes)
|
||||
} else {
|
||||
str_offsets.D32(0xffffffff);
|
||||
str_offsets.D64(48); // section length (12 bytes)
|
||||
}
|
||||
str_offsets.D16(GetParam().version); // version (2 bytes)
|
||||
str_offsets.D16(0); // padding (2 bytes)
|
||||
|
||||
// .debug_str_offsets data (the offsets)
|
||||
if (GetParam().address_size == 4) {
|
||||
str_offsets.D32(0);
|
||||
str_offsets.D32(6);
|
||||
str_offsets.D32(11);
|
||||
str_offsets.D32(18);
|
||||
} else {
|
||||
str_offsets.D64(0);
|
||||
str_offsets.D64(6);
|
||||
str_offsets.D64(11);
|
||||
str_offsets.D64(18);
|
||||
}
|
||||
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), google_breakpad::DW_TAG_compile_unit);
|
||||
EXPECT_CALL(handler, ProcessAttributeString(_, google_breakpad::DW_AT_name,
|
||||
google_breakpad::DW_FORM_strx1,
|
||||
"bird"))
|
||||
.WillOnce(Return());
|
||||
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, google_breakpad::DW_AT_low_pc,
|
||||
google_breakpad::DW_FORM_addr,
|
||||
value))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, block2_empty) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
|
||||
(DwarfAttribute) 0xe52c4463,
|
||||
google_breakpad::DW_FORM_block2);
|
||||
info.D16(0);
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
|
||||
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
|
||||
google_breakpad::DW_FORM_block2,
|
||||
_, 0))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, block2) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x16e4d2f7,
|
||||
(DwarfAttribute) 0xe52c4463,
|
||||
google_breakpad::DW_FORM_block2);
|
||||
unsigned char data[258];
|
||||
memset(data, '*', sizeof(data));
|
||||
info.D16(sizeof(data))
|
||||
.Append(data, sizeof(data));
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x16e4d2f7);
|
||||
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xe52c4463,
|
||||
google_breakpad::DW_FORM_block2,
|
||||
Pointee('*'), 258))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, flag_present) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x3e449ac2,
|
||||
(DwarfAttribute) 0x359d1972,
|
||||
google_breakpad::DW_FORM_flag_present);
|
||||
// DW_FORM_flag_present occupies no space in the DIE.
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x3e449ac2);
|
||||
EXPECT_CALL(handler,
|
||||
ProcessAttributeUnsigned(_, (DwarfAttribute) 0x359d1972,
|
||||
google_breakpad::DW_FORM_flag_present,
|
||||
1))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, sec_offset) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x1d971689,
|
||||
(DwarfAttribute) 0xa060bfd1,
|
||||
google_breakpad::DW_FORM_sec_offset);
|
||||
uint64_t value;
|
||||
if (GetParam().format_size == 4) {
|
||||
value = 0xacc9c388;
|
||||
info.D32(value);
|
||||
} else {
|
||||
value = 0xcffe5696ffe3ed0aULL;
|
||||
info.D64(value);
|
||||
}
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x1d971689);
|
||||
EXPECT_CALL(handler, ProcessAttributeUnsigned(_, (DwarfAttribute) 0xa060bfd1,
|
||||
google_breakpad::DW_FORM_sec_offset,
|
||||
value))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, exprloc) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0xb6d167bb,
|
||||
(DwarfAttribute) 0xba3ae5cb,
|
||||
google_breakpad::DW_FORM_exprloc);
|
||||
info.ULEB128(29)
|
||||
.Append(29, 173);
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0xb6d167bb);
|
||||
EXPECT_CALL(handler, ProcessAttributeBuffer(_, (DwarfAttribute) 0xba3ae5cb,
|
||||
google_breakpad::DW_FORM_exprloc,
|
||||
Pointee(173), 29))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, ref_sig8) {
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
|
||||
(DwarfAttribute) 0xd708d908,
|
||||
google_breakpad::DW_FORM_ref_sig8);
|
||||
info.D64(0xf72fa0cb6ddcf9d6ULL);
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
|
||||
EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
|
||||
google_breakpad::DW_FORM_ref_sig8,
|
||||
0xf72fa0cb6ddcf9d6ULL))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
// A value passed to ProcessAttributeSignature is just an absolute number,
|
||||
// not an offset within the compilation unit as most of the other
|
||||
// DW_FORM_ref forms are. Check that the reader doesn't try to apply any
|
||||
// offset to the signature, by reading it from a compilation unit that does
|
||||
// not start at the beginning of the section.
|
||||
TEST_P(DwarfForms, ref_sig8_not_first) {
|
||||
info.Append(98, '*');
|
||||
StartSingleAttributeDIE(GetParam(), (DwarfTag) 0x253e7b2b,
|
||||
(DwarfAttribute) 0xd708d908,
|
||||
google_breakpad::DW_FORM_ref_sig8);
|
||||
info.D64(0xf72fa0cb6ddcf9d6ULL);
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b, 98);
|
||||
EXPECT_CALL(handler, ProcessAttributeSignature(_, (DwarfAttribute) 0xd708d908,
|
||||
google_breakpad::DW_FORM_ref_sig8,
|
||||
0xf72fa0cb6ddcf9d6ULL))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam(), 98);
|
||||
}
|
||||
|
||||
TEST_P(DwarfForms, implicit_const) {
|
||||
const DwarfHeaderParams& params = GetParam();
|
||||
const uint64_t implicit_constant_value = 0x1234;
|
||||
// Create the abbreviation table.
|
||||
Label abbrev_table = abbrevs.Here();
|
||||
abbrevs.Abbrev(1, (DwarfTag) 0x253e7b2b, google_breakpad::DW_children_no)
|
||||
.Attribute((DwarfAttribute) 0xd708d908,
|
||||
google_breakpad::DW_FORM_implicit_const)
|
||||
.ULEB128(implicit_constant_value);
|
||||
abbrevs.EndAbbrev().EndTable();
|
||||
|
||||
info.set_format_size(params.format_size);
|
||||
info.set_endianness(params.endianness);
|
||||
info.Header(params.version, abbrev_table, params.address_size,
|
||||
google_breakpad::DW_UT_compile)
|
||||
.ULEB128(1); // abbrev code
|
||||
info.Finish();
|
||||
|
||||
ExpectBeginCompilationUnit(GetParam(), (DwarfTag) 0x253e7b2b);
|
||||
EXPECT_CALL(handler,
|
||||
ProcessAttributeUnsigned(_, (DwarfAttribute) 0xd708d908,
|
||||
google_breakpad::DW_FORM_implicit_const,
|
||||
implicit_constant_value))
|
||||
.InSequence(s)
|
||||
.WillOnce(Return());
|
||||
ExpectEndCompilationUnit();
|
||||
|
||||
ParseCompilationUnit(GetParam());
|
||||
}
|
||||
|
||||
// Tests for the other attribute forms could go here.
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
HeaderVariants, DwarfForms,
|
||||
::testing::Values(DwarfHeaderParams(kLittleEndian, 4, 2, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 2, 8, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 3, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 3, 8, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 4, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 4, 4, 8, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 2, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 2, 8, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 3, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 3, 8, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 4, 4, 1),
|
||||
DwarfHeaderParams(kLittleEndian, 8, 4, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 4, 2, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 4, 2, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 4, 3, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 4, 3, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 4, 4, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 4, 4, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 2, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 2, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 3, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 3, 8, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 4, 4, 1),
|
||||
DwarfHeaderParams(kBigEndian, 8, 4, 8, 1)));
|
||||
|
||||
class MockRangeListHandler: public google_breakpad::RangeListHandler {
|
||||
public:
|
||||
MOCK_METHOD(void, AddRange, (uint64_t begin, uint64_t end));
|
||||
MOCK_METHOD(void, Finish, ());
|
||||
};
|
||||
|
||||
TEST(RangeList, Dwarf4ReadRangeList) {
|
||||
using google_breakpad::RangeListReader;
|
||||
using google_breakpad::DW_FORM_sec_offset;
|
||||
|
||||
// Create a dwarf4 .debug_ranges section.
|
||||
google_breakpad::test_assembler::Section ranges(kBigEndian);
|
||||
std::string padding_offset = "padding offset";
|
||||
ranges.Append(padding_offset);
|
||||
const uint64_t section_offset = ranges.Size();
|
||||
ranges.D32(1).D32(2); // (2, 3)
|
||||
ranges.D32(0xFFFFFFFF).D32(3); // base_address = 3.
|
||||
ranges.D32(1).D32(2); // (4, 5)
|
||||
ranges.D32(0).D32(1); // (3, 4) An out of order entry is legal.
|
||||
ranges.D32(0).D32(0); // End of range.
|
||||
|
||||
std::string section_contents;
|
||||
ranges.GetContents(§ion_contents);
|
||||
|
||||
ByteReader byte_reader(ENDIANNESS_BIG);
|
||||
byte_reader.SetAddressSize(4);
|
||||
|
||||
RangeListReader::CURangesInfo cu_info;
|
||||
// Only set the fields that matter for dwarf 4.
|
||||
cu_info.version_ = 4;
|
||||
cu_info.base_address_ = 1;
|
||||
cu_info.buffer_ = reinterpret_cast<const uint8_t*>(section_contents.data());
|
||||
cu_info.size_ = section_contents.size();
|
||||
|
||||
MockRangeListHandler handler;
|
||||
google_breakpad::RangeListReader range_list_reader(&byte_reader, &cu_info,
|
||||
&handler);
|
||||
EXPECT_CALL(handler, AddRange(2, 3));
|
||||
EXPECT_CALL(handler, AddRange(4, 5));
|
||||
EXPECT_CALL(handler, AddRange(3, 4));
|
||||
EXPECT_CALL(handler, Finish());
|
||||
EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset,
|
||||
section_offset));
|
||||
}
|
||||
|
||||
TEST(RangeList, Dwarf5ReadRangeList_rnglists) {
|
||||
using google_breakpad::RangeListReader;
|
||||
using google_breakpad::DW_RLE_base_addressx;
|
||||
using google_breakpad::DW_RLE_startx_endx;
|
||||
using google_breakpad::DW_RLE_startx_length;
|
||||
using google_breakpad::DW_RLE_offset_pair;
|
||||
using google_breakpad::DW_RLE_end_of_list;
|
||||
using google_breakpad::DW_RLE_base_address;
|
||||
using google_breakpad::DW_RLE_start_end;
|
||||
using google_breakpad::DW_RLE_start_length;
|
||||
using google_breakpad::DW_FORM_sec_offset;
|
||||
using google_breakpad::DW_FORM_rnglistx;
|
||||
|
||||
// Size of header
|
||||
const uint64_t header_size = 12;
|
||||
// Size of length field in header
|
||||
const uint64_t length_size = 4;
|
||||
|
||||
// .debug_addr for the indexed entries like startx.
|
||||
Section addr;
|
||||
addr.set_endianness(kBigEndian);
|
||||
// Test addr_base handling with a padding address at 0.
|
||||
addr.D32(0).D32(1).D32(2).D32(3).D32(4);
|
||||
std::string addr_contents;
|
||||
assert(addr.GetContents(&addr_contents));
|
||||
|
||||
// .debug_rnglists is the dwarf 5 section.
|
||||
Section rnglists1(kBigEndian);
|
||||
Section rnglists2(kBigEndian);
|
||||
|
||||
// First header and body.
|
||||
Label section_size1;
|
||||
rnglists1.Append(kBigEndian, length_size, section_size1);
|
||||
rnglists1.D16(5); // Version
|
||||
rnglists1.D8(4); // Address size
|
||||
rnglists1.D8(0); // Segment selector size
|
||||
rnglists1.D32(2); // Offset entry count
|
||||
const uint64_t ranges_base_1 = rnglists1.Size();
|
||||
|
||||
// Offset entries.
|
||||
Label range0;
|
||||
rnglists1.Append(kBigEndian, 4, range0);
|
||||
Label range1;
|
||||
rnglists1.Append(kBigEndian, 4, range1);
|
||||
|
||||
// Range 0 (will be read via DW_AT_ranges, DW_FORM_rnglistx).
|
||||
range0 = rnglists1.Size() - header_size;
|
||||
rnglists1.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1
|
||||
rnglists1.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3)
|
||||
rnglists1.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5)
|
||||
rnglists1.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7)
|
||||
rnglists1.D8(DW_RLE_end_of_list);
|
||||
|
||||
// Range 1 (will be read via DW_AT_ranges, DW_FORM_rnglistx).
|
||||
range1 = rnglists1.Size() - header_size;
|
||||
rnglists1.D8(DW_RLE_base_address).D32(8); // base_addr = 8
|
||||
rnglists1.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [9, 10)
|
||||
rnglists1.D8(DW_RLE_start_end).D32(10).D32(11); // [10, 11)
|
||||
rnglists1.D8(DW_RLE_start_length).D32(12).ULEB128(1); // [12, 13)
|
||||
rnglists1.D8(DW_RLE_end_of_list);
|
||||
// The size doesn't include the size of length field itself.
|
||||
section_size1 = rnglists1.Size() - length_size;
|
||||
|
||||
// Second header and body.
|
||||
Label section_size2;
|
||||
rnglists2.Append(kBigEndian, length_size, section_size2);
|
||||
rnglists2.D16(5); // Version
|
||||
rnglists2.D8(4); // Address size
|
||||
rnglists2.D8(0); // Segment selector size
|
||||
rnglists2.D32(2); // Offset entry count
|
||||
const uint64_t ranges_base_2 = rnglists1.Size() + rnglists2.Size();
|
||||
|
||||
// Offset entries.
|
||||
Label range2;
|
||||
rnglists2.Append(kBigEndian, 4, range2);
|
||||
Label range3;
|
||||
rnglists2.Append(kBigEndian, 4, range3);
|
||||
|
||||
// Range 2 (will be read via DW_AT_ranges, DW_FORM_sec_offset).
|
||||
range2 = rnglists2.Size() - header_size;
|
||||
rnglists2.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1
|
||||
rnglists2.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3)
|
||||
rnglists2.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5)
|
||||
rnglists2.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7)
|
||||
rnglists2.D8(DW_RLE_end_of_list);
|
||||
|
||||
// Range 3 (will be read via DW_AT_ranges, DW_FORM_rnglistx).
|
||||
range3 = rnglists2.Size() - header_size;
|
||||
rnglists2.D8(DW_RLE_base_address).D32(15); // base_addr = 15
|
||||
rnglists2.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [16, 17)
|
||||
rnglists2.D8(DW_RLE_start_end).D32(17).D32(18); // [17, 18)
|
||||
rnglists2.D8(DW_RLE_start_length).D32(19).ULEB128(1); // [19, 20)
|
||||
rnglists2.D8(DW_RLE_end_of_list);
|
||||
// The size doesn't include the size of length field itself.
|
||||
section_size2 = rnglists2.Size() - length_size;
|
||||
|
||||
rnglists1.Append(rnglists2);
|
||||
string rnglists_contents;
|
||||
assert(rnglists1.GetContents(&rnglists_contents));
|
||||
|
||||
RangeListReader::CURangesInfo cu_info;
|
||||
cu_info.version_ = 5;
|
||||
cu_info.base_address_ = 1;
|
||||
cu_info.ranges_base_ = ranges_base_1;
|
||||
cu_info.buffer_ =
|
||||
reinterpret_cast<const uint8_t*>(rnglists_contents.data());
|
||||
cu_info.size_ = rnglists_contents.size();
|
||||
cu_info.addr_buffer_ =
|
||||
reinterpret_cast<const uint8_t*>(addr_contents.data());
|
||||
cu_info.addr_buffer_size_ = addr_contents.size();
|
||||
cu_info.addr_base_ = 4;
|
||||
|
||||
ByteReader byte_reader(ENDIANNESS_BIG);
|
||||
byte_reader.SetOffsetSize(4);
|
||||
byte_reader.SetAddressSize(4);
|
||||
MockRangeListHandler handler;
|
||||
google_breakpad::RangeListReader range_list_reader1(&byte_reader, &cu_info,
|
||||
&handler);
|
||||
EXPECT_CALL(handler, AddRange(2, 3));
|
||||
EXPECT_CALL(handler, AddRange(4, 5));
|
||||
EXPECT_CALL(handler, AddRange(6, 7));
|
||||
EXPECT_CALL(handler, AddRange(9, 10));
|
||||
EXPECT_CALL(handler, AddRange(10, 11));
|
||||
EXPECT_CALL(handler, AddRange(12, 13));
|
||||
EXPECT_CALL(handler, Finish()).Times(2);
|
||||
EXPECT_TRUE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 0));
|
||||
EXPECT_TRUE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 1));
|
||||
// Out of range index, should result in no calls.
|
||||
EXPECT_FALSE(range_list_reader1.ReadRanges(DW_FORM_rnglistx, 2));
|
||||
|
||||
// Set to new ranges_base
|
||||
cu_info.ranges_base_ = ranges_base_2;
|
||||
google_breakpad::RangeListReader range_list_reader2(&byte_reader, &cu_info,
|
||||
&handler);
|
||||
EXPECT_CALL(handler, AddRange(2, 3));
|
||||
EXPECT_CALL(handler, AddRange(4, 5));
|
||||
EXPECT_CALL(handler, AddRange(6, 7));
|
||||
EXPECT_CALL(handler, AddRange(16, 17));
|
||||
EXPECT_CALL(handler, AddRange(17, 18));
|
||||
EXPECT_CALL(handler, AddRange(19, 20));
|
||||
EXPECT_CALL(handler, Finish()).Times(2);
|
||||
EXPECT_TRUE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 0));
|
||||
EXPECT_TRUE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 1));
|
||||
// Out of range index, should result in no calls.
|
||||
EXPECT_FALSE(range_list_reader2.ReadRanges(DW_FORM_rnglistx, 2));
|
||||
}
|
||||
|
||||
TEST(RangeList, Dwarf5ReadRangeList_sec_offset) {
|
||||
using google_breakpad::RangeListReader;
|
||||
using google_breakpad::DW_RLE_base_addressx;
|
||||
using google_breakpad::DW_RLE_startx_endx;
|
||||
using google_breakpad::DW_RLE_startx_length;
|
||||
using google_breakpad::DW_RLE_offset_pair;
|
||||
using google_breakpad::DW_RLE_end_of_list;
|
||||
using google_breakpad::DW_RLE_base_address;
|
||||
using google_breakpad::DW_RLE_start_end;
|
||||
using google_breakpad::DW_RLE_start_length;
|
||||
using google_breakpad::DW_FORM_sec_offset;
|
||||
using google_breakpad::DW_FORM_rnglistx;
|
||||
|
||||
// Size of length field in header
|
||||
const uint64_t length_size = 4;
|
||||
|
||||
// .debug_addr for the indexed entries like startx.
|
||||
Section addr;
|
||||
addr.set_endianness(kBigEndian);
|
||||
// Test addr_base handling with a padding address at 0.
|
||||
addr.D32(0).D32(1).D32(2).D32(3).D32(4).D32(21).D32(22);
|
||||
std::string addr_contents;
|
||||
assert(addr.GetContents(&addr_contents));
|
||||
|
||||
// .debug_rnglists is the dwarf 5 section.
|
||||
Section rnglists1(kBigEndian);
|
||||
Section rnglists2(kBigEndian);
|
||||
|
||||
// First header and body.
|
||||
Label section_size1;
|
||||
rnglists1.Append(kBigEndian, length_size, section_size1);
|
||||
rnglists1.D16(5); // Version
|
||||
rnglists1.D8(4); // Address size
|
||||
rnglists1.D8(0); // Segment selector size
|
||||
rnglists1.D32(0); // Offset entry count
|
||||
|
||||
const uint64_t offset1 = rnglists1.Size();
|
||||
|
||||
rnglists1.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1
|
||||
rnglists1.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3)
|
||||
rnglists1.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5)
|
||||
rnglists1.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7)
|
||||
rnglists1.D8(DW_RLE_base_address).D32(8); // base_addr = 8
|
||||
rnglists1.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [9, 10)
|
||||
rnglists1.D8(DW_RLE_start_end).D32(10).D32(11); // [10, 11)
|
||||
rnglists1.D8(DW_RLE_start_length).D32(12).ULEB128(1); // [12, 13)
|
||||
rnglists1.D8(DW_RLE_end_of_list);
|
||||
// The size doesn't include the size of length field itself.
|
||||
section_size1 = rnglists1.Size() - length_size;
|
||||
|
||||
// Second header and body.
|
||||
Label section_size2;
|
||||
rnglists2.Append(kBigEndian, length_size, section_size2);
|
||||
rnglists2.D16(5); // Version
|
||||
rnglists2.D8(4); // Address size
|
||||
rnglists2.D8(0); // Segment selector size
|
||||
rnglists2.D32(0); // Offset entry count
|
||||
|
||||
const uint64_t offset2 = rnglists1.Size() + rnglists2.Size();
|
||||
|
||||
rnglists2.D8(DW_RLE_base_addressx).ULEB128(0); // base_addr = 1
|
||||
rnglists2.D8(DW_RLE_startx_endx).ULEB128(1).ULEB128(2); // [2, 3)
|
||||
rnglists2.D8(DW_RLE_startx_length).ULEB128(3).ULEB128(1); // [4, 5)
|
||||
rnglists2.D8(DW_RLE_offset_pair).ULEB128(5).ULEB128(6); // [6, 7)
|
||||
rnglists2.D8(DW_RLE_base_address).D32(15); // base_addr = 15
|
||||
rnglists2.D8(DW_RLE_offset_pair).ULEB128(1).ULEB128(2); // [16, 17)
|
||||
rnglists2.D8(DW_RLE_start_end).D32(17).D32(18); // [17, 18)
|
||||
rnglists2.D8(DW_RLE_start_length).D32(19).ULEB128(1); // [19, 20)
|
||||
rnglists2.D8(DW_RLE_end_of_list);
|
||||
// The size doesn't include the size of length field itself.
|
||||
section_size2 = rnglists2.Size() - length_size;
|
||||
|
||||
rnglists1.Append(rnglists2);
|
||||
string rnglists_contents;
|
||||
assert(rnglists1.GetContents(&rnglists_contents));
|
||||
|
||||
RangeListReader::CURangesInfo cu_info;
|
||||
cu_info.version_ = 5;
|
||||
cu_info.base_address_ = 1;
|
||||
cu_info.buffer_ =
|
||||
reinterpret_cast<const uint8_t*>(rnglists_contents.data());
|
||||
cu_info.size_ = rnglists_contents.size();
|
||||
cu_info.addr_buffer_ =
|
||||
reinterpret_cast<const uint8_t*>(addr_contents.data());
|
||||
cu_info.addr_buffer_size_ = addr_contents.size();
|
||||
cu_info.addr_base_ = 4;
|
||||
|
||||
ByteReader byte_reader(ENDIANNESS_BIG);
|
||||
byte_reader.SetOffsetSize(4);
|
||||
byte_reader.SetAddressSize(4);
|
||||
MockRangeListHandler handler;
|
||||
google_breakpad::RangeListReader range_list_reader(&byte_reader, &cu_info,
|
||||
&handler);
|
||||
EXPECT_CALL(handler, AddRange(2, 3));
|
||||
EXPECT_CALL(handler, AddRange(4, 5));
|
||||
EXPECT_CALL(handler, AddRange(6, 7));
|
||||
EXPECT_CALL(handler, AddRange(9, 10));
|
||||
EXPECT_CALL(handler, AddRange(10, 11));
|
||||
EXPECT_CALL(handler, AddRange(12, 13));
|
||||
EXPECT_CALL(handler, Finish()).Times(1);
|
||||
EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, offset1));
|
||||
// Out of range index, should result in no calls.
|
||||
EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_sec_offset,
|
||||
rnglists_contents.size()));
|
||||
|
||||
EXPECT_CALL(handler, AddRange(2, 3));
|
||||
EXPECT_CALL(handler, AddRange(4, 5));
|
||||
EXPECT_CALL(handler, AddRange(6, 7));
|
||||
EXPECT_CALL(handler, AddRange(16, 17));
|
||||
EXPECT_CALL(handler, AddRange(17, 18));
|
||||
EXPECT_CALL(handler, AddRange(19, 20));
|
||||
EXPECT_CALL(handler, Finish()).Times(1);
|
||||
EXPECT_TRUE(range_list_reader.ReadRanges(DW_FORM_sec_offset, offset2));
|
||||
// Out of range index, should result in no calls.
|
||||
EXPECT_FALSE(range_list_reader.ReadRanges(DW_FORM_sec_offset,
|
||||
rnglists_contents.size()));
|
||||
}
|
||||
190
externals/breakpad/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc
vendored
Normal file
190
externals/breakpad/src/common/dwarf/dwarf2reader_lineinfo_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 LLC 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: Sterling Augustine <saugustine@google.com>
|
||||
|
||||
// dwarf2reader_lineinfo_unittest.cc: Unit tests for google_breakpad::LineInfo
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/dwarf/bytereader.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
using std::vector;
|
||||
using testing::InSequence;
|
||||
using testing::Return;
|
||||
using testing::Sequence;
|
||||
using testing::Test;
|
||||
using testing::_;
|
||||
|
||||
using namespace google_breakpad;
|
||||
|
||||
namespace {
|
||||
|
||||
const uint8_t dwarf5_line_program[] = {
|
||||
0x40, 0x0, 0x0, 0x0, // unit_length (end - begin)
|
||||
// begin
|
||||
0x05, 0x0, // version
|
||||
0x8, // address_size
|
||||
0x0, // segment_selector_size
|
||||
0x26, 0x0, 0x0, 0x0, // header_length (end_header_end - begin_header)
|
||||
// begin_header:
|
||||
0x1, // minimum_instruction_length
|
||||
0x1, // maximum_operations_per_instruction
|
||||
0x1, // default_is_stmt
|
||||
0xfb, // line_base
|
||||
0xe, // line_range
|
||||
0xd, // opcode_base and lengths
|
||||
0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1,
|
||||
0x1, // directory entry format count
|
||||
DW_LNCT_path, DW_FORM_strp,
|
||||
0x1, // directories count
|
||||
0x1, 0x0, 0x0, 0x0, // offset into .debug_line_str
|
||||
0x2, // file_name_entry_format_count
|
||||
DW_LNCT_directory_index, DW_FORM_data1,
|
||||
DW_LNCT_path, DW_FORM_line_strp,
|
||||
0x1, // filename count
|
||||
0x0, // directory index
|
||||
0x1, 0x0, 0x0, 0x0, // offset into .debug_str
|
||||
// end_header
|
||||
DW_LNS_set_file, 0x0,
|
||||
// set address to 0x0
|
||||
0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
// Advance Address by 0 and line by 3
|
||||
0x15,
|
||||
// Advance PC by 1
|
||||
0x2, 0x1,
|
||||
0x0,
|
||||
DW_LNE_end_sequence,
|
||||
DW_LNE_end_sequence,
|
||||
// end
|
||||
};
|
||||
|
||||
const uint8_t dwarf4_line_program[] = {
|
||||
0x37, 0x0, 0x0, 0x0, // unit_length (end - begin)
|
||||
// begin
|
||||
0x04, 0x0, // version
|
||||
0x1d, 0x0, 0x0, 0x0, // header_length (end_header - begin_header)
|
||||
// begin_header:
|
||||
0x1, // minimum_instruction_length
|
||||
0x1, // maximum_operations_per_instruction
|
||||
0x1, // default_is_stmt
|
||||
0xfb, // line_base
|
||||
0xe, // line_range
|
||||
0xd, // opcode_base and lengths
|
||||
0x0, 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1,
|
||||
'/', 'a', '\0', // directory entry 1 (zeroth entry implied)
|
||||
'\0', // end of directory table
|
||||
'b', '/', 'c', '\0', // file entry 1 (zeroth entry implied)
|
||||
0, // file 1 directory
|
||||
0, // file 1 modification time
|
||||
0, // file 1 length
|
||||
'\0', // end of file table
|
||||
// end_header
|
||||
DW_LNS_set_file, 0x0,
|
||||
// set address to 0x0
|
||||
0x0, 0x9, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
// Advance Address by 0 and line by 3
|
||||
0x15,
|
||||
// Advance PC by 1
|
||||
0x2, 0x1,
|
||||
0x0,
|
||||
DW_LNE_end_sequence,
|
||||
DW_LNE_end_sequence,
|
||||
// end
|
||||
};
|
||||
|
||||
class MockLineInfoHandler: public LineInfoHandler {
|
||||
public:
|
||||
MOCK_METHOD(void, DefineDir, (const string&, uint32_t dir_num), (override));
|
||||
MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num,
|
||||
uint32_t dir_num, uint64_t mod_time,
|
||||
uint64_t length), (override));
|
||||
MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length,
|
||||
uint32_t file_num, uint32_t line_num,
|
||||
uint32_t column_num), (override));
|
||||
};
|
||||
|
||||
const uint8_t string_section[] = {'x', '/', 'a', '\0'};
|
||||
const uint8_t line_string_section[] = {'x', 'b', '/', 'c', '\0' };
|
||||
|
||||
struct LineProgram: public Test {
|
||||
MockLineInfoHandler handler_;
|
||||
};
|
||||
|
||||
TEST_F(LineProgram, ReadLinesDwarf5) {
|
||||
ByteReader byte_reader(ENDIANNESS_LITTLE);
|
||||
// LineTables don't specify the offset size like Compilation Units do.
|
||||
byte_reader.SetOffsetSize(4);
|
||||
LineInfo line_reader(dwarf5_line_program,
|
||||
sizeof(dwarf5_line_program),
|
||||
&byte_reader,
|
||||
string_section,
|
||||
sizeof(string_section),
|
||||
line_string_section,
|
||||
sizeof(line_string_section),
|
||||
&handler_);
|
||||
EXPECT_CALL(handler_, DefineDir("/a", 0)).Times(1);
|
||||
EXPECT_CALL(handler_, DefineFile("b/c", 0, 0, 0, 0)).Times(1);
|
||||
EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1);
|
||||
EXPECT_EQ(line_reader.Start(), sizeof(dwarf5_line_program));
|
||||
}
|
||||
|
||||
TEST_F(LineProgram, ReadLinesDwarf4) {
|
||||
ByteReader byte_reader(ENDIANNESS_LITTLE);
|
||||
// LineTables don't specify the offset size like Compilation Units do.
|
||||
byte_reader.SetOffsetSize(4);
|
||||
// dwarf4 line info headers don't encode the address size.
|
||||
byte_reader.SetAddressSize(8);
|
||||
LineInfo line_reader(dwarf4_line_program,
|
||||
sizeof(dwarf4_line_program),
|
||||
&byte_reader,
|
||||
// dwarf4 line tables can't access the string sections
|
||||
// so pass values likely to make assertions fail if
|
||||
// the code uses them improperly.
|
||||
nullptr, 0, nullptr, 0,
|
||||
&handler_);
|
||||
EXPECT_CALL(handler_, DefineDir("", 0)).Times(1);
|
||||
EXPECT_CALL(handler_, DefineDir("/a", 1)).Times(1);
|
||||
EXPECT_CALL(handler_, DefineFile("", 0, 0, 0, 0)).Times(1);
|
||||
EXPECT_CALL(handler_, DefineFile("b/c", 1, 0, 0, 0)).Times(1);
|
||||
EXPECT_CALL(handler_, AddLine(0, 1, 0, 4, 0)).Times(1);
|
||||
EXPECT_EQ(line_reader.Start(), sizeof(dwarf4_line_program));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
129
externals/breakpad/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc
vendored
Normal file
129
externals/breakpad/src/common/dwarf/dwarf2reader_splitfunctions_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
// Copyright 2020 Google LLC
|
||||
//
|
||||
// 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 LLC 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: Snehasish Kumar <snehasishk@google.com>
|
||||
|
||||
// dwarf2reader_splitfunctions_unittest.cc: Unit tests for with a focus on debug
|
||||
// information generated when with splitting optimizations such as
|
||||
// -fsplit-machine-functions (clang) -freorder-blocks-and-partition (gcc).
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/dwarf/bytereader.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
||||
using testing::_;
|
||||
using namespace google_breakpad;
|
||||
|
||||
namespace {
|
||||
|
||||
class MockLineInfoHandler: public LineInfoHandler {
|
||||
public:
|
||||
MOCK_METHOD(void, DefineFile, (const string& name, int32_t file_num,
|
||||
uint32_t dir_num, uint64_t mod_time,
|
||||
uint64_t length), (override));
|
||||
MOCK_METHOD(void, AddLine, (uint64_t address, uint64_t length,
|
||||
uint32_t file_num, uint32_t line_num,
|
||||
uint32_t column_num), (override));
|
||||
};
|
||||
|
||||
struct LineProgram: public testing::Test {
|
||||
MockLineInfoHandler handler_;
|
||||
};
|
||||
|
||||
// The debug information is generated from the following program --
|
||||
// $ cat -n split_functions.c
|
||||
// 1 #include <stdio.h>
|
||||
// 2
|
||||
// 3 __attribute__((noinline)) int foo(int i) {
|
||||
// 4 if (i % 100) {
|
||||
// 5 return i + 1;
|
||||
// 6 } else {
|
||||
// 7 return i * 10 % 3;
|
||||
// 8 }
|
||||
// 9 }
|
||||
// 10
|
||||
// 11
|
||||
// 12 int main(int argc, char *argv[]) {
|
||||
// 13 int total = 0;
|
||||
// 14 for (int i = 0; i < 1000; ++i) {
|
||||
// 15 total += foo(i);
|
||||
// 16 }
|
||||
// 17 printf("%d\n", total);
|
||||
// 18 }
|
||||
//
|
||||
// $ bin/clang -fprofile-generate -O2 split_functions.c
|
||||
// $ ./a.out > /dev/null
|
||||
// $ bin/llvm-profdata merge -o default.profdata default_*.profraw
|
||||
// $ bin/clang -fprofile-use -O2 -gmlt -gdwarf-5 -fsplit-machine-functions \
|
||||
// split_functions.c -o split.out
|
||||
//
|
||||
// For the test we pick the first instruction in foo.cold which should be the
|
||||
// else part of the function foo above.
|
||||
|
||||
const uint8_t debug_line[] = {
|
||||
0xb0,0x0,0x0,0x0,0x5,0x0,0x8,0x0,0x37,0x0,0x0,0x0,0x1,0x1,0x1,0xfb,0xe,0xd,0x0,0x1,0x1,0x1,0x1,0x0,0x0,0x0,0x1,0x0,0x0,0x1,0x1,0x1,0x1f,0x1,0x0,0x0,0x0,0x0,0x3,0x1,0x1f,0x2,0xf,0x5,0x1e,0x1,0x3d,0x0,0x0,0x0,0x0,0x24,0xb2,0xb6,0xb5,0xbb,0xf,0xf7,0x6d,0x27,0x92,0xab,0x55,0x3a,0x29,0x48,0x81,0x4,0x0,0x0,0x9,0x2,0x40,0x10,0x40,0x0,0x0,0x0,0x0,0x0,0x14,0x5,0x9,0xa,0x2f,0x5,0x7,0x6,0x8,0x4a,0x5,0xe,0x6,0x67,0x5,0x1,0x40,0x5,0x0,0xf5,0x5,0xe,0xa,0xf5,0x5,0xb,0x6,0x74,0x5,0x1d,0x6,0x2d,0x5,0x15,0x6,0x3c,0x5,0x3,0x66,0x2,0x7,0x0,0x1,0x1,0x4,0x0,0x5,0xe,0x0,0x9,0x2,0x84,0x11,0x40,0x0,0x0,0x0,0x0,0x0,0x18,0x5,0x13,0x6,0x58,0x5,0x1,0x6,0x8,0xa0,0x2,0x1,0x0,0x1,0x1,0x4,0x0,0x5,0x3,0x0,0x9,0x2,0xa5,0x11,0x40,0x0,0x0,0x0,0x0,0x0,0x3,0x10,0x1,0x5,0x1,0xd7,0x2,0x9,0x0,0x1,0x1
|
||||
};
|
||||
|
||||
const uint8_t debug_str[] = {
|
||||
0x63,0x6c,0x61,0x6e,0x67,0x20,0x76,0x65,0x72,0x73,0x69,0x6f,0x6e,0x20,0x31,0x32,0x2e,0x30,0x2e,0x30,0x20,0x28,0x67,0x69,0x74,0x40,0x67,0x69,0x74,0x68,0x75,0x62,0x2e,0x63,0x6f,0x6d,0x3a,0x6c,0x6c,0x76,0x6d,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2e,0x67,0x69,0x74,0x20,0x63,0x37,0x35,0x61,0x30,0x61,0x31,0x65,0x39,0x64,0x63,0x32,0x39,0x62,0x65,0x34,0x65,0x30,0x30,0x64,0x33,0x37,0x64,0x30,0x64,0x30,0x30,0x32,0x38,0x38,0x61,0x66,0x63,0x31,0x61,0x36,0x31,0x35,0x33,0x66,0x29,0x0,0x73,0x70,0x6c,0x69,0x74,0x5f,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x63,0x0,0x2f,0x75,0x73,0x72,0x2f,0x6c,0x6f,0x63,0x61,0x6c,0x2f,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x73,0x6e,0x65,0x68,0x61,0x73,0x69,0x73,0x68,0x6b,0x2f,0x77,0x6f,0x72,0x6b,0x69,0x6e,0x67,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2f,0x62,0x75,0x69,0x6c,0x64,0x0,0x66,0x6f,0x6f,0x0,0x69,0x6e,0x74,0x0,0x6d,0x61,0x69,0x6e,0x0,0x69,0x0,0x61,0x72,0x67,0x63,0x0,0x61,0x72,0x67,0x76,0x0,0x63,0x68,0x61,0x72,0x0,0x74,0x6f,0x74,0x61,0x6c,0x0
|
||||
};
|
||||
|
||||
const uint8_t debug_line_str[] = {
|
||||
0x2f,0x75,0x73,0x72,0x2f,0x6c,0x6f,0x63,0x61,0x6c,0x2f,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x2f,0x68,0x6f,0x6d,0x65,0x2f,0x73,0x6e,0x65,0x68,0x61,0x73,0x69,0x73,0x68,0x6b,0x2f,0x77,0x6f,0x72,0x6b,0x69,0x6e,0x67,0x2f,0x6c,0x6c,0x76,0x6d,0x2d,0x70,0x72,0x6f,0x6a,0x65,0x63,0x74,0x2f,0x62,0x75,0x69,0x6c,0x64,0x0,0x73,0x70,0x6c,0x69,0x74,0x5f,0x66,0x75,0x6e,0x63,0x74,0x69,0x6f,0x6e,0x73,0x2e,0x63,0x0
|
||||
};
|
||||
|
||||
TEST_F(LineProgram, ReadLinesSplitFunctions) {
|
||||
ByteReader byte_reader(ENDIANNESS_LITTLE);
|
||||
// LineTables don't specify the offset size like Compilation Units do.
|
||||
byte_reader.SetOffsetSize(4);
|
||||
LineInfo line_reader(debug_line,
|
||||
sizeof(debug_line),
|
||||
&byte_reader,
|
||||
debug_str,
|
||||
sizeof(debug_str),
|
||||
debug_line_str,
|
||||
sizeof(debug_line_str),
|
||||
&handler_);
|
||||
EXPECT_CALL(handler_, DefineFile("split_functions.c", 0, 0, 0, 0)).Times(1);
|
||||
EXPECT_CALL(handler_, AddLine(_, _, _, _, _)).Times(testing::AtLeast(1));
|
||||
// Pick the first address from the foo.cold symbol and check the line number.
|
||||
EXPECT_CALL(handler_, AddLine(testing::Eq(0x401184lu), _, _, /*line_num*/ 7, _)).Times(1);
|
||||
EXPECT_EQ(line_reader.Start(), sizeof(debug_line));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
163
externals/breakpad/src/common/dwarf/dwarf2reader_test_common.h
vendored
Normal file
163
externals/breakpad/src/common/dwarf/dwarf2reader_test_common.h
vendored
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dwarf2reader_test_common.h: Define TestCompilationUnit and
|
||||
// TestAbbrevTable, classes for creating properly (and improperly)
|
||||
// formatted DWARF compilation unit data for unit tests.
|
||||
|
||||
#ifndef COMMON_DWARF_DWARF2READER_TEST_COMMON_H__
|
||||
#define COMMON_DWARF_DWARF2READER_TEST_COMMON_H__
|
||||
|
||||
#include "common/test_assembler.h"
|
||||
#include "common/dwarf/dwarf2enums.h"
|
||||
|
||||
// A subclass of test_assembler::Section, specialized for constructing
|
||||
// DWARF compilation units.
|
||||
class TestCompilationUnit: public google_breakpad::test_assembler::Section {
|
||||
public:
|
||||
typedef google_breakpad::DwarfTag DwarfTag;
|
||||
typedef google_breakpad::DwarfAttribute DwarfAttribute;
|
||||
typedef google_breakpad::DwarfForm DwarfForm;
|
||||
typedef google_breakpad::test_assembler::Label Label;
|
||||
|
||||
// Set the section's DWARF format size (the 32-bit DWARF format or the
|
||||
// 64-bit DWARF format, for lengths and section offsets --- not the
|
||||
// address size) to format_size.
|
||||
void set_format_size(size_t format_size) {
|
||||
assert(format_size == 4 || format_size == 8);
|
||||
format_size_ = format_size;
|
||||
}
|
||||
|
||||
// Append a DWARF section offset value, of the appropriate size for this
|
||||
// compilation unit.
|
||||
template<typename T>
|
||||
void SectionOffset(T offset) {
|
||||
if (format_size_ == 4)
|
||||
D32(offset);
|
||||
else
|
||||
D64(offset);
|
||||
}
|
||||
|
||||
// Append a DWARF compilation unit header to the section, with the given
|
||||
// DWARF version, abbrev table offset, and address size.
|
||||
TestCompilationUnit& Header(int version, const Label& abbrev_offset,
|
||||
size_t address_size, int header_type) {
|
||||
if (format_size_ == 4) {
|
||||
D32(length_);
|
||||
} else {
|
||||
D32(0xffffffff);
|
||||
D64(length_);
|
||||
}
|
||||
post_length_offset_ = Size();
|
||||
D16(version);
|
||||
if (version <= 4) {
|
||||
SectionOffset(abbrev_offset);
|
||||
D8(address_size);
|
||||
} else {
|
||||
D8(header_type); // DW_UT_compile, DW_UT_type, etc.
|
||||
D8(address_size);
|
||||
SectionOffset(abbrev_offset);
|
||||
if (header_type == google_breakpad::DW_UT_type) {
|
||||
uint64_t dummy_type_signature = 0xdeadbeef;
|
||||
uint64_t dummy_type_offset = 0x2b;
|
||||
D64(dummy_type_signature);
|
||||
if (format_size_ == 4)
|
||||
D32(dummy_type_offset);
|
||||
else
|
||||
D64(dummy_type_offset);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Mark the end of this header's DIEs.
|
||||
TestCompilationUnit& Finish() {
|
||||
length_ = Size() - post_length_offset_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// The DWARF format size for this compilation unit.
|
||||
size_t format_size_;
|
||||
|
||||
// The offset of the point in the compilation unit header immediately
|
||||
// after the initial length field.
|
||||
uint64_t post_length_offset_;
|
||||
|
||||
// The length of the compilation unit, not including the initial length field.
|
||||
Label length_;
|
||||
};
|
||||
|
||||
// A subclass of test_assembler::Section specialized for constructing DWARF
|
||||
// abbreviation tables.
|
||||
class TestAbbrevTable: public google_breakpad::test_assembler::Section {
|
||||
public:
|
||||
typedef google_breakpad::DwarfTag DwarfTag;
|
||||
typedef google_breakpad::DwarfAttribute DwarfAttribute;
|
||||
typedef google_breakpad::DwarfForm DwarfForm;
|
||||
typedef google_breakpad::DwarfHasChild DwarfHasChild;
|
||||
typedef google_breakpad::test_assembler::Label Label;
|
||||
|
||||
// Start a new abbreviation table entry for abbreviation code |code|,
|
||||
// encoding a DIE whose tag is |tag|, and which has children if and only
|
||||
// if |has_children| is true.
|
||||
TestAbbrevTable& Abbrev(int code, DwarfTag tag, DwarfHasChild has_children) {
|
||||
assert(code != 0);
|
||||
ULEB128(code);
|
||||
ULEB128(static_cast<unsigned>(tag));
|
||||
D8(static_cast<unsigned>(has_children));
|
||||
return *this;
|
||||
};
|
||||
|
||||
// Add an attribute to the current abbreviation code whose name is |name|
|
||||
// and whose form is |form|.
|
||||
TestAbbrevTable& Attribute(DwarfAttribute name, DwarfForm form) {
|
||||
ULEB128(static_cast<unsigned>(name));
|
||||
ULEB128(static_cast<unsigned>(form));
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Finish the current abbreviation code.
|
||||
TestAbbrevTable& EndAbbrev() {
|
||||
ULEB128(0);
|
||||
ULEB128(0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Finish the current abbreviation table.
|
||||
TestAbbrevTable& EndTable() {
|
||||
ULEB128(0);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // COMMON_DWARF_DWARF2READER_TEST_COMMON_H__
|
||||
1302
externals/breakpad/src/common/dwarf/elf_reader.cc
vendored
Normal file
1302
externals/breakpad/src/common/dwarf/elf_reader.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
169
externals/breakpad/src/common/dwarf/elf_reader.h
vendored
Normal file
169
externals/breakpad/src/common/dwarf/elf_reader.h
vendored
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
// Copyright 2005 Google LLC
|
||||
// Author: chatham@google.com (Andrew Chatham)
|
||||
// Author: satorux@google.com (Satoru Takabayashi)
|
||||
//
|
||||
// ElfReader handles reading in ELF. It can extract symbols from the
|
||||
// current process, which may be used to symbolize stack traces
|
||||
// without having to make a potentially dangerous call to fork().
|
||||
//
|
||||
// ElfReader dynamically allocates memory, so it is not appropriate to
|
||||
// use once the address space might be corrupted, such as during
|
||||
// process death.
|
||||
//
|
||||
// ElfReader supports both 32-bit and 64-bit ELF binaries.
|
||||
|
||||
#ifndef COMMON_DWARF_ELF_READER_H__
|
||||
#define COMMON_DWARF_ELF_READER_H__
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "common/dwarf/types.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using std::vector;
|
||||
using std::pair;
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class SymbolMap;
|
||||
class Elf32;
|
||||
class Elf64;
|
||||
template<typename ElfArch>
|
||||
class ElfReaderImpl;
|
||||
|
||||
class ElfReader {
|
||||
public:
|
||||
explicit ElfReader(const string& path);
|
||||
~ElfReader();
|
||||
|
||||
// Parse the ELF prologue of this file and return whether it was
|
||||
// successfully parsed and matches the word size and byte order of
|
||||
// the current process.
|
||||
bool IsNativeElfFile() const;
|
||||
|
||||
// Similar to IsNativeElfFile but checks if it's a 32-bit ELF file.
|
||||
bool IsElf32File() const;
|
||||
|
||||
// Similar to IsNativeElfFile but checks if it's a 64-bit ELF file.
|
||||
bool IsElf64File() const;
|
||||
|
||||
// Checks if it's an ELF file of type ET_DYN (shared object file).
|
||||
bool IsDynamicSharedObject();
|
||||
|
||||
// Add symbols in the given ELF file into the provided SymbolMap,
|
||||
// assuming that the file has been loaded into the specified
|
||||
// offset.
|
||||
//
|
||||
// The remaining arguments are typically taken from a
|
||||
// ProcMapsIterator (base/sysinfo.h) and describe which portions of
|
||||
// the ELF file are mapped into which parts of memory:
|
||||
//
|
||||
// mem_offset - position at which the segment is mapped into memory
|
||||
// file_offset - offset in the file where the mapping begins
|
||||
// length - length of the mapped segment
|
||||
void AddSymbols(SymbolMap* symbols,
|
||||
uint64_t mem_offset, uint64_t file_offset,
|
||||
uint64_t length);
|
||||
|
||||
class SymbolSink {
|
||||
public:
|
||||
virtual ~SymbolSink() {}
|
||||
virtual void AddSymbol(const char* name, uint64_t address,
|
||||
uint64_t size) = 0;
|
||||
};
|
||||
|
||||
// Like AddSymbols above, but with no address correction.
|
||||
// Processes any SHT_SYMTAB section, followed by any SHT_DYNSYM section.
|
||||
void VisitSymbols(SymbolSink* sink);
|
||||
|
||||
// Like VisitSymbols above, but for a specific symbol binding/type.
|
||||
// A negative value for the binding and type parameters means any
|
||||
// binding or type.
|
||||
void VisitSymbols(SymbolSink* sink, int symbol_binding, int symbol_type);
|
||||
|
||||
// Like VisitSymbols above but can optionally export raw symbol values instead
|
||||
// of adjusted ones.
|
||||
void VisitSymbols(SymbolSink* sink, int symbol_binding, int symbol_type,
|
||||
bool get_raw_symbol_values);
|
||||
|
||||
// p_vaddr of the first PT_LOAD segment (if any), or 0 if no PT_LOAD
|
||||
// segments are present. This is the address an ELF image was linked
|
||||
// (by static linker) to be loaded at. Usually (but not always) 0 for
|
||||
// shared libraries and position-independent executables.
|
||||
uint64_t VaddrOfFirstLoadSegment();
|
||||
|
||||
// Return the name of section "shndx". Returns NULL if the section
|
||||
// is not found.
|
||||
const char* GetSectionName(int shndx);
|
||||
|
||||
// Return the number of sections in the given ELF file.
|
||||
uint64_t GetNumSections();
|
||||
|
||||
// Get section "shndx" from the given ELF file. On success, return
|
||||
// the pointer to the section and store the size in "size".
|
||||
// On error, return NULL. The returned section data is only valid
|
||||
// until the ElfReader gets destroyed.
|
||||
const char* GetSectionByIndex(int shndx, size_t* size);
|
||||
|
||||
// Get section with "section_name" (ex. ".text", ".symtab") in the
|
||||
// given ELF file. On success, return the pointer to the section
|
||||
// and store the size in "size". On error, return NULL. The
|
||||
// returned section data is only valid until the ElfReader gets
|
||||
// destroyed.
|
||||
const char* GetSectionByName(const string& section_name, size_t* size);
|
||||
|
||||
// This is like GetSectionByName() but it returns a lot of extra information
|
||||
// about the section. The SectionInfo structure is almost identical to
|
||||
// the typedef struct Elf64_Shdr defined in <elf.h>, but is redefined
|
||||
// here so that the many short macro names in <elf.h> don't have to be
|
||||
// added to our already cluttered namespace.
|
||||
struct SectionInfo {
|
||||
uint32_t type; // Section type (SHT_xxx constant from elf.h).
|
||||
uint64_t flags; // Section flags (SHF_xxx constants from elf.h).
|
||||
uint64_t addr; // Section virtual address at execution.
|
||||
uint64_t offset; // Section file offset.
|
||||
uint64_t size; // Section size in bytes.
|
||||
uint32_t link; // Link to another section.
|
||||
uint32_t info; // Additional section information.
|
||||
uint64_t addralign; // Section alignment.
|
||||
uint64_t entsize; // Entry size if section holds a table.
|
||||
};
|
||||
const char* GetSectionInfoByName(const string& section_name,
|
||||
SectionInfo* info);
|
||||
|
||||
// Check if "path" is an ELF binary that has not been stripped of symbol
|
||||
// tables. This function supports both 32-bit and 64-bit ELF binaries.
|
||||
static bool IsNonStrippedELFBinary(const string& path);
|
||||
|
||||
// Check if "path" is an ELF binary that has not been stripped of debug
|
||||
// info. Unlike IsNonStrippedELFBinary, this function will return
|
||||
// false for binaries passed through "strip -S".
|
||||
static bool IsNonDebugStrippedELFBinary(const string& path);
|
||||
|
||||
// Match a requested section name with the section name as it
|
||||
// appears in the elf-file, adjusting for compressed debug section
|
||||
// names. For example, returns true if name == ".debug_abbrev" and
|
||||
// sh_name == ".zdebug_abbrev"
|
||||
static bool SectionNamesMatch(std::string_view name,
|
||||
std::string_view sh_name);
|
||||
|
||||
private:
|
||||
// Lazily initialize impl32_ and return it.
|
||||
ElfReaderImpl<Elf32>* GetImpl32();
|
||||
// Ditto for impl64_.
|
||||
ElfReaderImpl<Elf64>* GetImpl64();
|
||||
|
||||
// Path of the file we're reading.
|
||||
const string path_;
|
||||
// Read-only file descriptor for the file. May be -1 if there was an
|
||||
// error during open.
|
||||
int fd_;
|
||||
ElfReaderImpl<Elf32>* impl32_;
|
||||
ElfReaderImpl<Elf64>* impl64_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_DWARF_ELF_READER_H__
|
||||
232
externals/breakpad/src/common/dwarf/functioninfo.cc
vendored
Normal file
232
externals/breakpad/src/common/dwarf/functioninfo.cc
vendored
Normal file
|
|
@ -0,0 +1,232 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// This is a client for the dwarf2reader to extract function and line
|
||||
// information from the debug info.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
#include "common/dwarf/functioninfo.h"
|
||||
#include "common/dwarf/bytereader.h"
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files,
|
||||
std::vector<string>* dirs,
|
||||
LineMap* linemap):linemap_(linemap),
|
||||
files_(files),
|
||||
dirs_(dirs) {
|
||||
// In dwarf4, the dirs and files are 1 indexed, and in dwarf5 they are zero
|
||||
// indexed. This is handled in the LineInfo reader, so empty files are not
|
||||
// needed here.
|
||||
}
|
||||
|
||||
void CULineInfoHandler::DefineDir(const string& name, uint32_t dir_num) {
|
||||
// These should never come out of order, actually
|
||||
assert(dir_num == dirs_->size());
|
||||
dirs_->push_back(name);
|
||||
}
|
||||
|
||||
void CULineInfoHandler::DefineFile(const string& name,
|
||||
int32 file_num, uint32_t dir_num,
|
||||
uint64_t mod_time, uint64_t length) {
|
||||
assert(dir_num >= 0);
|
||||
assert(dir_num < dirs_->size());
|
||||
|
||||
// These should never come out of order, actually.
|
||||
if (file_num == (int32)files_->size() || file_num == -1) {
|
||||
string dir = dirs_->at(dir_num);
|
||||
|
||||
SourceFileInfo s;
|
||||
s.lowpc = ULLONG_MAX;
|
||||
|
||||
if (dir == "") {
|
||||
s.name = name;
|
||||
} else {
|
||||
s.name = dir + "/" + name;
|
||||
}
|
||||
|
||||
files_->push_back(s);
|
||||
} else {
|
||||
fprintf(stderr, "error in DefineFile");
|
||||
}
|
||||
}
|
||||
|
||||
void CULineInfoHandler::AddLine(uint64_t address, uint64_t length,
|
||||
uint32_t file_num, uint32_t line_num,
|
||||
uint32_t column_num) {
|
||||
if (file_num < files_->size()) {
|
||||
linemap_->insert(
|
||||
std::make_pair(address,
|
||||
std::make_pair(files_->at(file_num).name.c_str(),
|
||||
line_num)));
|
||||
|
||||
if (address < files_->at(file_num).lowpc) {
|
||||
files_->at(file_num).lowpc = address;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "error in AddLine");
|
||||
}
|
||||
}
|
||||
|
||||
bool CUFunctionInfoHandler::StartCompilationUnit(uint64_t offset,
|
||||
uint8_t address_size,
|
||||
uint8_t offset_size,
|
||||
uint64_t cu_length,
|
||||
uint8_t dwarf_version) {
|
||||
current_compilation_unit_offset_ = offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// For function info, we only care about subprograms and inlined
|
||||
// subroutines. For line info, the DW_AT_stmt_list lives in the
|
||||
// compile unit tag.
|
||||
|
||||
bool CUFunctionInfoHandler::StartDIE(uint64_t offset, enum DwarfTag tag) {
|
||||
switch (tag) {
|
||||
case DW_TAG_subprogram:
|
||||
case DW_TAG_inlined_subroutine: {
|
||||
current_function_info_ = new FunctionInfo;
|
||||
current_function_info_->lowpc = current_function_info_->highpc = 0;
|
||||
current_function_info_->name = "";
|
||||
current_function_info_->line = 0;
|
||||
current_function_info_->file = "";
|
||||
offset_to_funcinfo_->insert(std::make_pair(offset,
|
||||
current_function_info_));
|
||||
};
|
||||
// FALLTHROUGH
|
||||
case DW_TAG_compile_unit:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only care about the name attribute for functions
|
||||
|
||||
void CUFunctionInfoHandler::ProcessAttributeString(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string& data) {
|
||||
if (current_function_info_) {
|
||||
if (attr == DW_AT_name)
|
||||
current_function_info_->name = data;
|
||||
else if (attr == DW_AT_MIPS_linkage_name)
|
||||
current_function_info_->mangled_name = data;
|
||||
}
|
||||
}
|
||||
|
||||
void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data) {
|
||||
if (attr == DW_AT_stmt_list) {
|
||||
SectionMap::const_iterator iter =
|
||||
GetSectionByName(sections_, ".debug_line");
|
||||
assert(iter != sections_.end());
|
||||
|
||||
scoped_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data,
|
||||
iter->second.second - data,
|
||||
reader_, linehandler_));
|
||||
lireader->Start();
|
||||
} else if (current_function_info_) {
|
||||
switch (attr) {
|
||||
case DW_AT_low_pc:
|
||||
current_function_info_->lowpc = data;
|
||||
break;
|
||||
case DW_AT_high_pc:
|
||||
current_function_info_->highpc = data;
|
||||
break;
|
||||
case DW_AT_decl_line:
|
||||
current_function_info_->line = data;
|
||||
break;
|
||||
case DW_AT_decl_file:
|
||||
current_function_info_->file = files_->at(data).name;
|
||||
break;
|
||||
case DW_AT_ranges:
|
||||
current_function_info_->ranges = data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CUFunctionInfoHandler::ProcessAttributeReference(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data) {
|
||||
if (current_function_info_) {
|
||||
switch (attr) {
|
||||
case DW_AT_specification: {
|
||||
// Some functions have a "specification" attribute
|
||||
// which means they were defined elsewhere. The name
|
||||
// attribute is not repeated, and must be taken from
|
||||
// the specification DIE. Here we'll assume that
|
||||
// any DIE referenced in this manner will already have
|
||||
// been seen, but that's not really required by the spec.
|
||||
FunctionMap::iterator iter = offset_to_funcinfo_->find(data);
|
||||
if (iter != offset_to_funcinfo_->end()) {
|
||||
current_function_info_->name = iter->second->name;
|
||||
current_function_info_->mangled_name = iter->second->mangled_name;
|
||||
} else {
|
||||
// If you hit this, this code probably needs to be rewritten.
|
||||
fprintf(stderr,
|
||||
"Error: DW_AT_specification was seen before the referenced "
|
||||
"DIE! (Looking for DIE at offset %08llx, in DIE at "
|
||||
"offset %08llx)\n", data, offset);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CUFunctionInfoHandler::EndDIE(uint64_t offset) {
|
||||
if (current_function_info_ && current_function_info_->lowpc)
|
||||
address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc,
|
||||
current_function_info_));
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
191
externals/breakpad/src/common/dwarf/functioninfo.h
vendored
Normal file
191
externals/breakpad/src/common/dwarf/functioninfo.h
vendored
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
// This file contains the definitions for a DWARF2/3 information
|
||||
// collector that uses the DWARF2/3 reader interface to build a mapping
|
||||
// of addresses to files, lines, and functions.
|
||||
|
||||
#ifndef COMMON_DWARF_FUNCTIONINFO_H__
|
||||
#define COMMON_DWARF_FUNCTIONINFO_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
struct FunctionInfo {
|
||||
// Name of the function
|
||||
string name;
|
||||
// Mangled name of the function
|
||||
string mangled_name;
|
||||
// File containing this function
|
||||
string file;
|
||||
// Line number for start of function.
|
||||
uint32_t line;
|
||||
// Beginning address for this function
|
||||
uint64_t lowpc;
|
||||
// End address for this function.
|
||||
uint64_t highpc;
|
||||
// Ranges offset
|
||||
uint64_t ranges;
|
||||
};
|
||||
|
||||
struct SourceFileInfo {
|
||||
// Name of the source file name
|
||||
string name;
|
||||
// Low address of source file name
|
||||
uint64_t lowpc;
|
||||
};
|
||||
|
||||
typedef std::map<uint64, FunctionInfo*> FunctionMap;
|
||||
typedef std::map<uint64, std::pair<string, uint32> > LineMap;
|
||||
|
||||
// This class is a basic line info handler that fills in the dirs,
|
||||
// file, and linemap passed into it with the data produced from the
|
||||
// LineInfoHandler.
|
||||
class CULineInfoHandler: public LineInfoHandler {
|
||||
public:
|
||||
|
||||
//
|
||||
CULineInfoHandler(std::vector<SourceFileInfo>* files,
|
||||
std::vector<string>* dirs,
|
||||
LineMap* linemap);
|
||||
virtual ~CULineInfoHandler() { }
|
||||
|
||||
// Called when we define a directory. We just place NAME into dirs_
|
||||
// at position DIR_NUM.
|
||||
virtual void DefineDir(const string& name, uint32_t dir_num);
|
||||
|
||||
// Called when we define a filename. We just place
|
||||
// concat(dirs_[DIR_NUM], NAME) into files_ at position FILE_NUM.
|
||||
virtual void DefineFile(const string& name, int32 file_num,
|
||||
uint32_t dir_num, uint64_t mod_time, uint64_t length);
|
||||
|
||||
|
||||
// Called when the line info reader has a new line, address pair
|
||||
// ready for us. ADDRESS is the address of the code, LENGTH is the
|
||||
// length of its machine code in bytes, FILE_NUM is the file number
|
||||
// containing the code, LINE_NUM is the line number in that file for
|
||||
// the code, and COLUMN_NUM is the column number the code starts at,
|
||||
// if we know it (0 otherwise).
|
||||
virtual void AddLine(uint64_t address, uint64_t length,
|
||||
uint32_t file_num, uint32_t line_num,
|
||||
uint32_t column_num);
|
||||
|
||||
private:
|
||||
LineMap* linemap_;
|
||||
std::vector<SourceFileInfo>* files_;
|
||||
std::vector<string>* dirs_;
|
||||
};
|
||||
|
||||
class CUFunctionInfoHandler: public Dwarf2Handler {
|
||||
public:
|
||||
CUFunctionInfoHandler(std::vector<SourceFileInfo>* files,
|
||||
std::vector<string>* dirs,
|
||||
LineMap* linemap,
|
||||
FunctionMap* offset_to_funcinfo,
|
||||
FunctionMap* address_to_funcinfo,
|
||||
CULineInfoHandler* linehandler,
|
||||
const SectionMap& sections,
|
||||
ByteReader* reader)
|
||||
: files_(files), dirs_(dirs), linemap_(linemap),
|
||||
offset_to_funcinfo_(offset_to_funcinfo),
|
||||
address_to_funcinfo_(address_to_funcinfo),
|
||||
linehandler_(linehandler), sections_(sections),
|
||||
reader_(reader), current_function_info_(NULL) { }
|
||||
|
||||
virtual ~CUFunctionInfoHandler() { }
|
||||
|
||||
// Start to process a compilation unit at OFFSET from the beginning of the
|
||||
// .debug_info section. We want to see all compilation units, so we
|
||||
// always return true.
|
||||
|
||||
virtual bool StartCompilationUnit(uint64_t offset, uint8_t address_size,
|
||||
uint8_t offset_size, uint64_t cu_length,
|
||||
uint8_t dwarf_version);
|
||||
|
||||
// Start to process a DIE at OFFSET from the beginning of the
|
||||
// .debug_info section. We only care about function related DIE's.
|
||||
virtual bool StartDIE(uint64_t offset, enum DwarfTag tag);
|
||||
|
||||
// Called when we have an attribute with unsigned data to give to
|
||||
// our handler. The attribute is for the DIE at OFFSET from the
|
||||
// beginning of the .debug_info section, has a name of ATTR, a form of
|
||||
// FORM, and the actual data of the attribute is in DATA.
|
||||
virtual void ProcessAttributeUnsigned(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data);
|
||||
|
||||
// Called when we have an attribute with a DIE reference to give to
|
||||
// our handler. The attribute is for the DIE at OFFSET from the
|
||||
// beginning of the .debug_info section, has a name of ATTR, a form of
|
||||
// FORM, and the offset of the referenced DIE from the start of the
|
||||
// .debug_info section is in DATA.
|
||||
virtual void ProcessAttributeReference(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data);
|
||||
|
||||
// Called when we have an attribute with string data to give to
|
||||
// our handler. The attribute is for the DIE at OFFSET from the
|
||||
// beginning of the .debug_info section, has a name of ATTR, a form of
|
||||
// FORM, and the actual data of the attribute is in DATA.
|
||||
virtual void ProcessAttributeString(uint64_t offset,
|
||||
enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string& data);
|
||||
|
||||
// Called when finished processing the DIE at OFFSET.
|
||||
// Because DWARF2/3 specifies a tree of DIEs, you may get starts
|
||||
// before ends of the previous DIE, as we process children before
|
||||
// ending the parent.
|
||||
virtual void EndDIE(uint64_t offset);
|
||||
|
||||
private:
|
||||
std::vector<SourceFileInfo>* files_;
|
||||
std::vector<string>* dirs_;
|
||||
LineMap* linemap_;
|
||||
FunctionMap* offset_to_funcinfo_;
|
||||
FunctionMap* address_to_funcinfo_;
|
||||
CULineInfoHandler* linehandler_;
|
||||
const SectionMap& sections_;
|
||||
ByteReader* reader_;
|
||||
FunctionInfo* current_function_info_;
|
||||
uint64_t current_compilation_unit_offset_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
#endif // COMMON_DWARF_FUNCTIONINFO_H__
|
||||
63
externals/breakpad/src/common/dwarf/line_state_machine.h
vendored
Normal file
63
externals/breakpad/src/common/dwarf/line_state_machine.h
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2008 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
#ifndef COMMON_DWARF_LINE_STATE_MACHINE_H__
|
||||
#define COMMON_DWARF_LINE_STATE_MACHINE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// This is the format of a DWARF2/3 line state machine that we process
|
||||
// opcodes using. There is no need for anything outside the lineinfo
|
||||
// processor to know how this works.
|
||||
struct LineStateMachine {
|
||||
void Reset(bool default_is_stmt) {
|
||||
file_num = 1;
|
||||
address = 0;
|
||||
line_num = 1;
|
||||
column_num = 0;
|
||||
is_stmt = default_is_stmt;
|
||||
basic_block = false;
|
||||
end_sequence = false;
|
||||
}
|
||||
|
||||
uint32_t file_num;
|
||||
uint64_t address;
|
||||
uint32_t line_num;
|
||||
uint32_t column_num;
|
||||
bool is_stmt; // stmt means statement.
|
||||
bool basic_block;
|
||||
bool end_sequence;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // COMMON_DWARF_LINE_STATE_MACHINE_H__
|
||||
41
externals/breakpad/src/common/dwarf/types.h
vendored
Normal file
41
externals/breakpad/src/common/dwarf/types.h
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2008 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
// This file contains some typedefs for basic types
|
||||
|
||||
|
||||
#ifndef _COMMON_DWARF_TYPES_H__
|
||||
#define _COMMON_DWARF_TYPES_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef intptr_t intptr;
|
||||
typedef uintptr_t uintptr;
|
||||
|
||||
#endif // _COMMON_DWARF_TYPES_H__
|
||||
324
externals/breakpad/src/common/dwarf_cfi_to_module.cc
vendored
Normal file
324
externals/breakpad/src/common/dwarf_cfi_to_module.cc
vendored
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// Implementation of google_breakpad::DwarfCFIToModule.
|
||||
// See dwarf_cfi_to_module.h for details.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include "common/dwarf_cfi_to_module.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::ostringstream;
|
||||
|
||||
vector<string> DwarfCFIToModule::RegisterNames::MakeVector(
|
||||
const char * const *strings,
|
||||
size_t size) {
|
||||
vector<string> names(strings, strings + size);
|
||||
return names;
|
||||
}
|
||||
|
||||
vector<string> DwarfCFIToModule::RegisterNames::I386() {
|
||||
static const char *const names[] = {
|
||||
"$eax", "$ecx", "$edx", "$ebx", "$esp", "$ebp", "$esi", "$edi",
|
||||
"$eip", "$eflags", "$unused1",
|
||||
"$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
|
||||
"$unused2", "$unused3",
|
||||
"$xmm0", "$xmm1", "$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
|
||||
"$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
|
||||
"$fcw", "$fsw", "$mxcsr",
|
||||
"$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused4", "$unused5",
|
||||
"$tr", "$ldtr"
|
||||
};
|
||||
|
||||
return MakeVector(names, sizeof(names) / sizeof(names[0]));
|
||||
}
|
||||
|
||||
vector<string> DwarfCFIToModule::RegisterNames::X86_64() {
|
||||
static const char *const names[] = {
|
||||
"$rax", "$rdx", "$rcx", "$rbx", "$rsi", "$rdi", "$rbp", "$rsp",
|
||||
"$r8", "$r9", "$r10", "$r11", "$r12", "$r13", "$r14", "$r15",
|
||||
"$rip",
|
||||
"$xmm0","$xmm1","$xmm2", "$xmm3", "$xmm4", "$xmm5", "$xmm6", "$xmm7",
|
||||
"$xmm8","$xmm9","$xmm10","$xmm11","$xmm12","$xmm13","$xmm14","$xmm15",
|
||||
"$st0", "$st1", "$st2", "$st3", "$st4", "$st5", "$st6", "$st7",
|
||||
"$mm0", "$mm1", "$mm2", "$mm3", "$mm4", "$mm5", "$mm6", "$mm7",
|
||||
"$rflags",
|
||||
"$es", "$cs", "$ss", "$ds", "$fs", "$gs", "$unused1", "$unused2",
|
||||
"$fs.base", "$gs.base", "$unused3", "$unused4",
|
||||
"$tr", "$ldtr",
|
||||
"$mxcsr", "$fcw", "$fsw"
|
||||
};
|
||||
|
||||
return MakeVector(names, sizeof(names) / sizeof(names[0]));
|
||||
}
|
||||
|
||||
// Per ARM IHI 0040A, section 3.1
|
||||
vector<string> DwarfCFIToModule::RegisterNames::ARM() {
|
||||
static const char *const names[] = {
|
||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
|
||||
"r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc",
|
||||
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
|
||||
"fps", "cpsr", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "",
|
||||
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
|
||||
"s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
|
||||
"s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
|
||||
"s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
|
||||
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7"
|
||||
};
|
||||
|
||||
return MakeVector(names, sizeof(names) / sizeof(names[0]));
|
||||
}
|
||||
|
||||
// Per ARM IHI 0057A, section 3.1
|
||||
vector<string> DwarfCFIToModule::RegisterNames::ARM64() {
|
||||
static const char *const names[] = {
|
||||
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
||||
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
|
||||
"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
|
||||
"x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp",
|
||||
"", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "",
|
||||
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
|
||||
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
|
||||
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
|
||||
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
|
||||
};
|
||||
|
||||
return MakeVector(names, sizeof(names) / sizeof(names[0]));
|
||||
}
|
||||
|
||||
vector<string> DwarfCFIToModule::RegisterNames::MIPS() {
|
||||
static const char* const kRegisterNames[] = {
|
||||
"$zero", "$at", "$v0", "$v1", "$a0", "$a1", "$a2", "$a3",
|
||||
"$t0", "$t1", "$t2", "$t3", "$t4", "$t5", "$t6", "$t7",
|
||||
"$s0", "$s1", "$s2", "$s3", "$s4", "$s5", "$s6", "$s7",
|
||||
"$t8", "$t9", "$k0", "$k1", "$gp", "$sp", "$fp", "$ra",
|
||||
"$lo", "$hi", "$pc", "$f0", "$f2", "$f3", "$f4", "$f5",
|
||||
"$f6", "$f7", "$f8", "$f9", "$f10", "$f11", "$f12", "$f13",
|
||||
"$f14", "$f15", "$f16", "$f17", "$f18", "$f19", "$f20",
|
||||
"$f21", "$f22", "$f23", "$f24", "$f25", "$f26", "$f27",
|
||||
"$f28", "$f29", "$f30", "$f31", "$fcsr", "$fir"
|
||||
};
|
||||
|
||||
return MakeVector(kRegisterNames,
|
||||
sizeof(kRegisterNames) / sizeof(kRegisterNames[0]));
|
||||
}
|
||||
|
||||
vector<string> DwarfCFIToModule::RegisterNames::RISCV() {
|
||||
static const char *const names[] = {
|
||||
"pc", "ra", "sp", "gp", "tp", "t0", "t1", "t2",
|
||||
"s0", "s1", "a0", "a1", "a2", "a3", "a4", "a5",
|
||||
"a6", "a7", "s2", "s3", "s4", "s5", "s6", "s7",
|
||||
"s8", "s9", "s10", "s11", "t3", "t4", "t5", "t6",
|
||||
"f0", "f1", "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",
|
||||
"", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "",
|
||||
"", "", "", "", "", "", "", "",
|
||||
"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
|
||||
"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",
|
||||
"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
|
||||
"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31"
|
||||
};
|
||||
|
||||
return MakeVector(names, sizeof(names) / sizeof(names[0]));
|
||||
}
|
||||
|
||||
bool DwarfCFIToModule::Entry(size_t offset, uint64_t address, uint64_t length,
|
||||
uint8_t version, const string& augmentation,
|
||||
unsigned return_address) {
|
||||
assert(!entry_);
|
||||
|
||||
// If CallFrameInfo can handle this version and
|
||||
// augmentation, then we should be okay with that, so there's no
|
||||
// need to check them here.
|
||||
|
||||
// Get ready to collect entries.
|
||||
entry_ = std::make_unique<Module::StackFrameEntry>();
|
||||
entry_->address = address;
|
||||
entry_->size = length;
|
||||
entry_offset_ = offset;
|
||||
return_address_ = return_address;
|
||||
|
||||
// Breakpad STACK CFI records must provide a .ra rule, but DWARF CFI
|
||||
// may not establish any rule for .ra if the return address column
|
||||
// is an ordinary register, and that register holds the return
|
||||
// address on entry to the function. So establish an initial .ra
|
||||
// rule citing the return address register.
|
||||
if (return_address_ < register_names_.size())
|
||||
entry_->initial_rules[ra_name_] = register_names_[return_address_];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string DwarfCFIToModule::RegisterName(int i) {
|
||||
assert(entry_);
|
||||
if (i < 0) {
|
||||
assert(i == kCFARegister);
|
||||
return cfa_name_;
|
||||
}
|
||||
unsigned reg = i;
|
||||
if (reg == return_address_)
|
||||
return ra_name_;
|
||||
|
||||
// Ensure that a non-empty name exists for this register value.
|
||||
if (reg < register_names_.size() && !register_names_[reg].empty())
|
||||
return register_names_[reg];
|
||||
|
||||
reporter_->UnnamedRegister(entry_offset_, reg);
|
||||
return string("unnamed_register") + std::to_string(reg);
|
||||
}
|
||||
|
||||
void DwarfCFIToModule::Record(Module::Address address, int reg,
|
||||
const string& rule) {
|
||||
assert(entry_);
|
||||
|
||||
// Place the name in our global set of strings, and then use the string
|
||||
// from the set. Even though the assignment looks like a copy, all the
|
||||
// major string implementations use reference counting internally,
|
||||
// so the effect is to have all our data structures share copies of rules
|
||||
// whenever possible. Since register names are drawn from a
|
||||
// vector<string>, register names are already shared.
|
||||
string shared_rule = *common_strings_.insert(rule).first;
|
||||
|
||||
// Is this one of this entry's initial rules?
|
||||
if (address == entry_->address)
|
||||
entry_->initial_rules[RegisterName(reg)] = shared_rule;
|
||||
// File it under the appropriate address.
|
||||
else
|
||||
entry_->rule_changes[address][RegisterName(reg)] = shared_rule;
|
||||
}
|
||||
|
||||
bool DwarfCFIToModule::UndefinedRule(uint64_t address, int reg) {
|
||||
reporter_->UndefinedNotSupported(entry_offset_, RegisterName(reg));
|
||||
// Treat this as a non-fatal error.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DwarfCFIToModule::SameValueRule(uint64_t address, int reg) {
|
||||
ostringstream s;
|
||||
s << RegisterName(reg);
|
||||
Record(address, reg, s.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DwarfCFIToModule::OffsetRule(uint64_t address, int reg,
|
||||
int base_register, long offset) {
|
||||
ostringstream s;
|
||||
s << RegisterName(base_register) << " " << offset << " + ^";
|
||||
Record(address, reg, s.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DwarfCFIToModule::ValOffsetRule(uint64_t address, int reg,
|
||||
int base_register, long offset) {
|
||||
ostringstream s;
|
||||
s << RegisterName(base_register) << " " << offset << " +";
|
||||
Record(address, reg, s.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DwarfCFIToModule::RegisterRule(uint64_t address, int reg,
|
||||
int base_register) {
|
||||
ostringstream s;
|
||||
s << RegisterName(base_register);
|
||||
Record(address, reg, s.str());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DwarfCFIToModule::ExpressionRule(uint64_t address, int reg,
|
||||
const string& expression) {
|
||||
reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
|
||||
// Treat this as a non-fatal error.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DwarfCFIToModule::ValExpressionRule(uint64_t address, int reg,
|
||||
const string& expression) {
|
||||
reporter_->ExpressionsNotSupported(entry_offset_, RegisterName(reg));
|
||||
// Treat this as a non-fatal error.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DwarfCFIToModule::End() {
|
||||
module_->AddStackFrameEntry(std::move(entry_));
|
||||
return true;
|
||||
}
|
||||
|
||||
string DwarfCFIToModule::Architecture() {
|
||||
return module_->architecture();
|
||||
}
|
||||
|
||||
void DwarfCFIToModule::Reporter::UnnamedRegister(size_t offset, int reg) {
|
||||
fprintf(stderr, "%s, section '%s': "
|
||||
"the call frame entry at offset 0x%zx refers to register %d,"
|
||||
" whose name we don't know\n",
|
||||
file_.c_str(), section_.c_str(), offset, reg);
|
||||
}
|
||||
|
||||
void DwarfCFIToModule::Reporter::UndefinedNotSupported(size_t offset,
|
||||
const string& reg) {
|
||||
fprintf(stderr, "%s, section '%s': "
|
||||
"the call frame entry at offset 0x%zx sets the rule for "
|
||||
"register '%s' to 'undefined', but the Breakpad symbol file format"
|
||||
" cannot express this\n",
|
||||
file_.c_str(), section_.c_str(), offset, reg.c_str());
|
||||
}
|
||||
|
||||
void DwarfCFIToModule::Reporter::ExpressionsNotSupported(size_t offset,
|
||||
const string& reg) {
|
||||
fprintf(stderr, "%s, section '%s': "
|
||||
"the call frame entry at offset 0x%zx uses a DWARF expression to"
|
||||
" describe how to recover register '%s', "
|
||||
" but this translator cannot yet translate DWARF expressions to"
|
||||
" Breakpad postfix expressions\n",
|
||||
file_.c_str(), section_.c_str(), offset, reg.c_str());
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
206
externals/breakpad/src/common/dwarf_cfi_to_module.h
vendored
Normal file
206
externals/breakpad/src/common/dwarf_cfi_to_module.h
vendored
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dwarf_cfi_to_module.h: Define the DwarfCFIToModule class, which
|
||||
// accepts parsed DWARF call frame info and adds it to a
|
||||
// google_breakpad::Module object, which can write that information to
|
||||
// a Breakpad symbol file.
|
||||
|
||||
#ifndef COMMON_LINUX_DWARF_CFI_TO_MODULE_H
|
||||
#define COMMON_LINUX_DWARF_CFI_TO_MODULE_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "common/module.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using google_breakpad::Module;
|
||||
using std::set;
|
||||
using std::vector;
|
||||
|
||||
// A class that accepts parsed call frame information from the DWARF
|
||||
// CFI parser and populates a google_breakpad::Module object with the
|
||||
// contents.
|
||||
class DwarfCFIToModule: public CallFrameInfo::Handler {
|
||||
public:
|
||||
|
||||
// DwarfCFIToModule uses an instance of this class to report errors
|
||||
// detected while converting DWARF CFI to Breakpad STACK CFI records.
|
||||
class Reporter {
|
||||
public:
|
||||
// Create a reporter that writes messages to the standard error
|
||||
// stream. FILE is the name of the file we're processing, and
|
||||
// SECTION is the name of the section within that file that we're
|
||||
// looking at (.debug_frame, .eh_frame, etc.).
|
||||
Reporter(const string& file, const string& section)
|
||||
: file_(file), section_(section) { }
|
||||
virtual ~Reporter() { }
|
||||
|
||||
// The DWARF CFI entry at OFFSET cites register REG, but REG is not
|
||||
// covered by the vector of register names passed to the
|
||||
// DwarfCFIToModule constructor, nor does it match the return
|
||||
// address column number for this entry.
|
||||
virtual void UnnamedRegister(size_t offset, int reg);
|
||||
|
||||
// The DWARF CFI entry at OFFSET says that REG is undefined, but the
|
||||
// Breakpad symbol file format cannot express this.
|
||||
virtual void UndefinedNotSupported(size_t offset, const string& reg);
|
||||
|
||||
// The DWARF CFI entry at OFFSET says that REG uses a DWARF
|
||||
// expression to find its value, but DwarfCFIToModule is not
|
||||
// capable of translating DWARF expressions to Breakpad postfix
|
||||
// expressions.
|
||||
virtual void ExpressionsNotSupported(size_t offset, const string& reg);
|
||||
|
||||
protected:
|
||||
string file_, section_;
|
||||
};
|
||||
|
||||
// Register name tables. If TABLE is a vector returned by one of these
|
||||
// functions, then TABLE[R] is the name of the register numbered R in
|
||||
// DWARF call frame information.
|
||||
class RegisterNames {
|
||||
public:
|
||||
// Intel's "x86" or IA-32.
|
||||
static vector<string> I386();
|
||||
|
||||
// AMD x86_64, AMD64, Intel EM64T, or Intel 64
|
||||
static vector<string> X86_64();
|
||||
|
||||
// ARM.
|
||||
static vector<string> ARM();
|
||||
|
||||
// ARM64, aka AARCH64.
|
||||
static vector<string> ARM64();
|
||||
|
||||
// MIPS.
|
||||
static vector<string> MIPS();
|
||||
|
||||
// RISC-V.
|
||||
static vector<string> RISCV();
|
||||
|
||||
private:
|
||||
// Given STRINGS, an array of C strings with SIZE elements, return an
|
||||
// equivalent vector<string>.
|
||||
static vector<string> MakeVector(const char* const* strings, size_t size);
|
||||
};
|
||||
|
||||
// Create a handler for the CallFrameInfo parser that
|
||||
// records the stack unwinding information it receives in MODULE.
|
||||
//
|
||||
// Use REGISTER_NAMES[I] as the name of register number I; *this
|
||||
// keeps a reference to the vector, so the vector should remain
|
||||
// alive for as long as the DwarfCFIToModule does.
|
||||
//
|
||||
// Use REPORTER for reporting problems encountered in the conversion
|
||||
// process.
|
||||
DwarfCFIToModule(Module* module, const vector<string>& register_names,
|
||||
Reporter* reporter)
|
||||
: module_(module), register_names_(register_names), reporter_(reporter),
|
||||
return_address_(-1), cfa_name_(".cfa"), ra_name_(".ra") {
|
||||
}
|
||||
virtual ~DwarfCFIToModule() = default;
|
||||
|
||||
virtual bool Entry(size_t offset, uint64_t address, uint64_t length,
|
||||
uint8_t version, const string& augmentation,
|
||||
unsigned return_address);
|
||||
virtual bool UndefinedRule(uint64_t address, int reg);
|
||||
virtual bool SameValueRule(uint64_t address, int reg);
|
||||
virtual bool OffsetRule(uint64_t address, int reg,
|
||||
int base_register, long offset);
|
||||
virtual bool ValOffsetRule(uint64_t address, int reg,
|
||||
int base_register, long offset);
|
||||
virtual bool RegisterRule(uint64_t address, int reg, int base_register);
|
||||
virtual bool ExpressionRule(uint64_t address, int reg,
|
||||
const string& expression);
|
||||
virtual bool ValExpressionRule(uint64_t address, int reg,
|
||||
const string& expression);
|
||||
virtual bool End();
|
||||
|
||||
virtual string Architecture();
|
||||
|
||||
private:
|
||||
// Return the name to use for register REG.
|
||||
string RegisterName(int i);
|
||||
|
||||
// Record RULE for register REG at ADDRESS.
|
||||
void Record(Module::Address address, int reg, const string& rule);
|
||||
|
||||
// The module to which we should add entries.
|
||||
Module* module_;
|
||||
|
||||
// Map from register numbers to register names.
|
||||
const vector<string>& register_names_;
|
||||
|
||||
// The reporter to use to report problems.
|
||||
Reporter* reporter_;
|
||||
|
||||
// The current entry we're constructing.
|
||||
std::unique_ptr<Module::StackFrameEntry> entry_;
|
||||
|
||||
// The section offset of the current frame description entry, for
|
||||
// use in error messages.
|
||||
size_t entry_offset_;
|
||||
|
||||
// The return address column for that entry.
|
||||
unsigned return_address_;
|
||||
|
||||
// The names of the return address and canonical frame address. Putting
|
||||
// these here instead of using string literals allows us to share their
|
||||
// texts in reference-counted string implementations (all the
|
||||
// popular ones). Many, many rules cite these strings.
|
||||
string cfa_name_, ra_name_;
|
||||
|
||||
// A set of strings used by this CFI. Before storing a string in one of
|
||||
// our data structures, insert it into this set, and then use the string
|
||||
// from the set.
|
||||
//
|
||||
// Because string uses reference counting internally, simply using
|
||||
// strings from this set, even if passed by value, assigned, or held
|
||||
// directly in structures and containers (map<string, ...>, for example),
|
||||
// causes those strings to share a single instance of each distinct piece
|
||||
// of text.
|
||||
set<string> common_strings_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_DWARF_CFI_TO_MODULE_H
|
||||
321
externals/breakpad/src/common/dwarf_cfi_to_module_unittest.cc
vendored
Normal file
321
externals/breakpad/src/common/dwarf_cfi_to_module_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dwarf_cfi_to_module_unittest.cc: Tests for google_breakpad::DwarfCFIToModule.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/dwarf_cfi_to_module.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using std::vector;
|
||||
|
||||
using google_breakpad::Module;
|
||||
using google_breakpad::DwarfCFIToModule;
|
||||
using testing::ContainerEq;
|
||||
using testing::Test;
|
||||
using testing::_;
|
||||
|
||||
struct MockCFIReporter: public DwarfCFIToModule::Reporter {
|
||||
MockCFIReporter(const string& file, const string& section)
|
||||
: Reporter(file, section) { }
|
||||
MOCK_METHOD2(UnnamedRegister, void(size_t offset, int reg));
|
||||
MOCK_METHOD2(UndefinedNotSupported, void(size_t offset, const string& reg));
|
||||
MOCK_METHOD2(ExpressionsNotSupported, void(size_t offset, const string& reg));
|
||||
};
|
||||
|
||||
struct DwarfCFIToModuleFixture {
|
||||
DwarfCFIToModuleFixture()
|
||||
: module("module name", "module os", "module arch", "module id"),
|
||||
reporter("reporter file", "reporter section"),
|
||||
handler(&module, register_names, &reporter) {
|
||||
register_names.push_back("reg0");
|
||||
register_names.push_back("reg1");
|
||||
register_names.push_back("reg2");
|
||||
register_names.push_back("reg3");
|
||||
register_names.push_back("reg4");
|
||||
register_names.push_back("reg5");
|
||||
register_names.push_back("reg6");
|
||||
register_names.push_back("reg7");
|
||||
register_names.push_back("sp");
|
||||
register_names.push_back("pc");
|
||||
register_names.push_back("");
|
||||
|
||||
EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0);
|
||||
EXPECT_CALL(reporter, UndefinedNotSupported(_, _)).Times(0);
|
||||
EXPECT_CALL(reporter, ExpressionsNotSupported(_, _)).Times(0);
|
||||
}
|
||||
|
||||
Module module;
|
||||
vector<string> register_names;
|
||||
MockCFIReporter reporter;
|
||||
DwarfCFIToModule handler;
|
||||
vector<Module::StackFrameEntry*> entries;
|
||||
};
|
||||
|
||||
class Entry: public DwarfCFIToModuleFixture, public Test { };
|
||||
|
||||
TEST_F(Entry, Accept) {
|
||||
ASSERT_TRUE(handler.Entry(0x3b8961b8, 0xa21069698096fc98ULL,
|
||||
0xb440ce248169c8d6ULL, 3, "", 0xea93c106));
|
||||
ASSERT_TRUE(handler.End());
|
||||
module.GetStackFrameEntries(&entries);
|
||||
EXPECT_EQ(1U, entries.size());
|
||||
EXPECT_EQ(0xa21069698096fc98ULL, entries[0]->address);
|
||||
EXPECT_EQ(0xb440ce248169c8d6ULL, entries[0]->size);
|
||||
EXPECT_EQ(0U, entries[0]->initial_rules.size());
|
||||
EXPECT_EQ(0U, entries[0]->rule_changes.size());
|
||||
}
|
||||
|
||||
TEST_F(Entry, AcceptOldVersion) {
|
||||
ASSERT_TRUE(handler.Entry(0xeb60e0fc, 0x75b8806bb09eab78ULL,
|
||||
0xc771f44958d40bbcULL, 1, "", 0x093c945e));
|
||||
ASSERT_TRUE(handler.End());
|
||||
module.GetStackFrameEntries(&entries);
|
||||
EXPECT_EQ(1U, entries.size());
|
||||
EXPECT_EQ(0x75b8806bb09eab78ULL, entries[0]->address);
|
||||
EXPECT_EQ(0xc771f44958d40bbcULL, entries[0]->size);
|
||||
EXPECT_EQ(0U, entries[0]->initial_rules.size());
|
||||
EXPECT_EQ(0U, entries[0]->rule_changes.size());
|
||||
}
|
||||
|
||||
struct RuleFixture: public DwarfCFIToModuleFixture {
|
||||
RuleFixture() : DwarfCFIToModuleFixture() {
|
||||
entry_address = 0x89327ebf86b47492ULL;
|
||||
entry_size = 0x2f8cd573072fe02aULL;
|
||||
return_reg = 0x7886a346;
|
||||
}
|
||||
void StartEntry() {
|
||||
ASSERT_TRUE(handler.Entry(0x4445c05c, entry_address, entry_size,
|
||||
3, "", return_reg));
|
||||
}
|
||||
void CheckEntry() {
|
||||
module.GetStackFrameEntries(&entries);
|
||||
EXPECT_EQ(1U, entries.size());
|
||||
EXPECT_EQ(entry_address, entries[0]->address);
|
||||
EXPECT_EQ(entry_size, entries[0]->size);
|
||||
}
|
||||
uint64_t entry_address, entry_size;
|
||||
unsigned return_reg;
|
||||
};
|
||||
|
||||
class Rule: public RuleFixture, public Test { };
|
||||
|
||||
TEST_F(Rule, UndefinedRule) {
|
||||
EXPECT_CALL(reporter, UndefinedNotSupported(_, "reg7"));
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.UndefinedRule(entry_address, 7));
|
||||
ASSERT_TRUE(handler.End());
|
||||
CheckEntry();
|
||||
EXPECT_EQ(0U, entries[0]->initial_rules.size());
|
||||
EXPECT_EQ(0U, entries[0]->rule_changes.size());
|
||||
}
|
||||
|
||||
TEST_F(Rule, RegisterWithEmptyName) {
|
||||
EXPECT_CALL(reporter, UnnamedRegister(_, 10));
|
||||
EXPECT_CALL(reporter, UndefinedNotSupported(_, "unnamed_register10"));
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.UndefinedRule(entry_address, 10));
|
||||
ASSERT_TRUE(handler.End());
|
||||
CheckEntry();
|
||||
EXPECT_EQ(0U, entries[0]->initial_rules.size());
|
||||
EXPECT_EQ(0U, entries[0]->rule_changes.size());
|
||||
}
|
||||
|
||||
TEST_F(Rule, SameValueRule) {
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.SameValueRule(entry_address, 6));
|
||||
ASSERT_TRUE(handler.End());
|
||||
CheckEntry();
|
||||
Module::RuleMap expected_initial;
|
||||
expected_initial["reg6"] = "reg6";
|
||||
EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
|
||||
EXPECT_EQ(0U, entries[0]->rule_changes.size());
|
||||
}
|
||||
|
||||
TEST_F(Rule, OffsetRule) {
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.OffsetRule(entry_address + 1, return_reg,
|
||||
DwarfCFIToModule::kCFARegister,
|
||||
16927065));
|
||||
ASSERT_TRUE(handler.End());
|
||||
CheckEntry();
|
||||
EXPECT_EQ(0U, entries[0]->initial_rules.size());
|
||||
Module::RuleChangeMap expected_changes;
|
||||
expected_changes[entry_address + 1][".ra"] = ".cfa 16927065 + ^";
|
||||
EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
|
||||
}
|
||||
|
||||
TEST_F(Rule, OffsetRuleNegative) {
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.OffsetRule(entry_address + 1,
|
||||
DwarfCFIToModule::kCFARegister, 4, -34530721));
|
||||
ASSERT_TRUE(handler.End());
|
||||
CheckEntry();
|
||||
EXPECT_EQ(0U, entries[0]->initial_rules.size());
|
||||
Module::RuleChangeMap expected_changes;
|
||||
expected_changes[entry_address + 1][".cfa"] = "reg4 -34530721 + ^";
|
||||
EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
|
||||
}
|
||||
|
||||
TEST_F(Rule, ValOffsetRule) {
|
||||
// Use an unnamed register number, to exercise that branch of RegisterName.
|
||||
EXPECT_CALL(reporter, UnnamedRegister(_, 11));
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.ValOffsetRule(entry_address + 0x5ab7,
|
||||
DwarfCFIToModule::kCFARegister,
|
||||
11, 61812979));
|
||||
ASSERT_TRUE(handler.End());
|
||||
CheckEntry();
|
||||
EXPECT_EQ(0U, entries[0]->initial_rules.size());
|
||||
Module::RuleChangeMap expected_changes;
|
||||
expected_changes[entry_address + 0x5ab7][".cfa"] =
|
||||
"unnamed_register11 61812979 +";
|
||||
EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
|
||||
}
|
||||
|
||||
TEST_F(Rule, RegisterRule) {
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 3));
|
||||
ASSERT_TRUE(handler.End());
|
||||
CheckEntry();
|
||||
Module::RuleMap expected_initial;
|
||||
expected_initial[".ra"] = "reg3";
|
||||
EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
|
||||
EXPECT_EQ(0U, entries[0]->rule_changes.size());
|
||||
}
|
||||
|
||||
TEST_F(Rule, ExpressionRule) {
|
||||
EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg2"));
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2,
|
||||
"it takes two to tango"));
|
||||
ASSERT_TRUE(handler.End());
|
||||
CheckEntry();
|
||||
EXPECT_EQ(0U, entries[0]->initial_rules.size());
|
||||
EXPECT_EQ(0U, entries[0]->rule_changes.size());
|
||||
}
|
||||
|
||||
TEST_F(Rule, ValExpressionRule) {
|
||||
EXPECT_CALL(reporter, ExpressionsNotSupported(_, "reg0"));
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0,
|
||||
"bit off more than he could chew"));
|
||||
ASSERT_TRUE(handler.End());
|
||||
CheckEntry();
|
||||
EXPECT_EQ(0U, entries[0]->initial_rules.size());
|
||||
EXPECT_EQ(0U, entries[0]->rule_changes.size());
|
||||
}
|
||||
|
||||
TEST_F(Rule, DefaultReturnAddressRule) {
|
||||
return_reg = 2;
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.RegisterRule(entry_address, 0, 1));
|
||||
ASSERT_TRUE(handler.End());
|
||||
CheckEntry();
|
||||
Module::RuleMap expected_initial;
|
||||
expected_initial[".ra"] = "reg2";
|
||||
expected_initial["reg0"] = "reg1";
|
||||
EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
|
||||
EXPECT_EQ(0U, entries[0]->rule_changes.size());
|
||||
}
|
||||
|
||||
TEST_F(Rule, DefaultReturnAddressRuleOverride) {
|
||||
return_reg = 2;
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.RegisterRule(entry_address, return_reg, 1));
|
||||
ASSERT_TRUE(handler.End());
|
||||
CheckEntry();
|
||||
Module::RuleMap expected_initial;
|
||||
expected_initial[".ra"] = "reg1";
|
||||
EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
|
||||
EXPECT_EQ(0U, entries[0]->rule_changes.size());
|
||||
}
|
||||
|
||||
TEST_F(Rule, DefaultReturnAddressRuleLater) {
|
||||
return_reg = 2;
|
||||
StartEntry();
|
||||
ASSERT_TRUE(handler.RegisterRule(entry_address + 1, return_reg, 1));
|
||||
ASSERT_TRUE(handler.End());
|
||||
CheckEntry();
|
||||
Module::RuleMap expected_initial;
|
||||
expected_initial[".ra"] = "reg2";
|
||||
EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
|
||||
Module::RuleChangeMap expected_changes;
|
||||
expected_changes[entry_address + 1][".ra"] = "reg1";
|
||||
EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
|
||||
}
|
||||
|
||||
TEST(RegisterNames, I386) {
|
||||
vector<string> names = DwarfCFIToModule::RegisterNames::I386();
|
||||
|
||||
EXPECT_EQ("$eax", names[0]);
|
||||
EXPECT_EQ("$ecx", names[1]);
|
||||
EXPECT_EQ("$esp", names[4]);
|
||||
EXPECT_EQ("$eip", names[8]);
|
||||
}
|
||||
|
||||
TEST(RegisterNames, ARM) {
|
||||
vector<string> names = DwarfCFIToModule::RegisterNames::ARM();
|
||||
|
||||
EXPECT_EQ("r0", names[0]);
|
||||
EXPECT_EQ("r10", names[10]);
|
||||
EXPECT_EQ("sp", names[13]);
|
||||
EXPECT_EQ("lr", names[14]);
|
||||
EXPECT_EQ("pc", names[15]);
|
||||
}
|
||||
|
||||
TEST(RegisterNames, X86_64) {
|
||||
vector<string> names = DwarfCFIToModule::RegisterNames::X86_64();
|
||||
|
||||
EXPECT_EQ("$rax", names[0]);
|
||||
EXPECT_EQ("$rdx", names[1]);
|
||||
EXPECT_EQ("$rbp", names[6]);
|
||||
EXPECT_EQ("$rsp", names[7]);
|
||||
EXPECT_EQ("$rip", names[16]);
|
||||
}
|
||||
|
||||
TEST(RegisterNames, RISCV) {
|
||||
vector<string> names = DwarfCFIToModule::RegisterNames::RISCV();
|
||||
|
||||
EXPECT_EQ("pc", names[0]);
|
||||
EXPECT_EQ("t6", names[31]);
|
||||
EXPECT_EQ("f0", names[32]);
|
||||
EXPECT_EQ("f31", names[63]);
|
||||
EXPECT_EQ("v0", names[96]);
|
||||
EXPECT_EQ("v31", names[127]);
|
||||
}
|
||||
|
||||
1641
externals/breakpad/src/common/dwarf_cu_to_module.cc
vendored
Normal file
1641
externals/breakpad/src/common/dwarf_cu_to_module.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
417
externals/breakpad/src/common/dwarf_cu_to_module.h
vendored
Normal file
417
externals/breakpad/src/common/dwarf_cu_to_module.h
vendored
Normal file
|
|
@ -0,0 +1,417 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// Add DWARF debugging information to a Breakpad symbol file. This
|
||||
// file defines the DwarfCUToModule class, which accepts parsed DWARF
|
||||
// data and populates a google_breakpad::Module with the results; the
|
||||
// Module can then write its contents as a Breakpad symbol file.
|
||||
|
||||
#ifndef COMMON_LINUX_DWARF_CU_TO_MODULE_H__
|
||||
#define COMMON_LINUX_DWARF_CU_TO_MODULE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/language.h"
|
||||
#include "common/module.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 {
|
||||
|
||||
// Populate a google_breakpad::Module with DWARF debugging information.
|
||||
//
|
||||
// An instance of this class can be provided as a handler to a
|
||||
// DIEDispatcher, which can in turn be a handler for a
|
||||
// CompilationUnit DWARF parser. The handler uses the results
|
||||
// of parsing to populate a google_breakpad::Module with source file,
|
||||
// function, and source line information.
|
||||
class DwarfCUToModule: public RootDIEHandler {
|
||||
struct FilePrivate;
|
||||
public:
|
||||
// Information global to the DWARF-bearing file we are processing,
|
||||
// for use by DwarfCUToModule. Each DwarfCUToModule instance deals
|
||||
// with a single compilation unit within the file, but information
|
||||
// global to the whole file is held here. The client is responsible
|
||||
// for filling it in appropriately (except for the 'file_private'
|
||||
// field, which the constructor and destructor take care of), and
|
||||
// then providing it to the DwarfCUToModule instance for each
|
||||
// compilation unit we process in that file. Set HANDLE_INTER_CU_REFS
|
||||
// to true to handle debugging symbols with DW_FORM_ref_addr entries.
|
||||
class FileContext {
|
||||
public:
|
||||
FileContext(const string& filename,
|
||||
Module* module,
|
||||
bool handle_inter_cu_refs);
|
||||
~FileContext();
|
||||
|
||||
// Add CONTENTS of size LENGTH to the section map as NAME.
|
||||
void AddSectionToSectionMap(const string& name,
|
||||
const uint8_t* contents,
|
||||
uint64_t length);
|
||||
|
||||
void AddManagedSectionToSectionMap(const string& name,
|
||||
uint8_t* contents,
|
||||
uint64_t length);
|
||||
|
||||
// Clear the section map for testing.
|
||||
void ClearSectionMapForTest();
|
||||
|
||||
const 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_t offset,
|
||||
uint64_t compilation_unit_start) const;
|
||||
|
||||
// The name of this file, for use in error messages.
|
||||
const string filename_;
|
||||
|
||||
// A map of this file's sections, used for finding other DWARF
|
||||
// sections that the .debug_info section may refer to.
|
||||
SectionMap section_map_;
|
||||
|
||||
// The Module to which we're contributing definitions.
|
||||
Module* module_;
|
||||
|
||||
// True if we are handling references between compilation units.
|
||||
const bool handle_inter_cu_refs_;
|
||||
|
||||
// Inter-compilation unit data used internally by the handlers.
|
||||
scoped_ptr<FilePrivate> file_private_;
|
||||
std::vector<uint8_t *> uncompressed_sections_;
|
||||
};
|
||||
|
||||
// An abstract base class for handlers that handle DWARF range lists for
|
||||
// DwarfCUToModule.
|
||||
class RangesHandler {
|
||||
public:
|
||||
RangesHandler() { }
|
||||
virtual ~RangesHandler() { }
|
||||
|
||||
// Called when finishing a function to populate the function's ranges.
|
||||
// The entries are read according to the form and data.
|
||||
virtual bool ReadRanges(
|
||||
enum DwarfForm form, uint64_t data,
|
||||
RangeListReader::CURangesInfo* cu_info,
|
||||
vector<Module::Range>* ranges) = 0;
|
||||
};
|
||||
|
||||
// An abstract base class for handlers that handle DWARF line data
|
||||
// for DwarfCUToModule. DwarfCUToModule could certainly just use
|
||||
// LineInfo itself directly, but decoupling things
|
||||
// this way makes unit testing a little easier.
|
||||
class LineToModuleHandler {
|
||||
public:
|
||||
LineToModuleHandler() { }
|
||||
virtual ~LineToModuleHandler() { }
|
||||
|
||||
// Called at the beginning of a new compilation unit, prior to calling
|
||||
// ReadProgram(). compilation_dir will indicate the path that the
|
||||
// current compilation unit was compiled in, consistent with the
|
||||
// DW_AT_comp_dir DIE.
|
||||
virtual void StartCompilationUnit(const string& compilation_dir) = 0;
|
||||
|
||||
// Populate MODULE and LINES with source file names and code/line
|
||||
// mappings, given a pointer to some DWARF line number data
|
||||
// PROGRAM, and an overestimate of its size. Add no zero-length
|
||||
// lines to LINES.
|
||||
virtual void ReadProgram(const uint8_t* program, uint64_t length,
|
||||
const uint8_t* string_section,
|
||||
uint64_t string_section_length,
|
||||
const uint8_t* line_string_section,
|
||||
uint64_t line_string_length,
|
||||
Module* module, vector<Module::Line>* lines,
|
||||
map<uint32_t, Module::File*>* files) = 0;
|
||||
};
|
||||
|
||||
// The interface DwarfCUToModule uses to report warnings. The member
|
||||
// function definitions for this class write messages to stderr, but
|
||||
// you can override them if you'd like to detect or report these
|
||||
// conditions yourself.
|
||||
class WarningReporter {
|
||||
public:
|
||||
// Warn about problems in the DWARF file FILENAME, in the
|
||||
// compilation unit at OFFSET.
|
||||
WarningReporter(const string& filename, uint64_t cu_offset)
|
||||
: filename_(filename), cu_offset_(cu_offset), printed_cu_header_(false),
|
||||
printed_unpaired_header_(false),
|
||||
uncovered_warnings_enabled_(false) { }
|
||||
virtual ~WarningReporter() { }
|
||||
|
||||
// Set the name of the compilation unit we're processing to NAME.
|
||||
virtual void SetCUName(const string& name) { cu_name_ = name; }
|
||||
|
||||
// Accessor and setter for uncovered_warnings_enabled_.
|
||||
// UncoveredFunction and UncoveredLine only report a problem if that is
|
||||
// true. By default, these warnings are disabled, because those
|
||||
// conditions occur occasionally in healthy code.
|
||||
virtual bool uncovered_warnings_enabled() const {
|
||||
return uncovered_warnings_enabled_;
|
||||
}
|
||||
virtual void set_uncovered_warnings_enabled(bool value) {
|
||||
uncovered_warnings_enabled_ = value;
|
||||
}
|
||||
|
||||
// A DW_AT_specification in the DIE at OFFSET refers to a DIE we
|
||||
// haven't processed yet, or that wasn't marked as a declaration,
|
||||
// at TARGET.
|
||||
virtual void UnknownSpecification(uint64_t offset, uint64_t target);
|
||||
|
||||
// A DW_AT_abstract_origin in the DIE at OFFSET refers to a DIE we
|
||||
// haven't processed yet, or that wasn't marked as inline, at TARGET.
|
||||
virtual void UnknownAbstractOrigin(uint64_t offset, uint64_t target);
|
||||
|
||||
// We were unable to find the DWARF section named SECTION_NAME.
|
||||
virtual void MissingSection(const string& section_name);
|
||||
|
||||
// The CU's DW_AT_stmt_list offset OFFSET is bogus.
|
||||
virtual void BadLineInfoOffset(uint64_t offset);
|
||||
|
||||
// FUNCTION includes code covered by no line number data.
|
||||
virtual void UncoveredFunction(const Module::Function& function);
|
||||
|
||||
// Line number NUMBER in LINE_FILE, of length LENGTH, includes code
|
||||
// covered by no function.
|
||||
virtual void UncoveredLine(const Module::Line& line);
|
||||
|
||||
// The DW_TAG_subprogram DIE at OFFSET has no name specified directly
|
||||
// in the DIE, nor via a DW_AT_specification or DW_AT_abstract_origin
|
||||
// link.
|
||||
virtual void UnnamedFunction(uint64_t offset);
|
||||
|
||||
// __cxa_demangle() failed to demangle INPUT.
|
||||
virtual void DemangleError(const string& input);
|
||||
|
||||
// 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_t offset, uint64_t target);
|
||||
|
||||
// The DW_AT_ranges at offset is malformed (truncated or outside of the
|
||||
// .debug_ranges section's bound).
|
||||
virtual void MalformedRangeList(uint64_t offset);
|
||||
|
||||
// A DW_AT_ranges attribute was encountered but the no .debug_ranges
|
||||
// section was found.
|
||||
virtual void MissingRanges();
|
||||
|
||||
uint64_t cu_offset() const {
|
||||
return cu_offset_;
|
||||
}
|
||||
|
||||
protected:
|
||||
const string filename_;
|
||||
const uint64_t cu_offset_;
|
||||
string cu_name_;
|
||||
bool printed_cu_header_;
|
||||
bool printed_unpaired_header_;
|
||||
bool uncovered_warnings_enabled_;
|
||||
|
||||
private:
|
||||
// Print a per-CU heading, once.
|
||||
void CUHeading();
|
||||
// Print an unpaired function/line heading, once.
|
||||
void UncoveredHeading();
|
||||
};
|
||||
|
||||
class NullWarningReporter : public WarningReporter {
|
||||
public:
|
||||
NullWarningReporter(const string& filename, uint64_t cu_offset)
|
||||
: WarningReporter(filename, cu_offset) {}
|
||||
|
||||
// Set the name of the compilation unit we're processing to NAME.
|
||||
void SetCUName(const string& name) {}
|
||||
|
||||
// Accessor and setter for uncovered_warnings_enabled_.
|
||||
// UncoveredFunction and UncoveredLine only report a problem if that is
|
||||
// true. By default, these warnings are disabled, because those
|
||||
// conditions occur occasionally in healthy code.
|
||||
void set_uncovered_warnings_enabled(bool value) {}
|
||||
|
||||
// A DW_AT_specification in the DIE at OFFSET refers to a DIE we
|
||||
// haven't processed yet, or that wasn't marked as a declaration,
|
||||
// at TARGET.
|
||||
void UnknownSpecification(uint64_t offset, uint64_t target) {}
|
||||
|
||||
// A DW_AT_abstract_origin in the DIE at OFFSET refers to a DIE we
|
||||
// haven't processed yet, or that wasn't marked as inline, at TARGET.
|
||||
void UnknownAbstractOrigin(uint64_t offset, uint64_t target) {}
|
||||
|
||||
// We were unable to find the DWARF section named SECTION_NAME.
|
||||
void MissingSection(const string& section_name) {}
|
||||
|
||||
// The CU's DW_AT_stmt_list offset OFFSET is bogus.
|
||||
void BadLineInfoOffset(uint64_t offset) {}
|
||||
|
||||
// FUNCTION includes code covered by no line number data.
|
||||
void UncoveredFunction(const Module::Function& function) {}
|
||||
|
||||
// Line number NUMBER in LINE_FILE, of length LENGTH, includes code
|
||||
// covered by no function.
|
||||
void UncoveredLine(const Module::Line& line) {}
|
||||
|
||||
// The DW_TAG_subprogram DIE at OFFSET has no name specified directly
|
||||
// in the DIE, nor via a DW_AT_specification or DW_AT_abstract_origin
|
||||
// link.
|
||||
void UnnamedFunction(uint64_t offset) {}
|
||||
|
||||
// __cxa_demangle() failed to demangle INPUT.
|
||||
void DemangleError(const string& input) {}
|
||||
|
||||
// The DW_FORM_ref_addr at OFFSET to TARGET was not handled because
|
||||
// FilePrivate did not retain the inter-CU specification data.
|
||||
void UnhandledInterCUReference(uint64_t offset, uint64_t target) {}
|
||||
|
||||
// The DW_AT_ranges at offset is malformed (truncated or outside of the
|
||||
// .debug_ranges section's bound).
|
||||
void MalformedRangeList(uint64_t offset) {}
|
||||
|
||||
// A DW_AT_ranges attribute was encountered but the no .debug_ranges
|
||||
// section was found.
|
||||
void MissingRanges() {}
|
||||
};
|
||||
|
||||
// Create a DWARF debugging info handler for a compilation unit
|
||||
// within FILE_CONTEXT. This uses information received from the
|
||||
// CompilationUnit DWARF parser to populate
|
||||
// FILE_CONTEXT->module. Use LINE_READER to handle the compilation
|
||||
// unit's line number data. Use REPORTER to report problems with the
|
||||
// data we find.
|
||||
DwarfCUToModule(FileContext* file_context,
|
||||
LineToModuleHandler* line_reader,
|
||||
RangesHandler* ranges_handler,
|
||||
WarningReporter* reporter,
|
||||
bool handle_inline = false,
|
||||
uint64_t low_pc = 0,
|
||||
uint64_t addr_base = 0,
|
||||
bool has_source_line_info = false,
|
||||
uint64_t source_line_offset = 0);
|
||||
~DwarfCUToModule();
|
||||
|
||||
void ProcessAttributeSigned(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
int64_t data);
|
||||
void ProcessAttributeUnsigned(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
uint64_t data);
|
||||
void ProcessAttributeString(enum DwarfAttribute attr,
|
||||
enum DwarfForm form,
|
||||
const string& data);
|
||||
bool EndAttributes();
|
||||
DIEHandler* FindChildHandler(uint64_t offset, enum DwarfTag tag);
|
||||
|
||||
// Assign all our source Lines to the Functions that cover their
|
||||
// addresses, and then add them to module_.
|
||||
void Finish();
|
||||
|
||||
bool StartCompilationUnit(uint64_t offset, uint8_t address_size,
|
||||
uint8_t offset_size, uint64_t cu_length,
|
||||
uint8_t dwarf_version);
|
||||
bool StartRootDIE(uint64_t offset, enum DwarfTag tag);
|
||||
|
||||
private:
|
||||
// Used internally by the handler. Full definitions are in
|
||||
// dwarf_cu_to_module.cc.
|
||||
struct CUContext;
|
||||
struct DIEContext;
|
||||
struct Specification;
|
||||
class GenericDIEHandler;
|
||||
class FuncHandler;
|
||||
class LexicalBlockHandler;
|
||||
class InlineHandler;
|
||||
class NamedScopeHandler;
|
||||
|
||||
// A map from section offsets to specifications.
|
||||
typedef map<uint64_t, Specification> SpecificationByOffset;
|
||||
|
||||
// Set this compilation unit's source language to LANGUAGE.
|
||||
void SetLanguage(DwarfLanguage language);
|
||||
|
||||
// Read source line information at OFFSET in the .debug_line
|
||||
// section. Record source files in module_, but record source lines
|
||||
// in lines_; we apportion them to functions in
|
||||
// AssignLinesToFunctions.
|
||||
void ReadSourceLines(uint64_t offset);
|
||||
|
||||
// Assign the lines in lines_ to the individual line lists of the
|
||||
// functions in functions_. (DWARF line information maps an entire
|
||||
// compilation unit at a time, and gives no indication of which
|
||||
// lines belong to which functions, beyond their addresses.)
|
||||
void AssignLinesToFunctions();
|
||||
|
||||
void AssignFilesToInlines();
|
||||
|
||||
// The only reason cu_context_ and child_context_ are pointers is
|
||||
// that we want to keep their definitions private to
|
||||
// dwarf_cu_to_module.cc, instead of listing them all here. They are
|
||||
// owned by this DwarfCUToModule: the constructor sets them, and the
|
||||
// destructor deletes them.
|
||||
|
||||
// The handler to use to handle line number data.
|
||||
LineToModuleHandler* line_reader_;
|
||||
|
||||
// This compilation unit's context.
|
||||
scoped_ptr<CUContext> cu_context_;
|
||||
|
||||
// A context for our children.
|
||||
scoped_ptr<DIEContext> child_context_;
|
||||
|
||||
// True if this compilation unit has source line information.
|
||||
bool has_source_line_info_;
|
||||
|
||||
// The offset of this compilation unit's line number information in
|
||||
// the .debug_line section.
|
||||
uint64_t source_line_offset_;
|
||||
|
||||
// The line numbers we have seen thus far. We accumulate these here
|
||||
// during parsing. Then, in Finish, we call AssignLinesToFunctions
|
||||
// to dole them out to the appropriate functions.
|
||||
vector<Module::Line> lines_;
|
||||
|
||||
// The map from file index to File* in this CU.
|
||||
std::map<uint32_t, Module::File*> files_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_DWARF_CU_TO_MODULE_H__
|
||||
1872
externals/breakpad/src/common/dwarf_cu_to_module_unittest.cc
vendored
Normal file
1872
externals/breakpad/src/common/dwarf_cu_to_module_unittest.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
146
externals/breakpad/src/common/dwarf_line_to_module.cc
vendored
Normal file
146
externals/breakpad/src/common/dwarf_line_to_module.cc
vendored
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dwarf_line_to_module.cc: Implementation of DwarfLineToModule class.
|
||||
// See dwarf_line_to_module.h for details.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
// Trying to support Windows paths in a reasonable way adds a lot of
|
||||
// variations to test; it would be better to just put off dealing with
|
||||
// it until we actually have to deal with DWARF on Windows.
|
||||
|
||||
// Return true if PATH is an absolute path, false if it is relative.
|
||||
static bool PathIsAbsolute(const string& path) {
|
||||
return (path.size() >= 1 && path[0] == '/');
|
||||
}
|
||||
|
||||
static bool HasTrailingSlash(const string& path) {
|
||||
return (path.size() >= 1 && path[path.size() - 1] == '/');
|
||||
}
|
||||
|
||||
// If PATH is an absolute path, return PATH. If PATH is a relative path,
|
||||
// treat it as relative to BASE and return the combined path.
|
||||
static string ExpandPath(const string& path,
|
||||
const string& base) {
|
||||
if (PathIsAbsolute(path) || base.empty())
|
||||
return path;
|
||||
return base + (HasTrailingSlash(base) ? "" : "/") + path;
|
||||
}
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
void DwarfLineToModule::DefineDir(const string& name, uint32_t dir_num) {
|
||||
// Directory number zero is reserved to mean the compilation
|
||||
// directory. Silently ignore attempts to redefine it.
|
||||
if (dir_num != 0)
|
||||
directories_[dir_num] = ExpandPath(name, compilation_dir_);
|
||||
}
|
||||
|
||||
void DwarfLineToModule::DefineFile(const string& name, int32_t file_num,
|
||||
uint32_t dir_num, uint64_t mod_time,
|
||||
uint64_t length) {
|
||||
if (file_num == -1)
|
||||
file_num = ++highest_file_number_;
|
||||
else if (file_num > highest_file_number_)
|
||||
highest_file_number_ = file_num;
|
||||
|
||||
string dir_name;
|
||||
if (dir_num == 0) {
|
||||
// Directory number zero is the compilation directory, and is stored as
|
||||
// an attribute on the compilation unit, rather than in the program table.
|
||||
dir_name = compilation_dir_;
|
||||
} else {
|
||||
DirectoryTable::const_iterator directory_it = directories_.find(dir_num);
|
||||
if (directory_it != directories_.end()) {
|
||||
dir_name = directory_it->second;
|
||||
} else {
|
||||
if (!warned_bad_directory_number_) {
|
||||
fprintf(stderr, "warning: DWARF line number data refers to undefined"
|
||||
" directory numbers\n");
|
||||
warned_bad_directory_number_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string full_name = ExpandPath(name, dir_name);
|
||||
|
||||
// Find a Module::File object of the given name, and add it to the
|
||||
// file table.
|
||||
(*files_)[file_num] = module_->FindFile(full_name);
|
||||
}
|
||||
|
||||
void DwarfLineToModule::AddLine(uint64_t address, uint64_t length,
|
||||
uint32_t file_num, uint32_t line_num,
|
||||
uint32_t column_num) {
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
// Clip lines not to extend beyond the end of the address space.
|
||||
if (address + length < address)
|
||||
length = -address;
|
||||
|
||||
// Should we omit this line? (See the comments for omitted_line_end_.)
|
||||
if (address == 0 || address == omitted_line_end_) {
|
||||
omitted_line_end_ = address + length;
|
||||
return;
|
||||
} else {
|
||||
omitted_line_end_ = 0;
|
||||
}
|
||||
|
||||
// Find the source file being referred to.
|
||||
Module::File *file = (*files_)[file_num];
|
||||
if (!file) {
|
||||
if (!warned_bad_file_number_) {
|
||||
fprintf(stderr, "warning: DWARF line number data refers to "
|
||||
"undefined file numbers\n");
|
||||
warned_bad_file_number_ = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Module::Line line;
|
||||
line.address = address;
|
||||
// We set the size when we get the next line or the EndSequence call.
|
||||
line.size = length;
|
||||
line.file = file;
|
||||
line.number = line_num;
|
||||
lines_->push_back(line);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
190
externals/breakpad/src/common/dwarf_line_to_module.h
vendored
Normal file
190
externals/breakpad/src/common/dwarf_line_to_module.h
vendored
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// The DwarfLineToModule class accepts line number information from a
|
||||
// DWARF parser and adds it to a google_breakpad::Module. The Module
|
||||
// can write that data out as a Breakpad symbol file.
|
||||
|
||||
#ifndef COMMON_LINUX_DWARF_LINE_TO_MODULE_H
|
||||
#define COMMON_LINUX_DWARF_LINE_TO_MODULE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/module.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A class for producing a vector of google_breakpad::Module::Line
|
||||
// instances from parsed DWARF line number data.
|
||||
//
|
||||
// An instance of this class can be provided as a handler to a
|
||||
// LineInfo DWARF line number information parser. The
|
||||
// handler accepts source location information from the parser and
|
||||
// uses it to produce a vector of google_breakpad::Module::Line
|
||||
// objects, referring to google_breakpad::Module::File objects added
|
||||
// to a particular google_breakpad::Module.
|
||||
//
|
||||
// GNU toolchain omitted sections support:
|
||||
// ======================================
|
||||
//
|
||||
// Given the right options, the GNU toolchain will omit unreferenced
|
||||
// functions from the final executable. Unfortunately, when it does so, it
|
||||
// does not remove the associated portions of the DWARF line number
|
||||
// program; instead, it gives the DW_LNE_set_address instructions referring
|
||||
// to the now-deleted code addresses of zero. Given this input, the DWARF
|
||||
// line parser will call AddLine with a series of lines starting at address
|
||||
// zero. For example, here is the output from 'readelf -wl' for a program
|
||||
// with four functions, the first three of which have been omitted:
|
||||
//
|
||||
// Line Number Statements:
|
||||
// Extended opcode 2: set Address to 0x0
|
||||
// Advance Line by 14 to 15
|
||||
// Copy
|
||||
// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 16
|
||||
// Special opcode 119: advance Address by 8 to 0xb and Line by 2 to 18
|
||||
// Advance PC by 2 to 0xd
|
||||
// Extended opcode 1: End of Sequence
|
||||
//
|
||||
// Extended opcode 2: set Address to 0x0
|
||||
// Advance Line by 14 to 15
|
||||
// Copy
|
||||
// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 16
|
||||
// Special opcode 119: advance Address by 8 to 0xb and Line by 2 to 18
|
||||
// Advance PC by 2 to 0xd
|
||||
// Extended opcode 1: End of Sequence
|
||||
//
|
||||
// Extended opcode 2: set Address to 0x0
|
||||
// Advance Line by 19 to 20
|
||||
// Copy
|
||||
// Special opcode 48: advance Address by 3 to 0x3 and Line by 1 to 21
|
||||
// Special opcode 76: advance Address by 5 to 0x8 and Line by 1 to 22
|
||||
// Advance PC by 2 to 0xa
|
||||
// Extended opcode 1: End of Sequence
|
||||
//
|
||||
// Extended opcode 2: set Address to 0x80483a4
|
||||
// Advance Line by 23 to 24
|
||||
// Copy
|
||||
// Special opcode 202: advance Address by 14 to 0x80483b2 and Line by 1 to 25
|
||||
// Special opcode 76: advance Address by 5 to 0x80483b7 and Line by 1 to 26
|
||||
// Advance PC by 6 to 0x80483bd
|
||||
// Extended opcode 1: End of Sequence
|
||||
//
|
||||
// Instead of collecting runs of lines describing code that is not there,
|
||||
// we try to recognize and drop them. Since the linker doesn't explicitly
|
||||
// distinguish references to dropped sections from genuine references to
|
||||
// code at address zero, we must use a heuristic. We have chosen:
|
||||
//
|
||||
// - If a line starts at address zero, omit it. (On the platforms
|
||||
// breakpad targets, it is extremely unlikely that there will be code
|
||||
// at address zero.)
|
||||
//
|
||||
// - If a line starts immediately after an omitted line, omit it too.
|
||||
class DwarfLineToModule: public LineInfoHandler {
|
||||
public:
|
||||
// As the DWARF line info parser passes us line records, add source
|
||||
// files to MODULE, and add all lines to the end of LINES. LINES
|
||||
// need not be empty. If the parser hands us a zero-length line, we
|
||||
// omit it. If the parser hands us a line that extends beyond the
|
||||
// end of the address space, we clip it. It's up to our client to
|
||||
// sort out which lines belong to which functions; we don't add them
|
||||
// to any particular function in MODULE ourselves.
|
||||
DwarfLineToModule(Module* module,
|
||||
const string& compilation_dir,
|
||||
vector<Module::Line>* lines,
|
||||
std::map<uint32_t, Module::File*>* files)
|
||||
: module_(module),
|
||||
compilation_dir_(compilation_dir),
|
||||
lines_(lines),
|
||||
files_(files),
|
||||
highest_file_number_(-1),
|
||||
omitted_line_end_(0),
|
||||
warned_bad_file_number_(false),
|
||||
warned_bad_directory_number_(false) { }
|
||||
|
||||
~DwarfLineToModule() { }
|
||||
|
||||
void DefineDir(const string& name, uint32_t dir_num);
|
||||
void DefineFile(const string& name, int32_t file_num,
|
||||
uint32_t dir_num, uint64_t mod_time,
|
||||
uint64_t length);
|
||||
void AddLine(uint64_t address, uint64_t length,
|
||||
uint32_t file_num, uint32_t line_num, uint32_t column_num);
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<uint32_t, string> DirectoryTable;
|
||||
typedef std::map<uint32_t, Module::File*> FileTable;
|
||||
|
||||
// The module we're contributing debugging info to. Owned by our
|
||||
// client.
|
||||
Module *module_;
|
||||
|
||||
// The compilation directory for the current compilation unit whose
|
||||
// lines are being accumulated.
|
||||
string compilation_dir_;
|
||||
|
||||
// The vector of lines we're accumulating. Owned by our client.
|
||||
//
|
||||
// In a Module, as in a breakpad symbol file, lines belong to
|
||||
// specific functions, but DWARF simply assigns lines to addresses;
|
||||
// one must infer the line/function relationship using the
|
||||
// functions' beginning and ending addresses. So we can't add these
|
||||
// to the appropriate function from module_ until we've read the
|
||||
// function info as well. Instead, we accumulate lines here, and let
|
||||
// whoever constructed this sort it all out.
|
||||
vector<Module::Line>* lines_;
|
||||
|
||||
// A table mapping directory numbers to paths.
|
||||
DirectoryTable directories_;
|
||||
|
||||
// A table mapping file numbers to Module::File pointers.
|
||||
FileTable* files_;
|
||||
|
||||
// The highest file number we've seen so far, or -1 if we've seen
|
||||
// none. Used for dynamically defined file numbers.
|
||||
int32_t highest_file_number_;
|
||||
|
||||
// This is the ending address of the last line we omitted, or zero if we
|
||||
// didn't omit the previous line. It is zero before we have received any
|
||||
// AddLine calls.
|
||||
uint64_t omitted_line_end_;
|
||||
|
||||
// True if we've warned about:
|
||||
bool warned_bad_file_number_; // bad file numbers
|
||||
bool warned_bad_directory_number_; // bad directory numbers
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_DWARF_LINE_TO_MODULE_H
|
||||
413
externals/breakpad/src/common/dwarf_line_to_module_unittest.cc
vendored
Normal file
413
externals/breakpad/src/common/dwarf_line_to_module_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,413 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// dwarf_line_to_module.cc: Unit tests for google_breakpad::DwarfLineToModule.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
|
||||
using std::vector;
|
||||
|
||||
using google_breakpad::DwarfLineToModule;
|
||||
using google_breakpad::Module;
|
||||
using google_breakpad::Module;
|
||||
|
||||
TEST(SimpleModule, One) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineFile("file1", 0x30bf0f27, 0, 0, 0);
|
||||
h.AddLine(0x6fd126fbf74f2680LL, 0x63c9a14cf556712bLL, 0x30bf0f27,
|
||||
0x4c090cbf, 0x1cf9fe0d);
|
||||
|
||||
vector<Module::File*> files;
|
||||
m.GetFiles(&files);
|
||||
EXPECT_EQ(1U, files.size());
|
||||
EXPECT_STREQ("/file1", files[0]->name.c_str());
|
||||
|
||||
EXPECT_EQ(1U, lines.size());
|
||||
EXPECT_EQ(0x6fd126fbf74f2680ULL, lines[0].address);
|
||||
EXPECT_EQ(0x63c9a14cf556712bULL, lines[0].size);
|
||||
EXPECT_TRUE(lines[0].file == files[0]);
|
||||
EXPECT_EQ(0x4c090cbf, lines[0].number);
|
||||
}
|
||||
|
||||
TEST(SimpleModule, Many) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineDir("directory1", 0x838299ab);
|
||||
h.DefineDir("directory2", 0xf85de023);
|
||||
h.DefineFile("file1", 0x2b80377a, 0x838299ab, 0, 0);
|
||||
h.DefineFile("file1", 0x63beb4a4, 0xf85de023, 0, 0);
|
||||
h.DefineFile("file2", 0x1d161d56, 0x838299ab, 0, 0);
|
||||
h.DefineFile("file2", 0x1e7a667c, 0xf85de023, 0, 0);
|
||||
h.AddLine(0x69900c5d553b7274ULL, 0x90fded183f0d0d3cULL, 0x2b80377a,
|
||||
0x15b0f0a9U, 0x3ff5abd6U);
|
||||
h.AddLine(0x45811219a39b7101ULL, 0x25a5e6a924afc41fULL, 0x63beb4a4,
|
||||
0x4d259ce9U, 0x41c5ee32U);
|
||||
h.AddLine(0xfa90514c1dc9704bULL, 0x0063efeabc02f313ULL, 0x1d161d56,
|
||||
0x1ee9fa4fU, 0xbf70e46aU);
|
||||
h.AddLine(0x556b55fb6a647b10ULL, 0x3f3089ca2bfd80f5ULL, 0x1e7a667c,
|
||||
0x77fc280eU, 0x2c4a728cU);
|
||||
h.DefineFile("file3", -1, 0, 0, 0);
|
||||
h.AddLine(0xe2d72a37f8d9403aULL, 0x034dfab5b0d4d236ULL, 0x63beb4a5,
|
||||
0x75047044U, 0xb6a0016cU);
|
||||
|
||||
vector<Module::File*> files;
|
||||
m.GetFiles(&files);
|
||||
ASSERT_EQ(5U, files.size());
|
||||
EXPECT_STREQ("/directory1/file1", files[0]->name.c_str());
|
||||
EXPECT_STREQ("/directory1/file2", files[1]->name.c_str());
|
||||
EXPECT_STREQ("/directory2/file1", files[2]->name.c_str());
|
||||
EXPECT_STREQ("/directory2/file2", files[3]->name.c_str());
|
||||
EXPECT_STREQ("/file3", files[4]->name.c_str());
|
||||
|
||||
ASSERT_EQ(5U, lines.size());
|
||||
|
||||
EXPECT_EQ(0x69900c5d553b7274ULL, lines[0].address);
|
||||
EXPECT_EQ(0x90fded183f0d0d3cULL, lines[0].size);
|
||||
EXPECT_TRUE(lines[0].file == files[0]);
|
||||
EXPECT_EQ(0x15b0f0a9, lines[0].number);
|
||||
|
||||
EXPECT_EQ(0x45811219a39b7101ULL, lines[1].address);
|
||||
EXPECT_EQ(0x25a5e6a924afc41fULL, lines[1].size);
|
||||
EXPECT_TRUE(lines[1].file == files[2]);
|
||||
EXPECT_EQ(0x4d259ce9, lines[1].number);
|
||||
|
||||
EXPECT_EQ(0xfa90514c1dc9704bULL, lines[2].address);
|
||||
EXPECT_EQ(0x0063efeabc02f313ULL, lines[2].size);
|
||||
EXPECT_TRUE(lines[2].file == files[1]);
|
||||
EXPECT_EQ(0x1ee9fa4f, lines[2].number);
|
||||
|
||||
EXPECT_EQ(0x556b55fb6a647b10ULL, lines[3].address);
|
||||
EXPECT_EQ(0x3f3089ca2bfd80f5ULL, lines[3].size);
|
||||
EXPECT_TRUE(lines[3].file == files[3]);
|
||||
EXPECT_EQ(0x77fc280e, lines[3].number);
|
||||
|
||||
EXPECT_EQ(0xe2d72a37f8d9403aULL, lines[4].address);
|
||||
EXPECT_EQ(0x034dfab5b0d4d236ULL, lines[4].size);
|
||||
EXPECT_TRUE(lines[4].file == files[4]);
|
||||
EXPECT_EQ(0x75047044, lines[4].number);
|
||||
}
|
||||
|
||||
TEST(Filenames, Absolute) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineDir("directory1", 1);
|
||||
h.DefineFile("/absolute", 1, 1, 0, 0);
|
||||
|
||||
h.AddLine(1, 1, 1, 0, 0);
|
||||
|
||||
vector<Module::File*> files;
|
||||
m.GetFiles(&files);
|
||||
ASSERT_EQ(1U, files.size());
|
||||
EXPECT_STREQ("/absolute", files[0]->name.c_str());
|
||||
ASSERT_EQ(1U, lines.size());
|
||||
EXPECT_TRUE(lines[0].file == files[0]);
|
||||
}
|
||||
|
||||
TEST(Filenames, Relative) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineDir("directory1", 1);
|
||||
h.DefineFile("relative", 1, 1, 0, 0);
|
||||
|
||||
h.AddLine(1, 1, 1, 0, 0);
|
||||
|
||||
vector<Module::File*> files;
|
||||
m.GetFiles(&files);
|
||||
ASSERT_EQ(1U, files.size());
|
||||
EXPECT_STREQ("/directory1/relative", files[0]->name.c_str());
|
||||
ASSERT_EQ(1U, lines.size());
|
||||
EXPECT_TRUE(lines[0].file == files[0]);
|
||||
}
|
||||
|
||||
TEST(Filenames, StrangeFile) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineDir("directory1", 1);
|
||||
h.DefineFile("", 1, 1, 0, 0);
|
||||
h.AddLine(1, 1, 1, 0, 0);
|
||||
|
||||
ASSERT_EQ(1U, lines.size());
|
||||
EXPECT_STREQ("/directory1/", lines[0].file->name.c_str());
|
||||
}
|
||||
|
||||
TEST(Filenames, StrangeDirectory) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineDir("", 1);
|
||||
h.DefineFile("file1", 1, 1, 0, 0);
|
||||
h.AddLine(1, 1, 1, 0, 0);
|
||||
|
||||
ASSERT_EQ(1U, lines.size());
|
||||
EXPECT_STREQ("/file1", lines[0].file->name.c_str());
|
||||
}
|
||||
|
||||
TEST(Filenames, StrangeDirectoryAndFile) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineDir("", 1);
|
||||
h.DefineFile("", 1, 1, 0, 0);
|
||||
h.AddLine(1, 1, 1, 0, 0);
|
||||
|
||||
ASSERT_EQ(1U, lines.size());
|
||||
EXPECT_STREQ("/", lines[0].file->name.c_str());
|
||||
}
|
||||
|
||||
// We should use the compilation directory when encountering a file for
|
||||
// directory number zero.
|
||||
TEST(Filenames, DirectoryZeroFileIsRelativeToCompilationDir) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "src/build", &lines, &cu_files);
|
||||
|
||||
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;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "src/build", &lines, &cu_files);
|
||||
|
||||
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;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "src/build", &lines, &cu_files);
|
||||
|
||||
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;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineDir("directory0", 0); // should be ignored
|
||||
h.DefineFile("relative", 1, 0, 0, 0);
|
||||
|
||||
h.AddLine(1, 1, 1, 0, 0);
|
||||
|
||||
ASSERT_EQ(1U, lines.size());
|
||||
EXPECT_STREQ("/relative", lines[0].file->name.c_str());
|
||||
}
|
||||
|
||||
// We should refuse to add lines with bogus file numbers. We should
|
||||
// produce only one warning, however.
|
||||
TEST(ModuleErrors, BadFileNumber) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineFile("relative", 1, 0, 0, 0);
|
||||
h.AddLine(1, 1, 2, 0, 0); // bad file number
|
||||
h.AddLine(2, 1, 2, 0, 0); // bad file number (no duplicate warning)
|
||||
|
||||
EXPECT_EQ(0U, lines.size());
|
||||
}
|
||||
|
||||
// We should treat files with bogus directory numbers as relative to
|
||||
// the compilation unit.
|
||||
TEST(ModuleErrors, BadDirectoryNumber) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineDir("directory1", 1);
|
||||
h.DefineFile("baddirnumber1", 1, 2, 0, 0); // bad directory number
|
||||
h.DefineFile("baddirnumber2", 2, 2, 0, 0); // bad dir number (no warning)
|
||||
h.AddLine(1, 1, 1, 0, 0);
|
||||
|
||||
ASSERT_EQ(1U, lines.size());
|
||||
EXPECT_STREQ("baddirnumber1", lines[0].file->name.c_str());
|
||||
}
|
||||
|
||||
// We promise not to report empty lines.
|
||||
TEST(ModuleErrors, EmptyLine) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineFile("filename1", 1, 0, 0, 0);
|
||||
h.AddLine(1, 0, 1, 0, 0);
|
||||
|
||||
ASSERT_EQ(0U, lines.size());
|
||||
}
|
||||
|
||||
// We are supposed to clip lines that extend beyond the end of the
|
||||
// address space.
|
||||
TEST(ModuleErrors, BigLine) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineFile("filename1", 1, 0, 0, 0);
|
||||
h.AddLine(0xffffffffffffffffULL, 2, 1, 0, 0);
|
||||
|
||||
ASSERT_EQ(1U, lines.size());
|
||||
EXPECT_EQ(1U, lines[0].size);
|
||||
}
|
||||
|
||||
// The 'Omitted' tests verify that we correctly omit line information
|
||||
// for code in sections that the linker has dropped. See "GNU
|
||||
// toolchain omitted sections support" at the top of the
|
||||
// DwarfLineToModule class.
|
||||
|
||||
TEST(Omitted, DroppedThenGood) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineFile("filename1", 1, 0, 0, 0);
|
||||
h.AddLine(0, 10, 1, 83816211, 0); // should be omitted
|
||||
h.AddLine(20, 10, 1, 13059195, 0); // should be recorded
|
||||
|
||||
ASSERT_EQ(1U, lines.size());
|
||||
EXPECT_EQ(13059195, lines[0].number);
|
||||
}
|
||||
|
||||
TEST(Omitted, GoodThenDropped) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineFile("filename1", 1, 0, 0, 0);
|
||||
h.AddLine(0x9dd6a372, 10, 1, 41454594, 0); // should be recorded
|
||||
h.AddLine(0, 10, 1, 44793413, 0); // should be omitted
|
||||
|
||||
ASSERT_EQ(1U, lines.size());
|
||||
EXPECT_EQ(41454594, lines[0].number);
|
||||
}
|
||||
|
||||
TEST(Omitted, Mix1) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineFile("filename1", 1, 0, 0, 0);
|
||||
h.AddLine(0x679ed72f, 10, 1, 58932642, 0); // should be recorded
|
||||
h.AddLine(0xdfb5a72d, 10, 1, 39847385, 0); // should be recorded
|
||||
h.AddLine(0, 0x78, 1, 23053829, 0); // should be omitted
|
||||
h.AddLine(0x78, 0x6a, 1, 65317783, 0); // should be omitted
|
||||
h.AddLine(0x78 + 0x6a, 0x2a, 1, 77601423, 0); // should be omitted
|
||||
h.AddLine(0x9fe0cea5, 10, 1, 91806582, 0); // should be recorded
|
||||
h.AddLine(0x7e41a109, 10, 1, 56169221, 0); // should be recorded
|
||||
|
||||
ASSERT_EQ(4U, lines.size());
|
||||
EXPECT_EQ(58932642, lines[0].number);
|
||||
EXPECT_EQ(39847385, lines[1].number);
|
||||
EXPECT_EQ(91806582, lines[2].number);
|
||||
EXPECT_EQ(56169221, lines[3].number);
|
||||
}
|
||||
|
||||
TEST(Omitted, Mix2) {
|
||||
Module m("name", "os", "architecture", "id");
|
||||
vector<Module::Line> lines;
|
||||
std::map<uint32_t, Module::File*> cu_files;
|
||||
DwarfLineToModule h(&m, "/", &lines, &cu_files);
|
||||
|
||||
h.DefineFile("filename1", 1, 0, 0, 0);
|
||||
h.AddLine(0, 0xf2, 1, 58802211, 0); // should be omitted
|
||||
h.AddLine(0xf2, 0xb9, 1, 78958222, 0); // should be omitted
|
||||
h.AddLine(0xf2 + 0xb9, 0xf7, 1, 64861892, 0); // should be omitted
|
||||
h.AddLine(0x4e4d271e, 9, 1, 67355743, 0); // should be recorded
|
||||
h.AddLine(0xdfb5a72d, 30, 1, 23365776, 0); // should be recorded
|
||||
h.AddLine(0, 0x64, 1, 76196762, 0); // should be omitted
|
||||
h.AddLine(0x64, 0x33, 1, 71066611, 0); // should be omitted
|
||||
h.AddLine(0x64 + 0x33, 0xe3, 1, 61749337, 0); // should be omitted
|
||||
|
||||
ASSERT_EQ(2U, lines.size());
|
||||
EXPECT_EQ(67355743, lines[0].number);
|
||||
EXPECT_EQ(23365776, lines[1].number);
|
||||
}
|
||||
59
externals/breakpad/src/common/dwarf_range_list_handler.cc
vendored
Normal file
59
externals/breakpad/src/common/dwarf_range_list_handler.cc
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Copyright 2018 Google LLC
|
||||
//
|
||||
// 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 LLC 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: Gabriele Svelto <gsvelto@mozilla.com>
|
||||
// <gabriele.svelto@gmail.com>
|
||||
|
||||
// dwarf_range_list_handler.cc: Implementation of DwarfRangeListHandler class.
|
||||
// See dwarf_range_list_handler.h for details.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "common/dwarf_range_list_handler.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
void DwarfRangeListHandler::AddRange(uint64_t begin, uint64_t end) {
|
||||
Module::Range r(begin, end - begin);
|
||||
|
||||
ranges_->push_back(r);
|
||||
}
|
||||
|
||||
void DwarfRangeListHandler::Finish() {
|
||||
std::sort(ranges_->begin(), ranges_->end(),
|
||||
[](const Module::Range& a, const Module::Range& b) {
|
||||
return a.address < b.address;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
71
externals/breakpad/src/common/dwarf_range_list_handler.h
vendored
Normal file
71
externals/breakpad/src/common/dwarf_range_list_handler.h
vendored
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2018 Google LLC
|
||||
//
|
||||
// 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 LLC 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: Gabriele Svelto <gsvelto@mozilla.com>
|
||||
// <gabriele.svelto@gmail.com>
|
||||
|
||||
// The DwarfRangeListHandler class accepts rangelist data from a DWARF parser
|
||||
// and adds it to a google_breakpad::Function or other objects supporting
|
||||
// ranges.
|
||||
|
||||
#ifndef COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H
|
||||
#define COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "common/module.h"
|
||||
#include "common/dwarf/dwarf2reader.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A class for producing a vector of google_breakpad::Module::Range
|
||||
// instances from a parsed DWARF range list.
|
||||
|
||||
class DwarfRangeListHandler: public RangeListHandler {
|
||||
public:
|
||||
DwarfRangeListHandler(vector<Module::Range>* ranges)
|
||||
: ranges_(ranges) { }
|
||||
|
||||
~DwarfRangeListHandler() { }
|
||||
|
||||
// Add a range to the list
|
||||
void AddRange(uint64_t begin, uint64_t end);
|
||||
|
||||
// Sort the ranges so that they are in ascending order of starting address
|
||||
void Finish();
|
||||
|
||||
private:
|
||||
// The list of ranges to be populated
|
||||
vector<Module::Range>* ranges_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_DWARF_RANGE_LIST_HANDLER_H
|
||||
223
externals/breakpad/src/common/language.cc
vendored
Normal file
223
externals/breakpad/src/common/language.cc
vendored
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// language.cc: Subclasses and singletons for google_breakpad::Language.
|
||||
// See language.h for details.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/language.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <array>
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_RUSTC_DEMANGLE)
|
||||
#include <rustc_demangle.h>
|
||||
#endif
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace {
|
||||
|
||||
string MakeQualifiedNameWithSeparator(const string& parent_name,
|
||||
const char* separator,
|
||||
const string& name) {
|
||||
if (parent_name.empty()) {
|
||||
return name;
|
||||
}
|
||||
|
||||
return parent_name + separator + name;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// C++ language-specific operations.
|
||||
class CPPLanguage: public Language {
|
||||
public:
|
||||
CPPLanguage() {}
|
||||
|
||||
string MakeQualifiedName(const string& parent_name,
|
||||
const string& name) const {
|
||||
return MakeQualifiedNameWithSeparator(parent_name, "::", name);
|
||||
}
|
||||
|
||||
virtual DemangleResult DemangleName(const string& mangled,
|
||||
string* demangled) const {
|
||||
#if defined(__ANDROID__)
|
||||
// Android NDK doesn't provide abi::__cxa_demangle.
|
||||
demangled->clear();
|
||||
return kDontDemangle;
|
||||
#else
|
||||
// Attempting to demangle non-C++ symbols with the C++ demangler would print
|
||||
// warnings and fail, so return kDontDemangle for these.
|
||||
if (!IsMangledName(mangled)) {
|
||||
demangled->clear();
|
||||
return kDontDemangle;
|
||||
}
|
||||
|
||||
int status;
|
||||
char* demangled_c =
|
||||
abi::__cxa_demangle(mangled.c_str(), NULL, NULL, &status);
|
||||
|
||||
DemangleResult result;
|
||||
if (status == 0) {
|
||||
result = kDemangleSuccess;
|
||||
demangled->assign(demangled_c);
|
||||
} else {
|
||||
result = kDemangleFailure;
|
||||
demangled->clear();
|
||||
}
|
||||
|
||||
if (demangled_c) {
|
||||
free(reinterpret_cast<void*>(demangled_c));
|
||||
}
|
||||
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
static bool IsMangledName(const string& name) {
|
||||
// NOTE: For proper cross-compilation support, this should depend on target
|
||||
// binary's platform, not current build platform.
|
||||
#if defined(__APPLE__)
|
||||
// Mac C++ symbols can have up to 4 underscores, followed by a "Z".
|
||||
// Non-C++ symbols are not coded that way, but may have leading underscores.
|
||||
size_t i = name.find_first_not_of('_');
|
||||
return i > 0 && i != string::npos && i <= 4 && name[i] == 'Z';
|
||||
#else
|
||||
// Linux C++ symbols always start with "_Z".
|
||||
return name.size() > 2 && name[0] == '_' && name[1] == 'Z';
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
CPPLanguage CPPLanguageSingleton;
|
||||
|
||||
// Java language-specific operations.
|
||||
class JavaLanguage: public Language {
|
||||
public:
|
||||
JavaLanguage() {}
|
||||
|
||||
string MakeQualifiedName(const string& parent_name,
|
||||
const string& name) const {
|
||||
return MakeQualifiedNameWithSeparator(parent_name, ".", name);
|
||||
}
|
||||
};
|
||||
|
||||
JavaLanguage JavaLanguageSingleton;
|
||||
|
||||
// Swift language-specific operations.
|
||||
class SwiftLanguage: public Language {
|
||||
public:
|
||||
SwiftLanguage() {}
|
||||
|
||||
string MakeQualifiedName(const string& parent_name,
|
||||
const string& name) const {
|
||||
return MakeQualifiedNameWithSeparator(parent_name, ".", name);
|
||||
}
|
||||
|
||||
virtual DemangleResult DemangleName(const string& mangled,
|
||||
string* demangled) const {
|
||||
// There is no programmatic interface to a Swift demangler. Pass through the
|
||||
// mangled form because it encodes more information than the qualified name
|
||||
// that would have been built by MakeQualifiedName(). The output can be
|
||||
// post-processed by xcrun swift-demangle to transform mangled Swift names
|
||||
// into something more readable.
|
||||
demangled->assign(mangled);
|
||||
return kDemangleSuccess;
|
||||
}
|
||||
};
|
||||
|
||||
SwiftLanguage SwiftLanguageSingleton;
|
||||
|
||||
// Rust language-specific operations.
|
||||
class RustLanguage: public Language {
|
||||
public:
|
||||
RustLanguage() {}
|
||||
|
||||
string MakeQualifiedName(const string& parent_name,
|
||||
const string& name) const {
|
||||
return MakeQualifiedNameWithSeparator(parent_name, ".", name);
|
||||
}
|
||||
|
||||
virtual DemangleResult DemangleName(const string& mangled,
|
||||
string* demangled) const {
|
||||
// Rust names use GCC C++ name mangling, but demangling them with
|
||||
// abi_demangle doesn't produce stellar results due to them having
|
||||
// another layer of encoding.
|
||||
// If callers provide rustc-demangle, use that.
|
||||
#if defined(HAVE_RUSTC_DEMANGLE)
|
||||
std::array<char, 1 * 1024 * 1024> rustc_demangled;
|
||||
if (rustc_demangle(mangled.c_str(), rustc_demangled.data(),
|
||||
rustc_demangled.size()) == 0) {
|
||||
return kDemangleFailure;
|
||||
}
|
||||
demangled->assign(rustc_demangled.data());
|
||||
#else
|
||||
// Otherwise, pass through the mangled name so callers can demangle
|
||||
// after the fact.
|
||||
demangled->assign(mangled);
|
||||
#endif
|
||||
return kDemangleSuccess;
|
||||
}
|
||||
};
|
||||
|
||||
RustLanguage RustLanguageSingleton;
|
||||
|
||||
// Assembler language-specific operations.
|
||||
class AssemblerLanguage: public Language {
|
||||
public:
|
||||
AssemblerLanguage() {}
|
||||
|
||||
bool HasFunctions() const { return false; }
|
||||
string MakeQualifiedName(const string& parent_name,
|
||||
const string& name) const {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
AssemblerLanguage AssemblerLanguageSingleton;
|
||||
|
||||
const Language * const Language::CPlusPlus = &CPPLanguageSingleton;
|
||||
const Language * const Language::Java = &JavaLanguageSingleton;
|
||||
const Language * const Language::Swift = &SwiftLanguageSingleton;
|
||||
const Language * const Language::Rust = &RustLanguageSingleton;
|
||||
const Language * const Language::Assembler = &AssemblerLanguageSingleton;
|
||||
|
||||
} // namespace google_breakpad
|
||||
104
externals/breakpad/src/common/language.h
vendored
Normal file
104
externals/breakpad/src/common/language.h
vendored
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
|
||||
|
||||
// language.h: Define google_breakpad::Language. Instances of
|
||||
// subclasses of this class provide language-appropriate operations
|
||||
// for the Breakpad symbol dumper.
|
||||
|
||||
#ifndef COMMON_LINUX_LANGUAGE_H__
|
||||
#define COMMON_LINUX_LANGUAGE_H__
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// An abstract base class for language-specific operations. We choose
|
||||
// an instance of a subclass of this when we find the CU's language.
|
||||
// This class's definitions are appropriate for CUs with no specified
|
||||
// language.
|
||||
class Language {
|
||||
public:
|
||||
// A base class destructor should be either public and virtual,
|
||||
// or protected and nonvirtual.
|
||||
virtual ~Language() {}
|
||||
|
||||
// Return true if this language has functions to which we can assign
|
||||
// line numbers. (Debugging info for assembly language, for example,
|
||||
// can have source location information, but does not have functions
|
||||
// recorded using DW_TAG_subprogram DIEs.)
|
||||
virtual bool HasFunctions() const { return true; }
|
||||
|
||||
// Construct a fully-qualified, language-appropriate form of NAME,
|
||||
// given that PARENT_NAME is the name of the construct enclosing
|
||||
// NAME. If PARENT_NAME is the empty string, then NAME is a
|
||||
// top-level name.
|
||||
//
|
||||
// This API sort of assumes that a fully-qualified name is always
|
||||
// some simple textual composition of the unqualified name and its
|
||||
// parent's name, and that we don't need to know anything else about
|
||||
// the parent or the child (say, their DIEs' tags) to do the job.
|
||||
// This is true for the languages we support at the moment, and
|
||||
// keeps things concrete. Perhaps a more refined operation would
|
||||
// take into account the parent and child DIE types, allow languages
|
||||
// to use their own data type for complex parent names, etc. But if
|
||||
// C++ doesn't need all that, who would?
|
||||
virtual string MakeQualifiedName (const string& parent_name,
|
||||
const string& name) const = 0;
|
||||
|
||||
enum DemangleResult {
|
||||
// Demangling was not performed because it’s not appropriate to attempt.
|
||||
kDontDemangle = -1,
|
||||
|
||||
kDemangleSuccess,
|
||||
kDemangleFailure,
|
||||
};
|
||||
|
||||
// Wraps abi::__cxa_demangle() or similar for languages where appropriate.
|
||||
virtual DemangleResult DemangleName(const string& mangled,
|
||||
string* demangled) const {
|
||||
demangled->clear();
|
||||
return kDontDemangle;
|
||||
}
|
||||
|
||||
// Instances for specific languages.
|
||||
static const Language * const CPlusPlus,
|
||||
* const Java,
|
||||
* const Swift,
|
||||
* const Rust,
|
||||
* const Assembler;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_LANGUAGE_H__
|
||||
645
externals/breakpad/src/common/linux/breakpad_getcontext.S
vendored
Normal file
645
externals/breakpad/src/common/linux/breakpad_getcontext.S
vendored
Normal file
|
|
@ -0,0 +1,645 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// A minimalistic implementation of getcontext() to be used by
|
||||
// Google Breakpad when getcontext() is not available in libc.
|
||||
|
||||
#include "common/linux/ucontext_constants.h"
|
||||
|
||||
/* int getcontext (ucontext_t* ucp) */
|
||||
|
||||
#if defined(__arm__)
|
||||
|
||||
.text
|
||||
.global breakpad_getcontext
|
||||
.hidden breakpad_getcontext
|
||||
.type breakpad_getcontext, #function
|
||||
.align 0
|
||||
.fnstart
|
||||
breakpad_getcontext:
|
||||
|
||||
/* First, save r4-r11 */
|
||||
add r1, r0, #(MCONTEXT_GREGS_OFFSET + 4*4)
|
||||
stm r1, {r4-r11}
|
||||
|
||||
/* r12 is a scratch register, don't save it */
|
||||
|
||||
/* Save sp and lr explicitly. */
|
||||
/* - sp can't be stored with stmia in Thumb-2 */
|
||||
/* - STM instructions that store sp and pc are deprecated in ARM */
|
||||
str sp, [r0, #(MCONTEXT_GREGS_OFFSET + 13*4)]
|
||||
str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)]
|
||||
|
||||
/* Save the caller's address in 'pc' */
|
||||
str lr, [r0, #(MCONTEXT_GREGS_OFFSET + 15*4)]
|
||||
|
||||
/* Save ucontext_t* pointer across next call */
|
||||
mov r4, r0
|
||||
|
||||
/* Call sigprocmask(SIG_BLOCK, NULL, &(ucontext->uc_sigmask)) */
|
||||
mov r0, #0 /* SIG_BLOCK */
|
||||
mov r1, #0 /* NULL */
|
||||
add r2, r4, #UCONTEXT_SIGMASK_OFFSET
|
||||
bl sigprocmask(PLT)
|
||||
|
||||
/* Intentionally do not save the FPU state here. This is because on
|
||||
* Linux/ARM, one should instead use ptrace(PTRACE_GETFPREGS) or
|
||||
* ptrace(PTRACE_GETVFPREGS) to get it.
|
||||
*
|
||||
* Note that a real implementation of getcontext() would need to save
|
||||
* this here to allow setcontext()/swapcontext() to work correctly.
|
||||
*/
|
||||
|
||||
/* Restore the values of r4 and lr */
|
||||
mov r0, r4
|
||||
ldr lr, [r0, #(MCONTEXT_GREGS_OFFSET + 14*4)]
|
||||
ldr r4, [r0, #(MCONTEXT_GREGS_OFFSET + 4*4)]
|
||||
|
||||
/* Return 0 */
|
||||
mov r0, #0
|
||||
bx lr
|
||||
|
||||
.fnend
|
||||
.size breakpad_getcontext, . - breakpad_getcontext
|
||||
|
||||
#elif defined(__aarch64__)
|
||||
|
||||
#if defined(__ARM_FEATURE_PAC_DEFAULT) && __ARM_FEATURE_PAC_DEFAULT
|
||||
// ENABLE_PAUTH must be defined to 1 since this value will be used in
|
||||
// bitwise-shift later!
|
||||
#define ENABLE_PAUTH 1
|
||||
|
||||
#if ((__ARM_FEATURE_PAC_DEFAULT&((1<<0)|(1<<1)))==0)
|
||||
#error Pointer authentication defines no valid key!
|
||||
#endif
|
||||
#else
|
||||
#define ENABLE_PAUTH 0
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT==1)
|
||||
// ENABLE_BTI must be defined to 1 since this value will be used in
|
||||
// bitwise-shift later!
|
||||
#define ENABLE_BTI 1
|
||||
#else
|
||||
#define ENABLE_BTI 0
|
||||
#endif
|
||||
|
||||
|
||||
// Although Pointer Authentication and Branch Target Instructions are technically
|
||||
// seperate features they work together, i.e. the paciasp and pacibsp instructions
|
||||
// serve as BTI landing pads.
|
||||
// Therefore PA-instructions are enabled when PA _or_ BTI is enabled!
|
||||
#if ENABLE_PAUTH || ENABLE_BTI
|
||||
// See section "Pointer Authentication" of
|
||||
// https://developer.arm.com/documentation/101028/0012/5--Feature-test-macros
|
||||
// for details how to interpret __ARM_FEATURE_PAC_DEFAULT
|
||||
#if (__ARM_FEATURE_PAC_DEFAULT & (1<<0))
|
||||
#define PAUTH_SIGN_SP paciasp
|
||||
#define PAUTH_AUTH_SP autiasp
|
||||
#else
|
||||
#define PAUTH_SIGN_SP pacibsp
|
||||
#define PAUTH_AUTH_SP autibsp
|
||||
#endif
|
||||
#else
|
||||
#define PAUTH_SIGN_SP
|
||||
#define PAUTH_AUTH_SP
|
||||
#endif
|
||||
|
||||
#define _NSIG 64
|
||||
#define __NR_rt_sigprocmask 135
|
||||
|
||||
.text
|
||||
.global breakpad_getcontext
|
||||
.hidden breakpad_getcontext
|
||||
.type breakpad_getcontext, #function
|
||||
.align 4
|
||||
.cfi_startproc
|
||||
breakpad_getcontext:
|
||||
|
||||
PAUTH_SIGN_SP
|
||||
|
||||
/* The saved context will return to the getcontext() call point
|
||||
with a return value of 0 */
|
||||
str xzr, [x0, MCONTEXT_GREGS_OFFSET + 0 * REGISTER_SIZE]
|
||||
|
||||
stp x18, x19, [x0, MCONTEXT_GREGS_OFFSET + 18 * REGISTER_SIZE]
|
||||
stp x20, x21, [x0, MCONTEXT_GREGS_OFFSET + 20 * REGISTER_SIZE]
|
||||
stp x22, x23, [x0, MCONTEXT_GREGS_OFFSET + 22 * REGISTER_SIZE]
|
||||
stp x24, x25, [x0, MCONTEXT_GREGS_OFFSET + 24 * REGISTER_SIZE]
|
||||
stp x26, x27, [x0, MCONTEXT_GREGS_OFFSET + 26 * REGISTER_SIZE]
|
||||
stp x28, x29, [x0, MCONTEXT_GREGS_OFFSET + 28 * REGISTER_SIZE]
|
||||
str x30, [x0, MCONTEXT_GREGS_OFFSET + 30 * REGISTER_SIZE]
|
||||
|
||||
/* Place LR into the saved PC, this will ensure that when
|
||||
switching to this saved context with setcontext() control
|
||||
will pass back to the caller of getcontext(), we have
|
||||
already arranged to return the appropriate return value in x0
|
||||
above. */
|
||||
str x30, [x0, MCONTEXT_PC_OFFSET]
|
||||
|
||||
/* Save the current SP */
|
||||
mov x2, sp
|
||||
str x2, [x0, MCONTEXT_SP_OFFSET]
|
||||
|
||||
/* Initialize the pstate. */
|
||||
str xzr, [x0, MCONTEXT_PSTATE_OFFSET]
|
||||
|
||||
/* Figure out where to place the first context extension
|
||||
block. */
|
||||
add x2, x0, #MCONTEXT_EXTENSION_OFFSET
|
||||
|
||||
/* Write the context extension fpsimd header. */
|
||||
mov w3, #(FPSIMD_MAGIC & 0xffff)
|
||||
movk w3, #(FPSIMD_MAGIC >> 16), lsl #16
|
||||
str w3, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET]
|
||||
mov w3, #FPSIMD_CONTEXT_SIZE
|
||||
str w3, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET]
|
||||
|
||||
/* Fill in the FP SIMD context. */
|
||||
add x3, x2, #(FPSIMD_CONTEXT_VREGS_OFFSET + 8 * SIMD_REGISTER_SIZE)
|
||||
stp d8, d9, [x3], #(2 * SIMD_REGISTER_SIZE)
|
||||
stp d10, d11, [x3], #(2 * SIMD_REGISTER_SIZE)
|
||||
stp d12, d13, [x3], #(2 * SIMD_REGISTER_SIZE)
|
||||
stp d14, d15, [x3], #(2 * SIMD_REGISTER_SIZE)
|
||||
|
||||
add x3, x2, FPSIMD_CONTEXT_FPSR_OFFSET
|
||||
|
||||
mrs x4, fpsr
|
||||
str w4, [x3]
|
||||
|
||||
mrs x4, fpcr
|
||||
str w4, [x3, FPSIMD_CONTEXT_FPCR_OFFSET - FPSIMD_CONTEXT_FPSR_OFFSET]
|
||||
|
||||
/* Write the termination context extension header. */
|
||||
add x2, x2, #FPSIMD_CONTEXT_SIZE
|
||||
|
||||
str xzr, [x2, #FPSIMD_CONTEXT_MAGIC_OFFSET]
|
||||
str xzr, [x2, #FPSIMD_CONTEXT_SIZE_OFFSET]
|
||||
|
||||
/* Grab the signal mask */
|
||||
/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
|
||||
add x2, x0, #UCONTEXT_SIGMASK_OFFSET
|
||||
mov x0, #0 /* SIG_BLOCK */
|
||||
mov x1, #0 /* NULL */
|
||||
mov x3, #(_NSIG / 8)
|
||||
mov x8, #__NR_rt_sigprocmask
|
||||
svc 0
|
||||
|
||||
/* Return x0 for success */
|
||||
mov x0, 0
|
||||
|
||||
PAUTH_AUTH_SP
|
||||
|
||||
ret
|
||||
|
||||
.cfi_endproc
|
||||
.size breakpad_getcontext, . - breakpad_getcontext
|
||||
|
||||
#elif defined(__i386__)
|
||||
|
||||
.text
|
||||
.global breakpad_getcontext
|
||||
.hidden breakpad_getcontext
|
||||
.align 4
|
||||
.type breakpad_getcontext, @function
|
||||
|
||||
breakpad_getcontext:
|
||||
|
||||
movl 4(%esp), %eax /* eax = uc */
|
||||
|
||||
/* Save register values */
|
||||
movl %ecx, MCONTEXT_ECX_OFFSET(%eax)
|
||||
movl %edx, MCONTEXT_EDX_OFFSET(%eax)
|
||||
movl %ebx, MCONTEXT_EBX_OFFSET(%eax)
|
||||
movl %edi, MCONTEXT_EDI_OFFSET(%eax)
|
||||
movl %esi, MCONTEXT_ESI_OFFSET(%eax)
|
||||
movl %ebp, MCONTEXT_EBP_OFFSET(%eax)
|
||||
|
||||
movl (%esp), %edx /* return address */
|
||||
lea 4(%esp), %ecx /* exclude return address from stack */
|
||||
mov %edx, MCONTEXT_EIP_OFFSET(%eax)
|
||||
mov %ecx, MCONTEXT_ESP_OFFSET(%eax)
|
||||
|
||||
xorl %ecx, %ecx
|
||||
movw %fs, %cx
|
||||
mov %ecx, MCONTEXT_FS_OFFSET(%eax)
|
||||
|
||||
movl $0, MCONTEXT_EAX_OFFSET(%eax)
|
||||
|
||||
/* Save floating point state to fpregstate, then update
|
||||
* the fpregs pointer to point to it */
|
||||
leal UCONTEXT_FPREGS_MEM_OFFSET(%eax), %ecx
|
||||
fnstenv (%ecx)
|
||||
fldenv (%ecx)
|
||||
mov %ecx, UCONTEXT_FPREGS_OFFSET(%eax)
|
||||
|
||||
/* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */
|
||||
leal UCONTEXT_SIGMASK_OFFSET(%eax), %edx
|
||||
xorl %ecx, %ecx
|
||||
push %edx /* &uc->uc_sigmask */
|
||||
push %ecx /* NULL */
|
||||
push %ecx /* SIGBLOCK == 0 on i386 */
|
||||
call sigprocmask@PLT
|
||||
addl $12, %esp
|
||||
|
||||
movl $0, %eax
|
||||
ret
|
||||
|
||||
.size breakpad_getcontext, . - breakpad_getcontext
|
||||
|
||||
#elif defined(__mips__)
|
||||
|
||||
// This implementation is inspired by implementation of getcontext in glibc.
|
||||
#include <asm-mips/asm.h>
|
||||
#include <asm-mips/regdef.h>
|
||||
#if _MIPS_SIM == _ABIO32
|
||||
#include <asm-mips/fpregdef.h>
|
||||
#endif
|
||||
|
||||
// from asm-mips/asm.h
|
||||
#if _MIPS_SIM == _ABIO32
|
||||
#define ALSZ 7
|
||||
#define ALMASK ~7
|
||||
#define SZREG 4
|
||||
#else // _MIPS_SIM != _ABIO32
|
||||
#define ALSZ 15
|
||||
#define ALMASK ~15
|
||||
#define SZREG 8
|
||||
#endif
|
||||
|
||||
#include <asm/unistd.h> // for __NR_rt_sigprocmask
|
||||
|
||||
#define _NSIG8 128 / 8
|
||||
#define SIG_BLOCK 1
|
||||
|
||||
|
||||
.text
|
||||
LOCALS_NUM = 1 // save gp on stack
|
||||
FRAME_SIZE = ((LOCALS_NUM * SZREG) + ALSZ) & ALMASK
|
||||
|
||||
GP_FRAME_OFFSET = FRAME_SIZE - (1 * SZREG)
|
||||
MCONTEXT_REG_SIZE = 8
|
||||
|
||||
#if _MIPS_SIM == _ABIO32
|
||||
|
||||
NESTED (breakpad_getcontext, FRAME_SIZE, ra)
|
||||
.mask 0x00000000, 0
|
||||
.fmask 0x00000000, 0
|
||||
|
||||
.set noreorder
|
||||
.cpload t9
|
||||
.set reorder
|
||||
|
||||
move a2, sp
|
||||
#define _SP a2
|
||||
|
||||
addiu sp, -FRAME_SIZE
|
||||
.cprestore GP_FRAME_OFFSET
|
||||
|
||||
sw s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sw s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sw s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sw s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sw s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sw s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sw s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sw s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sw _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sw fp, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sw ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sw ra, MCONTEXT_PC_OFFSET(a0)
|
||||
|
||||
#ifdef __mips_hard_float
|
||||
s.d fs0, (20 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
s.d fs1, (22 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
s.d fs2, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
s.d fs3, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
s.d fs4, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
s.d fs5, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
|
||||
cfc1 v1, fcr31
|
||||
sw v1, MCONTEXT_FPC_CSR(a0)
|
||||
#endif // __mips_hard_float
|
||||
|
||||
/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
|
||||
li a3, _NSIG8
|
||||
addu a2, a0, UCONTEXT_SIGMASK_OFFSET
|
||||
move a1, zero
|
||||
li a0, SIG_BLOCK
|
||||
li v0, __NR_rt_sigprocmask
|
||||
syscall
|
||||
|
||||
addiu sp, FRAME_SIZE
|
||||
jr ra
|
||||
|
||||
END (breakpad_getcontext)
|
||||
#else
|
||||
|
||||
#ifndef NESTED
|
||||
/*
|
||||
* NESTED - declare nested routine entry point
|
||||
*/
|
||||
#define NESTED(symbol, framesize, rpc) \
|
||||
.globl symbol; \
|
||||
.align 2; \
|
||||
.type symbol,@function; \
|
||||
.ent symbol,0; \
|
||||
symbol: .frame sp, framesize, rpc;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* END - mark end of function
|
||||
*/
|
||||
#ifndef END
|
||||
# define END(function) \
|
||||
.end function; \
|
||||
.size function,.-function
|
||||
#endif
|
||||
|
||||
/* int getcontext (ucontext_t* ucp) */
|
||||
|
||||
NESTED (breakpad_getcontext, FRAME_SIZE, ra)
|
||||
.mask 0x10000000, 0
|
||||
.fmask 0x00000000, 0
|
||||
|
||||
move a2, sp
|
||||
#define _SP a2
|
||||
move a3, gp
|
||||
#define _GP a3
|
||||
|
||||
daddiu sp, -FRAME_SIZE
|
||||
.cpsetup $25, GP_FRAME_OFFSET, breakpad_getcontext
|
||||
|
||||
/* Store a magic flag. */
|
||||
li v1, 1
|
||||
sd v1, (0 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0) /* zero */
|
||||
|
||||
sd s0, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd s1, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd s2, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd s3, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd s4, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd s5, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd s6, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd s7, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd _GP, (28 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd _SP, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd s8, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd ra, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)(a0)
|
||||
sd ra, MCONTEXT_PC_OFFSET(a0)
|
||||
|
||||
#ifdef __mips_hard_float
|
||||
s.d $f24, (24 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
s.d $f25, (25 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
s.d $f26, (26 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
s.d $f27, (27 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
s.d $f28, (28 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
s.d $f29, (29 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
s.d $f30, (30 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
s.d $f31, (31 * MCONTEXT_REG_SIZE + MCONTEXT_FPREGS_OFFSET)(a0)
|
||||
|
||||
cfc1 v1, $31
|
||||
sw v1, MCONTEXT_FPC_CSR(a0)
|
||||
#endif /* __mips_hard_float */
|
||||
|
||||
/* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
|
||||
li a3, _NSIG8
|
||||
daddu a2, a0, UCONTEXT_SIGMASK_OFFSET
|
||||
move a1, zero
|
||||
li a0, SIG_BLOCK
|
||||
|
||||
li v0, __NR_rt_sigprocmask
|
||||
syscall
|
||||
|
||||
.cpreturn
|
||||
daddiu sp, FRAME_SIZE
|
||||
move v0, zero
|
||||
jr ra
|
||||
|
||||
END (breakpad_getcontext)
|
||||
#endif // _MIPS_SIM == _ABIO32
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
/* The x64 implementation of breakpad_getcontext was derived in part
|
||||
from the implementation of libunwind which requires the following
|
||||
notice. */
|
||||
/* libunwind - a platform-independent unwind library
|
||||
Copyright (C) 2008 Google, Inc
|
||||
Contributed by Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
|
||||
|
||||
This file is part of libunwind.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
|
||||
.text
|
||||
.global breakpad_getcontext
|
||||
.hidden breakpad_getcontext
|
||||
.align 4
|
||||
.type breakpad_getcontext, @function
|
||||
|
||||
breakpad_getcontext:
|
||||
.cfi_startproc
|
||||
|
||||
/* Callee saved: RBX, RBP, R12-R15 */
|
||||
movq %r12, MCONTEXT_GREGS_R12(%rdi)
|
||||
movq %r13, MCONTEXT_GREGS_R13(%rdi)
|
||||
movq %r14, MCONTEXT_GREGS_R14(%rdi)
|
||||
movq %r15, MCONTEXT_GREGS_R15(%rdi)
|
||||
movq %rbp, MCONTEXT_GREGS_RBP(%rdi)
|
||||
movq %rbx, MCONTEXT_GREGS_RBX(%rdi)
|
||||
|
||||
/* Save argument registers (not strictly needed, but setcontext
|
||||
restores them, so don't restore garbage). */
|
||||
movq %r8, MCONTEXT_GREGS_R8(%rdi)
|
||||
movq %r9, MCONTEXT_GREGS_R9(%rdi)
|
||||
movq %rdi, MCONTEXT_GREGS_RDI(%rdi)
|
||||
movq %rsi, MCONTEXT_GREGS_RSI(%rdi)
|
||||
movq %rdx, MCONTEXT_GREGS_RDX(%rdi)
|
||||
movq %rax, MCONTEXT_GREGS_RAX(%rdi)
|
||||
movq %rcx, MCONTEXT_GREGS_RCX(%rdi)
|
||||
|
||||
/* Save fp state (not needed, except for setcontext not
|
||||
restoring garbage). */
|
||||
leaq MCONTEXT_FPREGS_MEM(%rdi),%r8
|
||||
movq %r8, MCONTEXT_FPREGS_PTR(%rdi)
|
||||
fnstenv (%r8)
|
||||
stmxcsr FPREGS_OFFSET_MXCSR(%r8)
|
||||
|
||||
leaq 8(%rsp), %rax /* exclude this call. */
|
||||
movq %rax, MCONTEXT_GREGS_RSP(%rdi)
|
||||
|
||||
movq 0(%rsp), %rax
|
||||
movq %rax, MCONTEXT_GREGS_RIP(%rdi)
|
||||
|
||||
/* Save signal mask: sigprocmask(SIGBLOCK, NULL, &uc->uc_sigmask) */
|
||||
leaq UCONTEXT_SIGMASK_OFFSET(%rdi), %rdx // arg3
|
||||
xorq %rsi, %rsi // arg2 NULL
|
||||
xorq %rdi, %rdi // arg1 SIGBLOCK == 0
|
||||
call sigprocmask@PLT
|
||||
|
||||
/* Always return 0 for success, even if sigprocmask failed. */
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
.cfi_endproc
|
||||
.size breakpad_getcontext, . - breakpad_getcontext
|
||||
|
||||
#elif defined(__riscv)
|
||||
|
||||
# define SIG_BLOCK 0
|
||||
# define _NSIG8 8
|
||||
# define __NR_rt_sigprocmask 135
|
||||
|
||||
.text
|
||||
.globl breakpad_getcontext
|
||||
.type breakpad_getcontext, @function
|
||||
.align 0
|
||||
.cfi_startproc
|
||||
breakpad_getcontext:
|
||||
REG_S ra, MCONTEXT_GREGS_PC(a0)
|
||||
REG_S ra, MCONTEXT_GREGS_RA(a0)
|
||||
REG_S sp, MCONTEXT_GREGS_SP(a0)
|
||||
REG_S gp, MCONTEXT_GREGS_SP(a0)
|
||||
REG_S tp, MCONTEXT_GREGS_TP(a0)
|
||||
REG_S t0, MCONTEXT_GREGS_T0(a0)
|
||||
REG_S t1, MCONTEXT_GREGS_T1(a0)
|
||||
REG_S t2, MCONTEXT_GREGS_T2(a0)
|
||||
REG_S s0, MCONTEXT_GREGS_S0(a0)
|
||||
REG_S s1, MCONTEXT_GREGS_S1(a0)
|
||||
REG_S a0, MCONTEXT_GREGS_A0(a0)
|
||||
REG_S a1, MCONTEXT_GREGS_A1(a0)
|
||||
REG_S a2, MCONTEXT_GREGS_A2(a0)
|
||||
REG_S a3, MCONTEXT_GREGS_A3(a0)
|
||||
REG_S a4, MCONTEXT_GREGS_A4(a0)
|
||||
REG_S a5, MCONTEXT_GREGS_A5(a0)
|
||||
REG_S a6, MCONTEXT_GREGS_A6(a0)
|
||||
REG_S a7, MCONTEXT_GREGS_A7(a0)
|
||||
REG_S s2, MCONTEXT_GREGS_S2(a0)
|
||||
REG_S s3, MCONTEXT_GREGS_S3(a0)
|
||||
REG_S s4, MCONTEXT_GREGS_S4(a0)
|
||||
REG_S s5, MCONTEXT_GREGS_S5(a0)
|
||||
REG_S s6, MCONTEXT_GREGS_S6(a0)
|
||||
REG_S s7, MCONTEXT_GREGS_S7(a0)
|
||||
REG_S s8, MCONTEXT_GREGS_S8(a0)
|
||||
REG_S s9, MCONTEXT_GREGS_S9(a0)
|
||||
REG_S s10, MCONTEXT_GREGS_S10(a0)
|
||||
REG_S s11, MCONTEXT_GREGS_S11(a0)
|
||||
REG_S t3, MCONTEXT_GREGS_T3(a0)
|
||||
REG_S t4, MCONTEXT_GREGS_T4(a0)
|
||||
REG_S t5, MCONTEXT_GREGS_T5(a0)
|
||||
REG_S t6 , MCONTEXT_GREGS_T6(a0)
|
||||
# ifndef __riscv_float_abi_soft
|
||||
frsr a1
|
||||
|
||||
FREG_S ft0, MCONTEXT_FPREGS_FT0(a0)
|
||||
FREG_S ft1, MCONTEXT_FPREGS_FT1(a0)
|
||||
FREG_S ft2, MCONTEXT_FPREGS_FT2(a0)
|
||||
FREG_S ft3, MCONTEXT_FPREGS_FT3(a0)
|
||||
FREG_S ft4, MCONTEXT_FPREGS_FT4(a0)
|
||||
FREG_S ft5, MCONTEXT_FPREGS_FT5(a0)
|
||||
FREG_S ft6, MCONTEXT_FPREGS_FT6(a0)
|
||||
FREG_S ft7, MCONTEXT_FPREGS_FT7(a0)
|
||||
FREG_S fs0, MCONTEXT_FPREGS_FS0(a0)
|
||||
FREG_S fs1, MCONTEXT_FPREGS_FS1(a0)
|
||||
FREG_S fa0, MCONTEXT_FPREGS_FA0(a0)
|
||||
FREG_S fa1, MCONTEXT_FPREGS_FA1(a0)
|
||||
FREG_S fa2, MCONTEXT_FPREGS_FA2(a0)
|
||||
FREG_S fa3, MCONTEXT_FPREGS_FA3(a0)
|
||||
FREG_S fa4, MCONTEXT_FPREGS_FA4(a0)
|
||||
FREG_S fa5, MCONTEXT_FPREGS_FA5(a0)
|
||||
FREG_S fa6, MCONTEXT_FPREGS_FA6(a0)
|
||||
FREG_S fa7, MCONTEXT_FPREGS_FA7(a0)
|
||||
FREG_S fs2, MCONTEXT_FPREGS_FS2(a0)
|
||||
FREG_S fs3, MCONTEXT_FPREGS_FS3(a0)
|
||||
FREG_S fs4, MCONTEXT_FPREGS_FS4(a0)
|
||||
FREG_S fs5, MCONTEXT_FPREGS_FS5(a0)
|
||||
FREG_S fs6, MCONTEXT_FPREGS_FS6(a0)
|
||||
FREG_S fs7, MCONTEXT_FPREGS_FS7(a0)
|
||||
FREG_S fs8, MCONTEXT_FPREGS_FS8(a0)
|
||||
FREG_S fs9, MCONTEXT_FPREGS_FS9(a0)
|
||||
FREG_S fs10, MCONTEXT_FPREGS_FS10(a0)
|
||||
FREG_S fs11, MCONTEXT_FPREGS_FS11(a0)
|
||||
FREG_S ft8, MCONTEXT_FPREGS_FT8(a0)
|
||||
FREG_S ft9, MCONTEXT_FPREGS_FT9(a0)
|
||||
FREG_S ft10, MCONTEXT_FPREGS_FT10(a0)
|
||||
FREG_S ft11, MCONTEXT_FPREGS_FT11(a0)
|
||||
|
||||
sw a1, MCONTEXT_FPC_CSR(a0)
|
||||
# endif // __riscv_float_abi_soft
|
||||
mv a1, zero
|
||||
add a2, a0, UCONTEXT_SIGMASK_OFFSET
|
||||
li a3, _NSIG8
|
||||
mv a0, zero
|
||||
li a7, __NR_rt_sigprocmask
|
||||
ecall
|
||||
mv a0, zero
|
||||
ret
|
||||
|
||||
.cfi_endproc
|
||||
.size breakpad_getcontext, . - breakpad_getcontext
|
||||
|
||||
#else
|
||||
# error "This file has not been ported for your CPU!"
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__)
|
||||
// ENABLE_PAUTH and ENABLE_BTI would be enabled at the definition
|
||||
// of AArch64 specific breakpad_getcontext function
|
||||
#if ENABLE_PAUTH || ENABLE_BTI
|
||||
// for further information on the .note.gnu.property section see
|
||||
// https://github.com/ARM-software/abi-aa/blob/main/aaelf64/aaelf64.rst#program-property
|
||||
.pushsection .note.gnu.property, "a";
|
||||
.balign 8
|
||||
.long 4
|
||||
.long 0x10
|
||||
.long 0x5
|
||||
.asciz "GNU"
|
||||
.long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
|
||||
.long 4
|
||||
.long ((ENABLE_PAUTH)<<1) | ((ENABLE_BTI)<<0) /* PAuth and BTI */
|
||||
.long 0
|
||||
.popsection
|
||||
#endif
|
||||
#endif
|
||||
51
externals/breakpad/src/common/linux/breakpad_getcontext.h
vendored
Normal file
51
externals/breakpad/src/common/linux/breakpad_getcontext.h
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H
|
||||
#define GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H
|
||||
|
||||
#ifndef HAVE_GETCONTEXT
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// Provided by src/common/linux/breakpad_getcontext.S
|
||||
int breakpad_getcontext(ucontext_t* ucp);
|
||||
|
||||
#define getcontext(x) breakpad_getcontext(x)
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // HAVE_GETCONTEXT
|
||||
|
||||
#endif // GOOGLE_BREAKPAD_COMMON_LINUX_INCLUDE_UCONTEXT_H
|
||||
216
externals/breakpad/src/common/linux/breakpad_getcontext_unittest.cc
vendored
Normal file
216
externals/breakpad/src/common/linux/breakpad_getcontext_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC 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.
|
||||
|
||||
// asm/sigcontext.h can't be included with signal.h on glibc or
|
||||
// musl, so only compare _libc_fpstate and _fpstate on Android.
|
||||
#if defined(__ANDROID__) && defined(__x86_64__)
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <asm/sigcontext.h>
|
||||
#endif
|
||||
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/ucontext_constants.h"
|
||||
|
||||
template <int left, int right>
|
||||
struct CompileAssertEquals {
|
||||
// a compilation error here indicates left and right are not equal.
|
||||
char left_too_large[right - left];
|
||||
// a compilation error here indicates left and right are not equal.
|
||||
char right_too_large[left - right];
|
||||
};
|
||||
|
||||
#define COMPILE_ASSERT_EQ(left, right, tag) \
|
||||
CompileAssertEquals<left, right> tag;
|
||||
|
||||
TEST(AndroidUContext, GRegsOffset) {
|
||||
#if defined(__arm__)
|
||||
// There is no gregs[] array on ARM, so compare to the offset of
|
||||
// first register fields, since they're stored in order.
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.arm_r0));
|
||||
#elif defined(__aarch64__)
|
||||
// There is no gregs[] array on ARM, so compare to the offset of
|
||||
// first register fields, since they're stored in order.
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.regs[0]));
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_SP_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.sp));
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_PC_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.pc));
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_PSTATE_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.pstate));
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_EXTENSION_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.__reserved));
|
||||
#elif defined(__i386__)
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.gregs));
|
||||
#define CHECK_REG(x) \
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_##x##_OFFSET), \
|
||||
offsetof(ucontext_t,uc_mcontext.gregs[REG_##x]))
|
||||
CHECK_REG(GS);
|
||||
CHECK_REG(FS);
|
||||
CHECK_REG(ES);
|
||||
CHECK_REG(DS);
|
||||
CHECK_REG(EDI);
|
||||
CHECK_REG(ESI);
|
||||
CHECK_REG(EBP);
|
||||
CHECK_REG(ESP);
|
||||
CHECK_REG(EBX);
|
||||
CHECK_REG(EDX);
|
||||
CHECK_REG(ECX);
|
||||
CHECK_REG(EAX);
|
||||
CHECK_REG(TRAPNO);
|
||||
CHECK_REG(ERR);
|
||||
CHECK_REG(EIP);
|
||||
CHECK_REG(CS);
|
||||
CHECK_REG(EFL);
|
||||
CHECK_REG(UESP);
|
||||
CHECK_REG(SS);
|
||||
|
||||
ASSERT_EQ(static_cast<size_t>(UCONTEXT_FPREGS_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.fpregs));
|
||||
|
||||
ASSERT_EQ(static_cast<size_t>(UCONTEXT_FPREGS_MEM_OFFSET),
|
||||
offsetof(ucontext_t,__fpregs_mem));
|
||||
#elif defined(__mips__)
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.gregs));
|
||||
|
||||
// PC for mips is not part of gregs.
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_PC_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.pc));
|
||||
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPREGS_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.fpregs));
|
||||
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_FPC_CSR),
|
||||
offsetof(ucontext_t,uc_mcontext.fpc_csr));
|
||||
#elif defined(__riscv)
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.__gregs[0]));
|
||||
|
||||
#define CHECK_REG(x) \
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_##x##_OFFSET), \
|
||||
offsetof(ucontext_t,uc_mcontext.__gregs[REG_##x]))
|
||||
CHECK_REG(PC)
|
||||
CHECK_REG(RA)
|
||||
CHECK_REG(SP)
|
||||
CHECK_REG(S0)
|
||||
CHECK_REG(S1)
|
||||
CHECK_REG(S2)
|
||||
|
||||
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.__fpregs.__fcsr));
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
COMPILE_ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.gregs),
|
||||
mcontext_gregs_offset);
|
||||
#define CHECK_REG(x) \
|
||||
COMPILE_ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_##x), \
|
||||
offsetof(ucontext_t,uc_mcontext.gregs[REG_##x]), reg_##x)
|
||||
CHECK_REG(R8);
|
||||
CHECK_REG(R9);
|
||||
CHECK_REG(R10);
|
||||
CHECK_REG(R11);
|
||||
CHECK_REG(R12);
|
||||
CHECK_REG(R13);
|
||||
CHECK_REG(R14);
|
||||
CHECK_REG(R15);
|
||||
CHECK_REG(RDI);
|
||||
CHECK_REG(RSI);
|
||||
CHECK_REG(RBP);
|
||||
CHECK_REG(RBX);
|
||||
CHECK_REG(RDX);
|
||||
CHECK_REG(RAX);
|
||||
CHECK_REG(RCX);
|
||||
CHECK_REG(RSP);
|
||||
CHECK_REG(RIP);
|
||||
|
||||
// sigcontext is an analog to mcontext_t. The layout should be the same.
|
||||
COMPILE_ASSERT_EQ(offsetof(mcontext_t,fpregs),
|
||||
offsetof(sigcontext,fpstate), sigcontext_fpstate);
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// Check that _fpstate from asm/sigcontext.h is essentially the same
|
||||
// as _libc_fpstate.
|
||||
COMPILE_ASSERT_EQ(sizeof(_libc_fpstate), sizeof(_fpstate),
|
||||
sigcontext_fpstate_size);
|
||||
COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,cwd),offsetof(_fpstate,cwd),
|
||||
sigcontext_fpstate_cwd);
|
||||
COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,swd),offsetof(_fpstate,swd),
|
||||
sigcontext_fpstate_swd);
|
||||
COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,ftw),offsetof(_fpstate,twd),
|
||||
sigcontext_fpstate_twd);
|
||||
COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,fop),offsetof(_fpstate,fop),
|
||||
sigcontext_fpstate_fop);
|
||||
COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,rip),offsetof(_fpstate,rip),
|
||||
sigcontext_fpstate_rip);
|
||||
COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,rdp),offsetof(_fpstate,rdp),
|
||||
sigcontext_fpstate_rdp);
|
||||
COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,mxcsr),offsetof(_fpstate,mxcsr),
|
||||
sigcontext_fpstate_mxcsr);
|
||||
COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,mxcr_mask),
|
||||
offsetof(_fpstate,mxcsr_mask),
|
||||
sigcontext_fpstate_mxcsr_mask);
|
||||
COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,_st), offsetof(_fpstate,st_space),
|
||||
sigcontext_fpstate_stspace);
|
||||
COMPILE_ASSERT_EQ(offsetof(_libc_fpstate,_xmm), offsetof(_fpstate,xmm_space),
|
||||
sigcontext_fpstate_xmm_space);
|
||||
#endif
|
||||
|
||||
COMPILE_ASSERT_EQ(MCONTEXT_FPREGS_PTR,
|
||||
offsetof(ucontext_t,uc_mcontext.fpregs),
|
||||
mcontext_fpregs_ptr);
|
||||
COMPILE_ASSERT_EQ(MCONTEXT_FPREGS_MEM, offsetof(ucontext_t,__fpregs_mem),
|
||||
mcontext_fpregs_mem);
|
||||
COMPILE_ASSERT_EQ(FPREGS_OFFSET_MXCSR,
|
||||
offsetof(std::remove_pointer<fpregset_t>::type,mxcsr),
|
||||
fpregs_offset_mxcsr);
|
||||
COMPILE_ASSERT_EQ(UCONTEXT_SIGMASK_OFFSET, offsetof(ucontext_t, uc_sigmask),
|
||||
ucontext_sigmask);
|
||||
#else
|
||||
ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
|
||||
offsetof(ucontext_t,uc_mcontext.gregs));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(AndroidUContext, SigmakOffset) {
|
||||
ASSERT_EQ(static_cast<size_t>(UCONTEXT_SIGMASK_OFFSET),
|
||||
offsetof(ucontext_t,uc_sigmask));
|
||||
}
|
||||
73
externals/breakpad/src/common/linux/crc32.cc
vendored
Normal file
73
externals/breakpad/src/common/linux/crc32.cc
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2014 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/crc32.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// This implementation is based on the sample implementation in RFC 1952.
|
||||
|
||||
// CRC32 polynomial, in reversed form.
|
||||
// See RFC 1952, or http://en.wikipedia.org/wiki/Cyclic_redundancy_check
|
||||
static const uint32_t kCrc32Polynomial = 0xEDB88320;
|
||||
static uint32_t kCrc32Table[256] = { 0 };
|
||||
|
||||
#define arraysize(f) (sizeof(f) / sizeof(*f))
|
||||
|
||||
static void EnsureCrc32TableInited() {
|
||||
if (kCrc32Table[arraysize(kCrc32Table) - 1])
|
||||
return; // already inited
|
||||
for (uint32_t i = 0; i < arraysize(kCrc32Table); ++i) {
|
||||
uint32_t c = i;
|
||||
for (size_t j = 0; j < 8; ++j) {
|
||||
if (c & 1) {
|
||||
c = kCrc32Polynomial ^ (c >> 1);
|
||||
} else {
|
||||
c >>= 1;
|
||||
}
|
||||
}
|
||||
kCrc32Table[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t UpdateCrc32(uint32_t start, const void* buf, size_t len) {
|
||||
EnsureCrc32TableInited();
|
||||
|
||||
uint32_t c = start ^ 0xFFFFFFFF;
|
||||
const uint8_t* u = static_cast<const uint8_t*>(buf);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
c = kCrc32Table[(c ^ u[i]) & 0xFF] ^ (c >> 8);
|
||||
}
|
||||
return c ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
52
externals/breakpad/src/common/linux/crc32.h
vendored
Normal file
52
externals/breakpad/src/common/linux/crc32.h
vendored
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
// Copyright 2014 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef COMMON_LINUX_CRC32_H_
|
||||
#define COMMON_LINUX_CRC32_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Updates a CRC32 checksum with |len| bytes from |buf|. |initial| holds the
|
||||
// checksum result from the previous update; for the first call, it should be 0.
|
||||
uint32_t UpdateCrc32(uint32_t initial, const void* buf, size_t len);
|
||||
|
||||
// Computes a CRC32 checksum using |len| bytes from |buf|.
|
||||
inline uint32_t ComputeCrc32(const void* buf, size_t len) {
|
||||
return UpdateCrc32(0, buf, len);
|
||||
}
|
||||
inline uint32_t ComputeCrc32(const std::string& str) {
|
||||
return ComputeCrc32(str.c_str(), str.size());
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_CRC32_H_
|
||||
1360
externals/breakpad/src/common/linux/dump_symbols.cc
vendored
Normal file
1360
externals/breakpad/src/common/linux/dump_symbols.cc
vendored
Normal file
File diff suppressed because it is too large
Load diff
95
externals/breakpad/src/common/linux/dump_symbols.h
vendored
Normal file
95
externals/breakpad/src/common/linux/dump_symbols.h
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// dump_symbols.h: Read debugging information from an ELF file, and write
|
||||
// it out as a Breakpad symbol file.
|
||||
|
||||
#ifndef COMMON_LINUX_DUMP_SYMBOLS_H__
|
||||
#define COMMON_LINUX_DUMP_SYMBOLS_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/symbol_data.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class Module;
|
||||
|
||||
struct DumpOptions {
|
||||
DumpOptions(SymbolData symbol_data,
|
||||
bool handle_inter_cu_refs,
|
||||
bool enable_multiple_field)
|
||||
: symbol_data(symbol_data),
|
||||
handle_inter_cu_refs(handle_inter_cu_refs),
|
||||
enable_multiple_field(enable_multiple_field) {}
|
||||
|
||||
SymbolData symbol_data;
|
||||
bool handle_inter_cu_refs;
|
||||
bool enable_multiple_field;
|
||||
};
|
||||
|
||||
// Find all the debugging information in OBJ_FILE, an ELF executable
|
||||
// or shared library, and write it to SYM_STREAM in the Breakpad symbol
|
||||
// file format.
|
||||
// If OBJ_FILE has been stripped but contains a .gnu_debuglink section,
|
||||
// then look for the debug file in DEBUG_DIRS.
|
||||
// SYMBOL_DATA allows limiting the type of symbol data written.
|
||||
bool WriteSymbolFile(const string& load_path,
|
||||
const string& obj_file,
|
||||
const string& obj_os,
|
||||
const std::vector<string>& debug_dirs,
|
||||
const DumpOptions& options,
|
||||
std::ostream& sym_stream);
|
||||
|
||||
// Read the selected object file's debugging information, and write out the
|
||||
// header only to |stream|. Return true on success; if an error occurs, report
|
||||
// it and return false. |obj_file| becomes the MODULE file name and |obj_os|
|
||||
// becomes the MODULE operating system.
|
||||
bool WriteSymbolFileHeader(const string& load_path,
|
||||
const string& obj_file,
|
||||
const string& obj_os,
|
||||
std::ostream& sym_stream);
|
||||
|
||||
// As above, but simply return the debugging information in MODULE
|
||||
// instead of writing it to a stream. The caller owns the resulting
|
||||
// Module object and must delete it when finished.
|
||||
bool ReadSymbolData(const string& load_path,
|
||||
const string& obj_file,
|
||||
const string& obj_os,
|
||||
const std::vector<string>& debug_dirs,
|
||||
const DumpOptions& options,
|
||||
Module** module);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_DUMP_SYMBOLS_H__
|
||||
211
externals/breakpad/src/common/linux/dump_symbols_unittest.cc
vendored
Normal file
211
externals/breakpad/src/common/linux/dump_symbols_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Ted Mielczarek <ted.mielczarek@gmail.com>
|
||||
|
||||
// dump_symbols_unittest.cc:
|
||||
// Unittests for google_breakpad::DumpSymbols
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/elf_gnu_compat.h"
|
||||
#include "common/linux/elfutils.h"
|
||||
#include "common/linux/dump_symbols.h"
|
||||
#include "common/linux/synth_elf.h"
|
||||
#include "common/module.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
bool ReadSymbolDataInternal(const uint8_t* obj_file,
|
||||
const string& obj_filename,
|
||||
const string& obj_os,
|
||||
const std::vector<string>& debug_dir,
|
||||
const DumpOptions& options,
|
||||
Module** module);
|
||||
|
||||
using google_breakpad::synth_elf::ELF;
|
||||
using google_breakpad::synth_elf::Notes;
|
||||
using google_breakpad::synth_elf::StringTable;
|
||||
using google_breakpad::synth_elf::SymbolTable;
|
||||
using google_breakpad::test_assembler::kLittleEndian;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
using std::stringstream;
|
||||
using std::vector;
|
||||
using ::testing::Test;
|
||||
using ::testing::Types;
|
||||
|
||||
template<typename ElfClass>
|
||||
class DumpSymbols : public Test {
|
||||
public:
|
||||
void GetElfContents(ELF& elf) {
|
||||
string contents;
|
||||
ASSERT_TRUE(elf.GetContents(&contents));
|
||||
ASSERT_LT(0U, contents.size());
|
||||
|
||||
elfdata_v.clear();
|
||||
elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end());
|
||||
elfdata = &elfdata_v[0];
|
||||
}
|
||||
|
||||
vector<uint8_t> elfdata_v;
|
||||
uint8_t* elfdata;
|
||||
};
|
||||
|
||||
typedef Types<ElfClass32, ElfClass64> ElfClasses;
|
||||
|
||||
TYPED_TEST_SUITE(DumpSymbols, ElfClasses);
|
||||
|
||||
TYPED_TEST(DumpSymbols, Invalid) {
|
||||
Elf32_Ehdr header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
Module* module;
|
||||
DumpOptions options(ALL_SYMBOL_DATA, true, false);
|
||||
EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header),
|
||||
"foo",
|
||||
"Linux",
|
||||
vector<string>(),
|
||||
options,
|
||||
&module));
|
||||
}
|
||||
|
||||
TYPED_TEST(DumpSymbols, SimplePublic) {
|
||||
ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian);
|
||||
// Zero out text section for simplicity.
|
||||
Section text(kLittleEndian);
|
||||
text.Append(4096, 0);
|
||||
elf.AddSection(".text", text, SHT_PROGBITS);
|
||||
|
||||
// Add a public symbol.
|
||||
StringTable table(kLittleEndian);
|
||||
SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table);
|
||||
syms.AddSymbol("superfunc",
|
||||
(typename TypeParam::Addr)0x1000,
|
||||
(typename TypeParam::Addr)0x10,
|
||||
// ELF32_ST_INFO works for 32-or 64-bit.
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
|
||||
SHN_UNDEF + 1);
|
||||
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
|
||||
elf.AddSection(".dynsym", syms,
|
||||
SHT_DYNSYM, // type
|
||||
SHF_ALLOC, // flags
|
||||
0, // addr
|
||||
index, // link
|
||||
sizeof(typename TypeParam::Sym)); // entsize
|
||||
|
||||
elf.Finish();
|
||||
this->GetElfContents(elf);
|
||||
|
||||
Module* module;
|
||||
DumpOptions options(ALL_SYMBOL_DATA, true, false);
|
||||
EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata,
|
||||
"foo",
|
||||
"Linux",
|
||||
vector<string>(),
|
||||
options,
|
||||
&module));
|
||||
|
||||
stringstream s;
|
||||
module->Write(s, ALL_SYMBOL_DATA);
|
||||
const string expected =
|
||||
string("MODULE Linux ") + TypeParam::kMachineName
|
||||
+ " 000000000000000000000000000000000 foo\n"
|
||||
"INFO CODE_ID 00000000000000000000000000000000\n"
|
||||
"PUBLIC 1000 0 superfunc\n";
|
||||
EXPECT_EQ(expected, s.str());
|
||||
delete module;
|
||||
}
|
||||
|
||||
TYPED_TEST(DumpSymbols, SimpleBuildID) {
|
||||
ELF elf(TypeParam::kMachine, TypeParam::kClass, kLittleEndian);
|
||||
// Zero out text section for simplicity.
|
||||
Section text(kLittleEndian);
|
||||
text.Append(4096, 0);
|
||||
elf.AddSection(".text", text, SHT_PROGBITS);
|
||||
|
||||
// Add a Build ID
|
||||
const uint8_t kExpectedIdentifierBytes[] =
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13};
|
||||
Notes notes(kLittleEndian);
|
||||
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
|
||||
sizeof(kExpectedIdentifierBytes));
|
||||
elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
|
||||
|
||||
// Add a public symbol.
|
||||
StringTable table(kLittleEndian);
|
||||
SymbolTable syms(kLittleEndian, TypeParam::kAddrSize, table);
|
||||
syms.AddSymbol("superfunc",
|
||||
(typename TypeParam::Addr)0x1000,
|
||||
(typename TypeParam::Addr)0x10,
|
||||
// ELF32_ST_INFO works for 32-or 64-bit.
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
|
||||
SHN_UNDEF + 1);
|
||||
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
|
||||
elf.AddSection(".dynsym", syms,
|
||||
SHT_DYNSYM, // type
|
||||
SHF_ALLOC, // flags
|
||||
0, // addr
|
||||
index, // link
|
||||
sizeof(typename TypeParam::Sym)); // entsize
|
||||
|
||||
elf.Finish();
|
||||
this->GetElfContents(elf);
|
||||
|
||||
Module* module;
|
||||
DumpOptions options(ALL_SYMBOL_DATA, true, false);
|
||||
EXPECT_TRUE(ReadSymbolDataInternal(this->elfdata,
|
||||
"foo",
|
||||
"Linux",
|
||||
vector<string>(),
|
||||
options,
|
||||
&module));
|
||||
|
||||
stringstream s;
|
||||
module->Write(s, ALL_SYMBOL_DATA);
|
||||
const string expected =
|
||||
string("MODULE Linux ") + TypeParam::kMachineName
|
||||
+ " 030201000504070608090A0B0C0D0E0F0 foo\n"
|
||||
"INFO CODE_ID 000102030405060708090A0B0C0D0E0F10111213\n"
|
||||
"PUBLIC 1000 0 superfunc\n";
|
||||
EXPECT_EQ(expected, s.str());
|
||||
delete module;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
57
externals/breakpad/src/common/linux/eintr_wrapper.h
vendored
Normal file
57
externals/breakpad/src/common/linux/eintr_wrapper.h
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef COMMON_LINUX_EINTR_WRAPPER_H_
|
||||
#define COMMON_LINUX_EINTR_WRAPPER_H_
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
// This provides a wrapper around system calls which may be interrupted by a
|
||||
// signal and return EINTR. See man 7 signal.
|
||||
//
|
||||
|
||||
#define HANDLE_EINTR(x) ({ \
|
||||
__typeof__(x) eintr_wrapper_result; \
|
||||
do { \
|
||||
eintr_wrapper_result = (x); \
|
||||
} while (eintr_wrapper_result == -1 && errno == EINTR); \
|
||||
eintr_wrapper_result; \
|
||||
})
|
||||
|
||||
#define IGNORE_EINTR(x) ({ \
|
||||
__typeof__(x) eintr_wrapper_result; \
|
||||
do { \
|
||||
eintr_wrapper_result = (x); \
|
||||
if (eintr_wrapper_result == -1 && errno == EINTR) { \
|
||||
eintr_wrapper_result = 0; \
|
||||
} \
|
||||
} while (0); \
|
||||
eintr_wrapper_result; \
|
||||
})
|
||||
|
||||
#endif // COMMON_LINUX_EINTR_WRAPPER_H_
|
||||
206
externals/breakpad/src/common/linux/elf_core_dump.cc
vendored
Normal file
206
externals/breakpad/src/common/linux/elf_core_dump.cc
vendored
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// elf_core_dump.cc: Implement google_breakpad::ElfCoreDump.
|
||||
// See elf_core_dump.h for details.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/elf_core_dump.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Implementation of ElfCoreDump::Note.
|
||||
|
||||
ElfCoreDump::Note::Note() {}
|
||||
|
||||
ElfCoreDump::Note::Note(const MemoryRange& content) : content_(content) {}
|
||||
|
||||
bool ElfCoreDump::Note::IsValid() const {
|
||||
return GetHeader() != NULL;
|
||||
}
|
||||
|
||||
const ElfCoreDump::Nhdr* ElfCoreDump::Note::GetHeader() const {
|
||||
return content_.GetData<Nhdr>(0);
|
||||
}
|
||||
|
||||
ElfCoreDump::Word ElfCoreDump::Note::GetType() const {
|
||||
const Nhdr* header = GetHeader();
|
||||
// 0 is not being used as a NOTE type.
|
||||
return header ? header->n_type : 0;
|
||||
}
|
||||
|
||||
MemoryRange ElfCoreDump::Note::GetName() const {
|
||||
const Nhdr* header = GetHeader();
|
||||
if (header) {
|
||||
return content_.Subrange(sizeof(Nhdr), header->n_namesz);
|
||||
}
|
||||
return MemoryRange();
|
||||
}
|
||||
|
||||
MemoryRange ElfCoreDump::Note::GetDescription() const {
|
||||
const Nhdr* header = GetHeader();
|
||||
if (header) {
|
||||
return content_.Subrange(AlignedSize(sizeof(Nhdr) + header->n_namesz),
|
||||
header->n_descsz);
|
||||
}
|
||||
return MemoryRange();
|
||||
}
|
||||
|
||||
ElfCoreDump::Note ElfCoreDump::Note::GetNextNote() const {
|
||||
MemoryRange next_content;
|
||||
const Nhdr* header = GetHeader();
|
||||
if (header) {
|
||||
size_t next_offset = AlignedSize(sizeof(Nhdr) + header->n_namesz);
|
||||
next_offset = AlignedSize(next_offset + header->n_descsz);
|
||||
next_content =
|
||||
content_.Subrange(next_offset, content_.length() - next_offset);
|
||||
}
|
||||
return Note(next_content);
|
||||
}
|
||||
|
||||
// static
|
||||
size_t ElfCoreDump::Note::AlignedSize(size_t size) {
|
||||
size_t mask = sizeof(Word) - 1;
|
||||
return (size + mask) & ~mask;
|
||||
}
|
||||
|
||||
|
||||
// Implementation of ElfCoreDump.
|
||||
|
||||
ElfCoreDump::ElfCoreDump() : proc_mem_fd_(-1) {}
|
||||
|
||||
ElfCoreDump::ElfCoreDump(const MemoryRange& content)
|
||||
: content_(content), proc_mem_fd_(-1) {}
|
||||
|
||||
ElfCoreDump::~ElfCoreDump() {
|
||||
if (proc_mem_fd_ != -1) {
|
||||
close(proc_mem_fd_);
|
||||
proc_mem_fd_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void ElfCoreDump::SetContent(const MemoryRange& content) {
|
||||
content_ = content;
|
||||
}
|
||||
|
||||
void ElfCoreDump::SetProcMem(int fd) {
|
||||
if (proc_mem_fd_ != -1) {
|
||||
close(proc_mem_fd_);
|
||||
}
|
||||
proc_mem_fd_ = fd;
|
||||
}
|
||||
|
||||
bool ElfCoreDump::IsValid() const {
|
||||
const Ehdr* header = GetHeader();
|
||||
return (header &&
|
||||
header->e_ident[0] == ELFMAG0 &&
|
||||
header->e_ident[1] == ELFMAG1 &&
|
||||
header->e_ident[2] == ELFMAG2 &&
|
||||
header->e_ident[3] == ELFMAG3 &&
|
||||
header->e_ident[4] == kClass &&
|
||||
header->e_version == EV_CURRENT &&
|
||||
header->e_type == ET_CORE);
|
||||
}
|
||||
|
||||
const ElfCoreDump::Ehdr* ElfCoreDump::GetHeader() const {
|
||||
return content_.GetData<Ehdr>(0);
|
||||
}
|
||||
|
||||
const ElfCoreDump::Phdr* ElfCoreDump::GetProgramHeader(unsigned index) const {
|
||||
const Ehdr* header = GetHeader();
|
||||
if (header) {
|
||||
return reinterpret_cast<const Phdr*>(content_.GetArrayElement(
|
||||
header->e_phoff, header->e_phentsize, index));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const ElfCoreDump::Phdr* ElfCoreDump::GetFirstProgramHeaderOfType(
|
||||
Word type) const {
|
||||
for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) {
|
||||
const Phdr* program = GetProgramHeader(i);
|
||||
if (program->p_type == type) {
|
||||
return program;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned ElfCoreDump::GetProgramHeaderCount() const {
|
||||
const Ehdr* header = GetHeader();
|
||||
return header ? header->e_phnum : 0;
|
||||
}
|
||||
|
||||
bool ElfCoreDump::CopyData(void* buffer, Addr virtual_address, size_t length) {
|
||||
for (unsigned i = 0, n = GetProgramHeaderCount(); i < n; ++i) {
|
||||
const Phdr* program = GetProgramHeader(i);
|
||||
if (program->p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
size_t offset_in_segment = virtual_address - program->p_vaddr;
|
||||
if (virtual_address >= program->p_vaddr &&
|
||||
offset_in_segment < program->p_filesz) {
|
||||
const void* data =
|
||||
content_.GetData(program->p_offset + offset_in_segment, length);
|
||||
if (data) {
|
||||
memcpy(buffer, data, length);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* fallback: if available, read from /proc/<pid>/mem */
|
||||
if (proc_mem_fd_ != -1) {
|
||||
off_t offset = virtual_address;
|
||||
ssize_t r = pread(proc_mem_fd_, buffer, length, offset);
|
||||
if (r < ssize_t(length)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ElfCoreDump::Note ElfCoreDump::GetFirstNote() const {
|
||||
MemoryRange note_content;
|
||||
const Phdr* program_header = GetFirstProgramHeaderOfType(PT_NOTE);
|
||||
if (program_header) {
|
||||
note_content = content_.Subrange(program_header->p_offset,
|
||||
program_header->p_filesz);
|
||||
}
|
||||
return Note(note_content);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
156
externals/breakpad/src/common/linux/elf_core_dump.h
vendored
Normal file
156
externals/breakpad/src/common/linux/elf_core_dump.h
vendored
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// elf_core_dump.h: Define the google_breakpad::ElfCoreDump class, which
|
||||
// encapsulates an ELF core dump file mapped into memory.
|
||||
|
||||
#ifndef COMMON_LINUX_ELF_CORE_DUMP_H_
|
||||
#define COMMON_LINUX_ELF_CORE_DUMP_H_
|
||||
|
||||
#include <elf.h>
|
||||
#include <limits.h>
|
||||
#include <link.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "common/memory_range.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A class encapsulating an ELF core dump file mapped into memory, which
|
||||
// provides methods for accessing program headers and the note section.
|
||||
class ElfCoreDump {
|
||||
public:
|
||||
// ELF types based on the native word size.
|
||||
typedef ElfW(Ehdr) Ehdr;
|
||||
typedef ElfW(Nhdr) Nhdr;
|
||||
typedef ElfW(Phdr) Phdr;
|
||||
typedef ElfW(Word) Word;
|
||||
typedef ElfW(Addr) Addr;
|
||||
#if ULONG_MAX == 0xffffffff
|
||||
static const int kClass = ELFCLASS32;
|
||||
#elif ULONG_MAX == 0xffffffffffffffff
|
||||
static const int kClass = ELFCLASS64;
|
||||
#else
|
||||
#error "Unsupported word size for ElfCoreDump."
|
||||
#endif
|
||||
|
||||
// A class encapsulating the note content in a core dump, which provides
|
||||
// methods for accessing the name and description of a note.
|
||||
class Note {
|
||||
public:
|
||||
Note();
|
||||
|
||||
// Constructor that takes the note content from |content|.
|
||||
explicit Note(const MemoryRange& content);
|
||||
|
||||
// Returns true if this note is valid, i,e. a note header is found in
|
||||
// |content_|, or false otherwise.
|
||||
bool IsValid() const;
|
||||
|
||||
// Returns the note header, or NULL if no note header is found in
|
||||
// |content_|.
|
||||
const Nhdr* GetHeader() const;
|
||||
|
||||
// Returns the note type, or 0 if no note header is found in |content_|.
|
||||
Word GetType() const;
|
||||
|
||||
// Returns a memory range covering the note name, or an empty range
|
||||
// if no valid note name is found in |content_|.
|
||||
MemoryRange GetName() const;
|
||||
|
||||
// Returns a memory range covering the note description, or an empty
|
||||
// range if no valid note description is found in |content_|.
|
||||
MemoryRange GetDescription() const;
|
||||
|
||||
// Returns the note following this note, or an empty note if no valid
|
||||
// note is found after this note.
|
||||
Note GetNextNote() const;
|
||||
|
||||
private:
|
||||
// Returns the size in bytes round up to the word alignment, specified
|
||||
// for the note section, of a given size in bytes.
|
||||
static size_t AlignedSize(size_t size);
|
||||
|
||||
// Note content.
|
||||
MemoryRange content_;
|
||||
};
|
||||
|
||||
ElfCoreDump();
|
||||
|
||||
// Constructor that takes the core dump content from |content|.
|
||||
explicit ElfCoreDump(const MemoryRange& content);
|
||||
|
||||
~ElfCoreDump();
|
||||
|
||||
// Sets the core dump content to |content|.
|
||||
void SetContent(const MemoryRange& content);
|
||||
|
||||
// Returns true if a valid ELF header in the core dump, or false otherwise.
|
||||
bool IsValid() const;
|
||||
|
||||
// Returns the ELF header in the core dump, or NULL if no ELF header
|
||||
// is found in |content_|.
|
||||
const Ehdr* GetHeader() const;
|
||||
|
||||
// Returns the |index|-th program header in the core dump, or NULL if no
|
||||
// ELF header is found in |content_| or |index| is out of bounds.
|
||||
const Phdr* GetProgramHeader(unsigned index) const;
|
||||
|
||||
// Returns the first program header of |type| in the core dump, or NULL if
|
||||
// no ELF header is found in |content_| or no program header of |type| is
|
||||
// found.
|
||||
const Phdr* GetFirstProgramHeaderOfType(Word type) const;
|
||||
|
||||
// Returns the number of program headers in the core dump, or 0 if no
|
||||
// ELF header is found in |content_|.
|
||||
unsigned GetProgramHeaderCount() const;
|
||||
|
||||
// Copies |length| bytes of data starting at |virtual_address| in the core
|
||||
// dump to |buffer|. |buffer| should be a valid pointer to a buffer of at
|
||||
// least |length| bytes. Returns true if the data to be copied is found in
|
||||
// the core dump, or false otherwise.
|
||||
bool CopyData(void* buffer, Addr virtual_address, size_t length);
|
||||
|
||||
// Returns the first note found in the note section of the core dump, or
|
||||
// an empty note if no note is found.
|
||||
Note GetFirstNote() const;
|
||||
|
||||
// Sets the mem fd.
|
||||
void SetProcMem(const int fd);
|
||||
|
||||
private:
|
||||
// Core dump content.
|
||||
MemoryRange content_;
|
||||
|
||||
// Descriptor for /proc/<pid>/mem.
|
||||
int proc_mem_fd_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_ELF_CORE_DUMP_H_
|
||||
272
externals/breakpad/src/common/linux/elf_core_dump_unittest.cc
vendored
Normal file
272
externals/breakpad/src/common/linux/elf_core_dump_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// elf_core_dump_unittest.cc: Unit tests for google_breakpad::ElfCoreDump.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <sys/procfs.h>
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/elf_core_dump.h"
|
||||
#include "common/linux/memory_mapped_file.h"
|
||||
#include "common/tests/file_utils.h"
|
||||
#include "common/linux/tests/crash_generator.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using google_breakpad::AutoTempDir;
|
||||
using google_breakpad::CrashGenerator;
|
||||
using google_breakpad::ElfCoreDump;
|
||||
using google_breakpad::MemoryMappedFile;
|
||||
using google_breakpad::MemoryRange;
|
||||
using google_breakpad::WriteFile;
|
||||
using std::set;
|
||||
|
||||
TEST(ElfCoreDumpTest, DefaultConstructor) {
|
||||
ElfCoreDump core;
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
EXPECT_EQ(NULL, core.GetHeader());
|
||||
EXPECT_EQ(0U, core.GetProgramHeaderCount());
|
||||
EXPECT_EQ(NULL, core.GetProgramHeader(0));
|
||||
EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD));
|
||||
EXPECT_FALSE(core.GetFirstNote().IsValid());
|
||||
}
|
||||
|
||||
TEST(ElfCoreDumpTest, TestElfHeader) {
|
||||
ElfCoreDump::Ehdr header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string core_path = temp_dir.path() + "/core";
|
||||
const char* core_file = core_path.c_str();
|
||||
MemoryMappedFile mapped_core_file;
|
||||
ElfCoreDump core;
|
||||
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header) - 1));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
EXPECT_EQ(NULL, core.GetHeader());
|
||||
EXPECT_EQ(0U, core.GetProgramHeaderCount());
|
||||
EXPECT_EQ(NULL, core.GetProgramHeader(0));
|
||||
EXPECT_EQ(NULL, core.GetFirstProgramHeaderOfType(PT_LOAD));
|
||||
EXPECT_FALSE(core.GetFirstNote().IsValid());
|
||||
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_ident[0] = ELFMAG0;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_ident[1] = ELFMAG1;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_ident[2] = ELFMAG2;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_ident[3] = ELFMAG3;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_ident[4] = ElfCoreDump::kClass;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_version = EV_CURRENT;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_FALSE(core.IsValid());
|
||||
|
||||
header.e_type = ET_CORE;
|
||||
ASSERT_TRUE(WriteFile(core_file, &header, sizeof(header)));
|
||||
ASSERT_TRUE(mapped_core_file.Map(core_file, 0));
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_TRUE(core.IsValid());
|
||||
}
|
||||
|
||||
TEST(ElfCoreDumpTest, ValidCoreFile) {
|
||||
CrashGenerator crash_generator;
|
||||
if (!crash_generator.HasDefaultCorePattern()) {
|
||||
GTEST_SKIP() << "ElfCoreDumpTest.ValidCoreFile test is skipped "
|
||||
"due to non-default core pattern";
|
||||
}
|
||||
|
||||
if (!crash_generator.HasResourceLimitsAmenableToCrashCollection()) {
|
||||
GTEST_SKIP() << "ElfCoreDumpTest.ValidCoreFile test is skipped "
|
||||
"due to inadequate system resource limits";
|
||||
}
|
||||
|
||||
const unsigned kNumOfThreads = 3;
|
||||
const unsigned kCrashThread = 1;
|
||||
const int kCrashSignal = SIGABRT;
|
||||
ASSERT_TRUE(crash_generator.CreateChildCrash(kNumOfThreads, kCrashThread,
|
||||
kCrashSignal, NULL));
|
||||
pid_t expected_crash_thread_id = crash_generator.GetThreadId(kCrashThread);
|
||||
set<pid_t> expected_thread_ids;
|
||||
for (unsigned i = 0; i < kNumOfThreads; ++i) {
|
||||
expected_thread_ids.insert(crash_generator.GetThreadId(i));
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
struct stat st;
|
||||
if (stat(crash_generator.GetCoreFilePath().c_str(), &st) != 0) {
|
||||
fprintf(stderr, "ElfCoreDumpTest.ValidCoreFile test is skipped "
|
||||
"due to no core file being generated");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
MemoryMappedFile mapped_core_file;
|
||||
ASSERT_TRUE(
|
||||
mapped_core_file.Map(crash_generator.GetCoreFilePath().c_str(), 0));
|
||||
|
||||
ElfCoreDump core;
|
||||
core.SetContent(mapped_core_file.content());
|
||||
EXPECT_TRUE(core.IsValid());
|
||||
|
||||
// Based on write_note_info() in linux/kernel/fs/binfmt_elf.c, notes are
|
||||
// ordered as follows (NT_PRXFPREG and NT_386_TLS are i386 specific):
|
||||
// Thread Name Type
|
||||
// -------------------------------------------------------------------
|
||||
// 1st thread CORE NT_PRSTATUS
|
||||
// process-wide CORE NT_PRPSINFO
|
||||
// process-wide CORE NT_AUXV
|
||||
// 1st thread CORE NT_FPREGSET
|
||||
// 1st thread LINUX NT_PRXFPREG
|
||||
// 1st thread LINUX NT_386_TLS
|
||||
//
|
||||
// 2nd thread CORE NT_PRSTATUS
|
||||
// 2nd thread CORE NT_FPREGSET
|
||||
// 2nd thread LINUX NT_PRXFPREG
|
||||
// 2nd thread LINUX NT_386_TLS
|
||||
//
|
||||
// 3rd thread CORE NT_PRSTATUS
|
||||
// 3rd thread CORE NT_FPREGSET
|
||||
// 3rd thread LINUX NT_PRXFPREG
|
||||
// 3rd thread LINUX NT_386_TLS
|
||||
|
||||
size_t num_nt_prpsinfo = 0;
|
||||
size_t num_nt_prstatus = 0;
|
||||
size_t num_pr_fpvalid = 0;
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
size_t num_nt_fpregset = 0;
|
||||
#endif
|
||||
#if defined(__i386__)
|
||||
size_t num_nt_prxfpreg = 0;
|
||||
#endif
|
||||
set<pid_t> actual_thread_ids;
|
||||
ElfCoreDump::Note note = core.GetFirstNote();
|
||||
while (note.IsValid()) {
|
||||
MemoryRange name = note.GetName();
|
||||
MemoryRange description = note.GetDescription();
|
||||
EXPECT_FALSE(name.IsEmpty());
|
||||
EXPECT_FALSE(description.IsEmpty());
|
||||
|
||||
switch (note.GetType()) {
|
||||
case NT_PRPSINFO: {
|
||||
EXPECT_TRUE(description.data() != NULL);
|
||||
EXPECT_EQ(sizeof(elf_prpsinfo), description.length());
|
||||
++num_nt_prpsinfo;
|
||||
break;
|
||||
}
|
||||
case NT_PRSTATUS: {
|
||||
EXPECT_TRUE(description.data() != NULL);
|
||||
EXPECT_EQ(sizeof(elf_prstatus), description.length());
|
||||
const elf_prstatus* status = description.GetData<elf_prstatus>(0);
|
||||
actual_thread_ids.insert(status->pr_pid);
|
||||
if (num_nt_prstatus == 0) {
|
||||
EXPECT_EQ(expected_crash_thread_id, status->pr_pid);
|
||||
EXPECT_EQ(kCrashSignal, status->pr_info.si_signo);
|
||||
}
|
||||
++num_nt_prstatus;
|
||||
if (status->pr_fpvalid)
|
||||
++num_pr_fpvalid;
|
||||
break;
|
||||
}
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
case NT_FPREGSET: {
|
||||
EXPECT_TRUE(description.data() != NULL);
|
||||
EXPECT_EQ(sizeof(user_fpregs_struct), description.length());
|
||||
++num_nt_fpregset;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#if defined(__i386__)
|
||||
case NT_PRXFPREG: {
|
||||
EXPECT_TRUE(description.data() != NULL);
|
||||
EXPECT_EQ(sizeof(user_fpxregs_struct), description.length());
|
||||
++num_nt_prxfpreg;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
note = note.GetNextNote();
|
||||
}
|
||||
|
||||
#if defined(THREAD_SANITIZER)
|
||||
for (std::set<pid_t>::const_iterator expected = expected_thread_ids.begin();
|
||||
expected != expected_thread_ids.end();
|
||||
++expected) {
|
||||
EXPECT_NE(actual_thread_ids.find(*expected), actual_thread_ids.end());
|
||||
}
|
||||
EXPECT_GE(num_nt_prstatus, kNumOfThreads);
|
||||
#else
|
||||
EXPECT_EQ(actual_thread_ids, expected_thread_ids);
|
||||
EXPECT_EQ(num_nt_prstatus, kNumOfThreads);
|
||||
#endif
|
||||
EXPECT_EQ(1U, num_nt_prpsinfo);
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
EXPECT_EQ(num_pr_fpvalid, num_nt_fpregset);
|
||||
#endif
|
||||
#if defined(__i386__)
|
||||
EXPECT_EQ(num_pr_fpvalid, num_nt_prxfpreg);
|
||||
#endif
|
||||
}
|
||||
50
externals/breakpad/src/common/linux/elf_gnu_compat.h
vendored
Normal file
50
externals/breakpad/src/common/linux/elf_gnu_compat.h
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// -*- mode: C++ -*-
|
||||
|
||||
// Copyright 2013 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Lei Zhang <thestig@google.com>
|
||||
|
||||
// elf_gnu_compat.h: #defines unique to glibc's elf.h.
|
||||
|
||||
#ifndef COMMON_LINUX_ELF_GNU_COMPAT_H_
|
||||
#define COMMON_LINUX_ELF_GNU_COMPAT_H_
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
// A note type on GNU systems corresponding to the .note.gnu.build-id section.
|
||||
#ifndef NT_GNU_BUILD_ID
|
||||
#define NT_GNU_BUILD_ID 3
|
||||
#endif
|
||||
|
||||
// Newer Linux systems offer this.
|
||||
#ifndef NT_SIGINFO
|
||||
#define NT_SIGINFO 0x53494749
|
||||
#endif
|
||||
|
||||
#endif // COMMON_LINUX_ELF_GNU_COMPAT_H_
|
||||
185
externals/breakpad/src/common/linux/elf_symbols_to_module.cc
vendored
Normal file
185
externals/breakpad/src/common/linux/elf_symbols_to_module.cc
vendored
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Ted Mielczarek <ted.mielczarek@gmail.com>
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/elf_symbols_to_module.h"
|
||||
|
||||
#include <cxxabi.h>
|
||||
#include <elf.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "common/byte_cursor.h"
|
||||
#include "common/module.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class ELFSymbolIterator {
|
||||
public:
|
||||
// The contents of an ELF symbol, adjusted for the host's endianness,
|
||||
// word size, and so on. Corresponds to the data in Elf32_Sym / Elf64_Sym.
|
||||
struct Symbol {
|
||||
// True if this iterator has reached the end of the symbol array. When
|
||||
// this is set, the other members of this structure are not valid.
|
||||
bool at_end;
|
||||
|
||||
// The number of this symbol within the list.
|
||||
size_t index;
|
||||
|
||||
// The current symbol's name offset. This is the offset within the
|
||||
// string table.
|
||||
size_t name_offset;
|
||||
|
||||
// The current symbol's value, size, info and shndx fields.
|
||||
uint64_t value;
|
||||
uint64_t size;
|
||||
unsigned char info;
|
||||
uint16_t shndx;
|
||||
};
|
||||
|
||||
// Create an ELFSymbolIterator walking the symbols in BUFFER. Treat the
|
||||
// symbols as big-endian if BIG_ENDIAN is true, as little-endian
|
||||
// otherwise. Assume each symbol has a 'value' field whose size is
|
||||
// VALUE_SIZE.
|
||||
//
|
||||
ELFSymbolIterator(const ByteBuffer* buffer, bool big_endian,
|
||||
size_t value_size)
|
||||
: value_size_(value_size), cursor_(buffer, big_endian) {
|
||||
// Actually, weird sizes could be handled just fine, but they're
|
||||
// probably mistakes --- expressed in bits, say.
|
||||
assert(value_size == 4 || value_size == 8);
|
||||
symbol_.index = 0;
|
||||
Fetch();
|
||||
}
|
||||
|
||||
// Move to the next symbol. This function's behavior is undefined if
|
||||
// at_end() is true when it is called.
|
||||
ELFSymbolIterator& operator++() { Fetch(); symbol_.index++; return *this; }
|
||||
|
||||
// Dereferencing this iterator produces a reference to an Symbol structure
|
||||
// that holds the current symbol's values. The symbol is owned by this
|
||||
// SymbolIterator, and will be invalidated at the next call to operator++.
|
||||
const Symbol& operator*() const { return symbol_; }
|
||||
const Symbol* operator->() const { return &symbol_; }
|
||||
|
||||
private:
|
||||
// Read the symbol at cursor_, and set symbol_ appropriately.
|
||||
void Fetch() {
|
||||
// Elf32_Sym and Elf64_Sym have different layouts.
|
||||
unsigned char other;
|
||||
if (value_size_ == 4) {
|
||||
// Elf32_Sym
|
||||
cursor_
|
||||
.Read(4, false, &symbol_.name_offset)
|
||||
.Read(4, false, &symbol_.value)
|
||||
.Read(4, false, &symbol_.size)
|
||||
.Read(1, false, &symbol_.info)
|
||||
.Read(1, false, &other)
|
||||
.Read(2, false, &symbol_.shndx);
|
||||
} else {
|
||||
// Elf64_Sym
|
||||
cursor_
|
||||
.Read(4, false, &symbol_.name_offset)
|
||||
.Read(1, false, &symbol_.info)
|
||||
.Read(1, false, &other)
|
||||
.Read(2, false, &symbol_.shndx)
|
||||
.Read(8, false, &symbol_.value)
|
||||
.Read(8, false, &symbol_.size);
|
||||
}
|
||||
symbol_.at_end = !cursor_;
|
||||
}
|
||||
|
||||
// The size of symbols' value field, in bytes.
|
||||
size_t value_size_;
|
||||
|
||||
// A byte cursor traversing buffer_.
|
||||
ByteCursor cursor_;
|
||||
|
||||
// Values for the symbol this iterator refers to.
|
||||
Symbol symbol_;
|
||||
};
|
||||
|
||||
const char* SymbolString(ptrdiff_t offset, ByteBuffer& strings) {
|
||||
if (offset < 0 || (size_t) offset >= strings.Size()) {
|
||||
// Return the null string.
|
||||
offset = 0;
|
||||
}
|
||||
return reinterpret_cast<const char*>(strings.start + offset);
|
||||
}
|
||||
|
||||
bool ELFSymbolsToModule(const uint8_t* symtab_section,
|
||||
size_t symtab_size,
|
||||
const uint8_t* string_section,
|
||||
size_t string_size,
|
||||
const bool big_endian,
|
||||
size_t value_size,
|
||||
Module* module) {
|
||||
ByteBuffer symbols(symtab_section, symtab_size);
|
||||
// Ensure that the string section is null-terminated.
|
||||
if (string_section[string_size - 1] != '\0') {
|
||||
const void* null_terminator = memrchr(string_section, '\0', string_size);
|
||||
string_size = reinterpret_cast<const uint8_t*>(null_terminator)
|
||||
- string_section;
|
||||
}
|
||||
ByteBuffer strings(string_section, string_size);
|
||||
|
||||
// The iterator walking the symbol table.
|
||||
ELFSymbolIterator iterator(&symbols, big_endian, value_size);
|
||||
|
||||
while(!iterator->at_end) {
|
||||
if (ELF32_ST_TYPE(iterator->info) == STT_FUNC &&
|
||||
iterator->shndx != SHN_UNDEF) {
|
||||
auto ext = std::make_unique<Module::Extern>(iterator->value);
|
||||
ext->name = SymbolString(iterator->name_offset, strings);
|
||||
#if !defined(__ANDROID__) // Android NDK doesn't provide abi::__cxa_demangle.
|
||||
int status = 0;
|
||||
char* demangled =
|
||||
abi::__cxa_demangle(ext->name.c_str(), NULL, NULL, &status);
|
||||
if (demangled) {
|
||||
if (status == 0)
|
||||
ext->name = demangled;
|
||||
free(demangled);
|
||||
}
|
||||
#endif
|
||||
module->AddExtern(std::move(ext));
|
||||
}
|
||||
++iterator;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
58
externals/breakpad/src/common/linux/elf_symbols_to_module.h
vendored
Normal file
58
externals/breakpad/src/common/linux/elf_symbols_to_module.h
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
// -*- mode: c++ -*-
|
||||
|
||||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Ted Mielczarek <ted.mielczarek@gmail.com>
|
||||
|
||||
// elf_symbols_to_module.h: Exposes ELFSymbolsToModule, a function
|
||||
// for reading ELF symbol tables and inserting exported symbol names
|
||||
// into a google_breakpad::Module as Extern definitions.
|
||||
|
||||
#ifndef BREAKPAD_COMMON_LINUX_ELF_SYMBOLS_TO_MODULE_H_
|
||||
#define BREAKPAD_COMMON_LINUX_ELF_SYMBOLS_TO_MODULE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class Module;
|
||||
|
||||
bool ELFSymbolsToModule(const uint8_t* symtab_section,
|
||||
size_t symtab_size,
|
||||
const uint8_t* string_section,
|
||||
size_t string_size,
|
||||
const bool big_endian,
|
||||
size_t value_size,
|
||||
Module* module);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
|
||||
#endif // BREAKPAD_COMMON_LINUX_ELF_SYMBOLS_TO_MODULE_H_
|
||||
373
externals/breakpad/src/common/linux/elf_symbols_to_module_unittest.cc
vendored
Normal file
373
externals/breakpad/src/common/linux/elf_symbols_to_module_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Original author: Ted Mielczarek <ted.mielczarek@gmail.com>
|
||||
|
||||
// elf_symbols_to_module_unittest.cc:
|
||||
// Unittests for google_breakpad::ELFSymbolsToModule
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <elf.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/elf_symbols_to_module.h"
|
||||
#include "common/linux/synth_elf.h"
|
||||
#include "common/module.h"
|
||||
#include "common/test_assembler.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using google_breakpad::Module;
|
||||
using google_breakpad::synth_elf::StringTable;
|
||||
using google_breakpad::test_assembler::Endianness;
|
||||
using google_breakpad::test_assembler::kBigEndian;
|
||||
using google_breakpad::test_assembler::kLittleEndian;
|
||||
using google_breakpad::test_assembler::Label;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
using ::testing::Test;
|
||||
using ::testing::TestWithParam;
|
||||
using std::vector;
|
||||
|
||||
class ELFSymbolsToModuleTestFixture {
|
||||
public:
|
||||
ELFSymbolsToModuleTestFixture(Endianness endianness,
|
||||
size_t value_size) : module("a", "b", "c", "d"),
|
||||
section(endianness),
|
||||
table(endianness),
|
||||
value_size(value_size) {}
|
||||
|
||||
bool ProcessSection() {
|
||||
string section_contents, table_contents;
|
||||
section.GetContents(§ion_contents);
|
||||
table.GetContents(&table_contents);
|
||||
|
||||
bool ret = ELFSymbolsToModule(reinterpret_cast<const uint8_t*>(section_contents.data()),
|
||||
section_contents.size(),
|
||||
reinterpret_cast<const uint8_t*>(table_contents.data()),
|
||||
table_contents.size(),
|
||||
section.endianness() == kBigEndian,
|
||||
value_size,
|
||||
&module);
|
||||
module.GetExterns(&externs, externs.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
Module module;
|
||||
Section section;
|
||||
StringTable table;
|
||||
string section_contents;
|
||||
// 4 or 8 (bytes)
|
||||
size_t value_size;
|
||||
|
||||
vector<Module::Extern*> externs;
|
||||
};
|
||||
|
||||
class ELFSymbolsToModuleTest32 : public ELFSymbolsToModuleTestFixture,
|
||||
public TestWithParam<Endianness> {
|
||||
public:
|
||||
ELFSymbolsToModuleTest32() : ELFSymbolsToModuleTestFixture(GetParam(), 4) {}
|
||||
|
||||
void AddElf32Sym(const string& name, uint32_t value,
|
||||
uint32_t size, unsigned info, uint16_t shndx) {
|
||||
section
|
||||
.D32(table.Add(name))
|
||||
.D32(value)
|
||||
.D32(size)
|
||||
.D8(info)
|
||||
.D8(0) // other
|
||||
.D16(shndx);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(ELFSymbolsToModuleTest32, NoFuncs) {
|
||||
ProcessSection();
|
||||
|
||||
ASSERT_EQ((size_t)0, externs.size());
|
||||
}
|
||||
|
||||
TEST_P(ELFSymbolsToModuleTest32, OneFunc) {
|
||||
const string kFuncName = "superfunc";
|
||||
const uint32_t kFuncAddr = 0x1000;
|
||||
const uint32_t kFuncSize = 0x10;
|
||||
|
||||
AddElf32Sym(kFuncName, kFuncAddr, kFuncSize,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
|
||||
// Doesn't really matter, just can't be SHN_UNDEF.
|
||||
SHN_UNDEF + 1);
|
||||
|
||||
ProcessSection();
|
||||
|
||||
ASSERT_EQ((size_t)1, externs.size());
|
||||
Module::Extern *extern1 = externs[0];
|
||||
EXPECT_EQ(kFuncName, extern1->name);
|
||||
EXPECT_EQ((Module::Address)kFuncAddr, extern1->address);
|
||||
}
|
||||
|
||||
TEST_P(ELFSymbolsToModuleTest32, NameOutOfBounds) {
|
||||
const string kFuncName = "";
|
||||
const uint32_t kFuncAddr = 0x1000;
|
||||
const uint32_t kFuncSize = 0x10;
|
||||
|
||||
table.Add("Foo");
|
||||
table.Add("Bar");
|
||||
// Can't use AddElf32Sym because it puts in a valid string offset.
|
||||
section
|
||||
.D32((uint32_t)table.Here().Value() + 1)
|
||||
.D32(kFuncAddr)
|
||||
.D32(kFuncSize)
|
||||
.D8(ELF32_ST_INFO(STB_GLOBAL, STT_FUNC))
|
||||
.D8(0) // other
|
||||
.D16(SHN_UNDEF + 1);
|
||||
|
||||
ProcessSection();
|
||||
|
||||
ASSERT_EQ((size_t)1, externs.size());
|
||||
Module::Extern *extern1 = externs[0];
|
||||
EXPECT_EQ(kFuncName, extern1->name);
|
||||
EXPECT_EQ((Module::Address)kFuncAddr, extern1->address);
|
||||
}
|
||||
|
||||
TEST_P(ELFSymbolsToModuleTest32, NonTerminatedStringTable) {
|
||||
const string kFuncName = "";
|
||||
const uint32_t kFuncAddr = 0x1000;
|
||||
const uint32_t kFuncSize = 0x10;
|
||||
|
||||
table.Add("Foo");
|
||||
table.Add("Bar");
|
||||
// Add a non-null-terminated string to the end of the string table
|
||||
Label l;
|
||||
table
|
||||
.Mark(&l)
|
||||
.Append("Unterminated");
|
||||
// Can't use AddElf32Sym because it puts in a valid string offset.
|
||||
section
|
||||
.D32((uint32_t)l.Value())
|
||||
.D32(kFuncAddr)
|
||||
.D32(kFuncSize)
|
||||
.D8(ELF32_ST_INFO(STB_GLOBAL, STT_FUNC))
|
||||
.D8(0) // other
|
||||
.D16(SHN_UNDEF + 1);
|
||||
|
||||
ProcessSection();
|
||||
|
||||
ASSERT_EQ((size_t)1, externs.size());
|
||||
Module::Extern *extern1 = externs[0];
|
||||
EXPECT_EQ(kFuncName, extern1->name);
|
||||
EXPECT_EQ((Module::Address)kFuncAddr, extern1->address);
|
||||
}
|
||||
|
||||
TEST_P(ELFSymbolsToModuleTest32, MultipleFuncs) {
|
||||
const string kFuncName1 = "superfunc";
|
||||
const uint32_t kFuncAddr1 = 0x10001000;
|
||||
const uint32_t kFuncSize1 = 0x10;
|
||||
const string kFuncName2 = "awesomefunc";
|
||||
const uint32_t kFuncAddr2 = 0x20002000;
|
||||
const uint32_t kFuncSize2 = 0x2f;
|
||||
const string kFuncName3 = "megafunc";
|
||||
const uint32_t kFuncAddr3 = 0x30003000;
|
||||
const uint32_t kFuncSize3 = 0x3c;
|
||||
|
||||
AddElf32Sym(kFuncName1, kFuncAddr1, kFuncSize1,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
|
||||
// Doesn't really matter, just can't be SHN_UNDEF.
|
||||
SHN_UNDEF + 1);
|
||||
AddElf32Sym(kFuncName2, kFuncAddr2, kFuncSize2,
|
||||
ELF32_ST_INFO(STB_LOCAL, STT_FUNC),
|
||||
// Doesn't really matter, just can't be SHN_UNDEF.
|
||||
SHN_UNDEF + 2);
|
||||
AddElf32Sym(kFuncName3, kFuncAddr3, kFuncSize3,
|
||||
ELF32_ST_INFO(STB_LOCAL, STT_FUNC),
|
||||
// Doesn't really matter, just can't be SHN_UNDEF.
|
||||
SHN_UNDEF + 3);
|
||||
|
||||
ProcessSection();
|
||||
|
||||
ASSERT_EQ((size_t)3, externs.size());
|
||||
Module::Extern *extern1 = externs[0];
|
||||
EXPECT_EQ(kFuncName1, extern1->name);
|
||||
EXPECT_EQ((Module::Address)kFuncAddr1, extern1->address);
|
||||
Module::Extern *extern2 = externs[1];
|
||||
EXPECT_EQ(kFuncName2, extern2->name);
|
||||
EXPECT_EQ((Module::Address)kFuncAddr2, extern2->address);
|
||||
Module::Extern *extern3 = externs[2];
|
||||
EXPECT_EQ(kFuncName3, extern3->name);
|
||||
EXPECT_EQ((Module::Address)kFuncAddr3, extern3->address);
|
||||
}
|
||||
|
||||
TEST_P(ELFSymbolsToModuleTest32, SkipStuff) {
|
||||
const string kFuncName = "superfunc";
|
||||
const uint32_t kFuncAddr = 0x1000;
|
||||
const uint32_t kFuncSize = 0x10;
|
||||
|
||||
// Should skip functions in SHN_UNDEF
|
||||
AddElf32Sym("skipme", 0xFFFF, 0x10,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
|
||||
SHN_UNDEF);
|
||||
AddElf32Sym(kFuncName, kFuncAddr, kFuncSize,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_FUNC),
|
||||
// Doesn't really matter, just can't be SHN_UNDEF.
|
||||
SHN_UNDEF + 1);
|
||||
// Should skip non-STT_FUNC entries.
|
||||
AddElf32Sym("skipmetoo", 0xAAAA, 0x10,
|
||||
ELF32_ST_INFO(STB_GLOBAL, STT_FILE),
|
||||
SHN_UNDEF + 1);
|
||||
|
||||
ProcessSection();
|
||||
|
||||
ASSERT_EQ((size_t)1, externs.size());
|
||||
Module::Extern *extern1 = externs[0];
|
||||
EXPECT_EQ(kFuncName, extern1->name);
|
||||
EXPECT_EQ((Module::Address)kFuncAddr, extern1->address);
|
||||
}
|
||||
|
||||
// Run all the 32-bit tests with both endianness
|
||||
INSTANTIATE_TEST_SUITE_P(Endian,
|
||||
ELFSymbolsToModuleTest32,
|
||||
::testing::Values(kLittleEndian, kBigEndian));
|
||||
|
||||
// Similar tests, but with 64-bit values. Ostensibly this could be
|
||||
// shoehorned into the parameterization by using ::testing::Combine,
|
||||
// but that would make it difficult to get the types right since these
|
||||
// actual test cases aren't parameterized. This could also be written
|
||||
// as a type-parameterized test, but combining that with a value-parameterized
|
||||
// test seemed really ugly, and also makes it harder to test 64-bit
|
||||
// values.
|
||||
class ELFSymbolsToModuleTest64 : public ELFSymbolsToModuleTestFixture,
|
||||
public TestWithParam<Endianness> {
|
||||
public:
|
||||
ELFSymbolsToModuleTest64() : ELFSymbolsToModuleTestFixture(GetParam(), 8) {}
|
||||
|
||||
void AddElf64Sym(const string& name, uint64_t value,
|
||||
uint64_t size, unsigned info, uint16_t shndx) {
|
||||
section
|
||||
.D32(table.Add(name))
|
||||
.D8(info)
|
||||
.D8(0) // other
|
||||
.D16(shndx)
|
||||
.D64(value)
|
||||
.D64(size);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(ELFSymbolsToModuleTest64, NoFuncs) {
|
||||
ProcessSection();
|
||||
|
||||
ASSERT_EQ((size_t)0, externs.size());
|
||||
}
|
||||
|
||||
TEST_P(ELFSymbolsToModuleTest64, OneFunc) {
|
||||
const string kFuncName = "superfunc";
|
||||
const uint64_t kFuncAddr = 0x1000200030004000ULL;
|
||||
const uint64_t kFuncSize = 0x1000;
|
||||
|
||||
AddElf64Sym(kFuncName, kFuncAddr, kFuncSize,
|
||||
ELF64_ST_INFO(STB_GLOBAL, STT_FUNC),
|
||||
// Doesn't really matter, just can't be SHN_UNDEF.
|
||||
SHN_UNDEF + 1);
|
||||
|
||||
ProcessSection();
|
||||
|
||||
ASSERT_EQ((size_t)1, externs.size());
|
||||
Module::Extern *extern1 = externs[0];
|
||||
EXPECT_EQ(kFuncName, extern1->name);
|
||||
EXPECT_EQ((Module::Address)kFuncAddr, extern1->address);
|
||||
}
|
||||
|
||||
TEST_P(ELFSymbolsToModuleTest64, MultipleFuncs) {
|
||||
const string kFuncName1 = "superfunc";
|
||||
const uint64_t kFuncAddr1 = 0x1000100010001000ULL;
|
||||
const uint64_t kFuncSize1 = 0x1000;
|
||||
const string kFuncName2 = "awesomefunc";
|
||||
const uint64_t kFuncAddr2 = 0x2000200020002000ULL;
|
||||
const uint64_t kFuncSize2 = 0x2f00;
|
||||
const string kFuncName3 = "megafunc";
|
||||
const uint64_t kFuncAddr3 = 0x3000300030003000ULL;
|
||||
const uint64_t kFuncSize3 = 0x3c00;
|
||||
|
||||
AddElf64Sym(kFuncName1, kFuncAddr1, kFuncSize1,
|
||||
ELF64_ST_INFO(STB_GLOBAL, STT_FUNC),
|
||||
// Doesn't really matter, just can't be SHN_UNDEF.
|
||||
SHN_UNDEF + 1);
|
||||
AddElf64Sym(kFuncName2, kFuncAddr2, kFuncSize2,
|
||||
ELF64_ST_INFO(STB_LOCAL, STT_FUNC),
|
||||
// Doesn't really matter, just can't be SHN_UNDEF.
|
||||
SHN_UNDEF + 2);
|
||||
AddElf64Sym(kFuncName3, kFuncAddr3, kFuncSize3,
|
||||
ELF64_ST_INFO(STB_LOCAL, STT_FUNC),
|
||||
// Doesn't really matter, just can't be SHN_UNDEF.
|
||||
SHN_UNDEF + 3);
|
||||
|
||||
ProcessSection();
|
||||
|
||||
ASSERT_EQ((size_t)3, externs.size());
|
||||
Module::Extern *extern1 = externs[0];
|
||||
EXPECT_EQ(kFuncName1, extern1->name);
|
||||
EXPECT_EQ((Module::Address)kFuncAddr1, extern1->address);
|
||||
Module::Extern *extern2 = externs[1];
|
||||
EXPECT_EQ(kFuncName2, extern2->name);
|
||||
EXPECT_EQ((Module::Address)kFuncAddr2, extern2->address);
|
||||
Module::Extern *extern3 = externs[2];
|
||||
EXPECT_EQ(kFuncName3, extern3->name);
|
||||
EXPECT_EQ((Module::Address)kFuncAddr3, extern3->address);
|
||||
}
|
||||
|
||||
TEST_P(ELFSymbolsToModuleTest64, SkipStuff) {
|
||||
const string kFuncName = "superfunc";
|
||||
const uint64_t kFuncAddr = 0x1000100010001000ULL;
|
||||
const uint64_t kFuncSize = 0x1000;
|
||||
|
||||
// Should skip functions in SHN_UNDEF
|
||||
AddElf64Sym("skipme", 0xFFFF, 0x10,
|
||||
ELF64_ST_INFO(STB_GLOBAL, STT_FUNC),
|
||||
SHN_UNDEF);
|
||||
AddElf64Sym(kFuncName, kFuncAddr, kFuncSize,
|
||||
ELF64_ST_INFO(STB_GLOBAL, STT_FUNC),
|
||||
// Doesn't really matter, just can't be SHN_UNDEF.
|
||||
SHN_UNDEF + 1);
|
||||
// Should skip non-STT_FUNC entries.
|
||||
AddElf64Sym("skipmetoo", 0xAAAA, 0x10,
|
||||
ELF64_ST_INFO(STB_GLOBAL, STT_FILE),
|
||||
SHN_UNDEF + 1);
|
||||
|
||||
ProcessSection();
|
||||
|
||||
ASSERT_EQ((size_t)1, externs.size());
|
||||
Module::Extern *extern1 = externs[0];
|
||||
EXPECT_EQ(kFuncName, extern1->name);
|
||||
EXPECT_EQ((Module::Address)kFuncAddr, extern1->address);
|
||||
}
|
||||
|
||||
// Run all the 64-bit tests with both endianness
|
||||
INSTANTIATE_TEST_SUITE_P(Endian,
|
||||
ELFSymbolsToModuleTest64,
|
||||
::testing::Values(kLittleEndian, kBigEndian));
|
||||
73
externals/breakpad/src/common/linux/elfutils-inl.h
vendored
Normal file
73
externals/breakpad/src/common/linux/elfutils-inl.h
vendored
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC 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__
|
||||
246
externals/breakpad/src/common/linux/elfutils.cc
vendored
Normal file
246
externals/breakpad/src/common/linux/elfutils.cc
vendored
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/elfutils.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "common/linux/elfutils-inl.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename ElfClass>
|
||||
void FindElfClassSection(const char* elf_base,
|
||||
const char* section_name,
|
||||
typename ElfClass::Word section_type,
|
||||
const void** section_start,
|
||||
size_t* section_size) {
|
||||
typedef typename ElfClass::Ehdr Ehdr;
|
||||
typedef typename ElfClass::Shdr Shdr;
|
||||
|
||||
assert(elf_base);
|
||||
assert(section_start);
|
||||
assert(section_size);
|
||||
|
||||
assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0);
|
||||
|
||||
const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base);
|
||||
assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass);
|
||||
|
||||
if (elf_header->e_shoff == 0) {
|
||||
*section_start = NULL;
|
||||
*section_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
const Shdr* sections =
|
||||
GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
|
||||
const Shdr* section_names = sections + elf_header->e_shstrndx;
|
||||
const char* names =
|
||||
GetOffset<ElfClass, char>(elf_header, section_names->sh_offset);
|
||||
const char* names_end = names + section_names->sh_size;
|
||||
|
||||
const Shdr* section =
|
||||
FindElfSectionByName<ElfClass>(section_name, section_type,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
|
||||
if (section != NULL && section->sh_size > 0) {
|
||||
*section_start = elf_base + section->sh_offset;
|
||||
*section_size = section->sh_size;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ElfClass>
|
||||
void FindElfClassSegment(const char* elf_base,
|
||||
typename ElfClass::Word segment_type,
|
||||
wasteful_vector<ElfSegment>* segments) {
|
||||
typedef typename ElfClass::Ehdr Ehdr;
|
||||
typedef typename ElfClass::Phdr Phdr;
|
||||
|
||||
assert(elf_base);
|
||||
assert(segments);
|
||||
|
||||
assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0);
|
||||
|
||||
const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base);
|
||||
assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass);
|
||||
|
||||
const Phdr* phdrs =
|
||||
GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff);
|
||||
|
||||
for (int i = 0; i < elf_header->e_phnum; ++i) {
|
||||
if (phdrs[i].p_type == segment_type) {
|
||||
ElfSegment seg = {};
|
||||
seg.start = elf_base + phdrs[i].p_offset;
|
||||
seg.size = phdrs[i].p_filesz;
|
||||
segments->push_back(seg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool IsValidElf(const void* elf_base) {
|
||||
return my_strncmp(reinterpret_cast<const char*>(elf_base),
|
||||
ELFMAG, SELFMAG) == 0;
|
||||
}
|
||||
|
||||
int ElfClass(const void* elf_base) {
|
||||
const ElfW(Ehdr)* elf_header =
|
||||
reinterpret_cast<const ElfW(Ehdr)*>(elf_base);
|
||||
|
||||
return elf_header->e_ident[EI_CLASS];
|
||||
}
|
||||
|
||||
bool FindElfSection(const void* elf_mapped_base,
|
||||
const char* section_name,
|
||||
uint32_t section_type,
|
||||
const void** section_start,
|
||||
size_t* section_size) {
|
||||
assert(elf_mapped_base);
|
||||
assert(section_start);
|
||||
assert(section_size);
|
||||
|
||||
*section_start = NULL;
|
||||
*section_size = 0;
|
||||
|
||||
if (!IsValidElf(elf_mapped_base))
|
||||
return false;
|
||||
|
||||
int cls = ElfClass(elf_mapped_base);
|
||||
const char* elf_base =
|
||||
static_cast<const char*>(elf_mapped_base);
|
||||
|
||||
if (cls == ELFCLASS32) {
|
||||
FindElfClassSection<ElfClass32>(elf_base, section_name, section_type,
|
||||
section_start, section_size);
|
||||
return *section_start != NULL;
|
||||
} else if (cls == ELFCLASS64) {
|
||||
FindElfClassSection<ElfClass64>(elf_base, section_name, section_type,
|
||||
section_start, section_size);
|
||||
return *section_start != NULL;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FindElfSegments(const void* elf_mapped_base,
|
||||
uint32_t segment_type,
|
||||
wasteful_vector<ElfSegment>* segments) {
|
||||
assert(elf_mapped_base);
|
||||
assert(segments);
|
||||
|
||||
if (!IsValidElf(elf_mapped_base))
|
||||
return false;
|
||||
|
||||
int cls = ElfClass(elf_mapped_base);
|
||||
const char* elf_base =
|
||||
static_cast<const char*>(elf_mapped_base);
|
||||
|
||||
if (cls == ELFCLASS32) {
|
||||
FindElfClassSegment<ElfClass32>(elf_base, segment_type, segments);
|
||||
return true;
|
||||
} else if (cls == ELFCLASS64) {
|
||||
FindElfClassSegment<ElfClass64>(elf_base, segment_type, segments);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename ElfClass>
|
||||
bool FindElfSoNameFromDynamicSection(const void* section_start,
|
||||
size_t section_size,
|
||||
const void* dynstr_start,
|
||||
size_t dynstr_size,
|
||||
char* soname,
|
||||
size_t soname_size) {
|
||||
typedef typename ElfClass::Dyn Dyn;
|
||||
|
||||
auto* dynamic = static_cast<const Dyn*>(section_start);
|
||||
size_t dcount = section_size / sizeof(Dyn);
|
||||
for (const Dyn* dyn = dynamic; dyn < dynamic + dcount; ++dyn) {
|
||||
if (dyn->d_tag == DT_SONAME) {
|
||||
const char* dynstr = static_cast<const char*>(dynstr_start);
|
||||
if (dyn->d_un.d_val >= dynstr_size) {
|
||||
// Beyond the end of the dynstr section
|
||||
return false;
|
||||
}
|
||||
const char* str = dynstr + dyn->d_un.d_val;
|
||||
const size_t maxsize = dynstr_size - dyn->d_un.d_val;
|
||||
my_strlcpy(soname, str, maxsize < soname_size ? maxsize : soname_size);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ElfFileSoNameFromMappedFile(const void* elf_base,
|
||||
char* soname,
|
||||
size_t soname_size) {
|
||||
if (!IsValidElf(elf_base)) {
|
||||
// Not ELF
|
||||
return false;
|
||||
}
|
||||
|
||||
const void* segment_start;
|
||||
size_t segment_size;
|
||||
if (!FindElfSection(elf_base, ".dynamic", SHT_DYNAMIC, &segment_start,
|
||||
&segment_size)) {
|
||||
// No dynamic section
|
||||
return false;
|
||||
}
|
||||
|
||||
const void* dynstr_start;
|
||||
size_t dynstr_size;
|
||||
if (!FindElfSection(elf_base, ".dynstr", SHT_STRTAB, &dynstr_start,
|
||||
&dynstr_size)) {
|
||||
// No dynstr section
|
||||
return false;
|
||||
}
|
||||
|
||||
int cls = ElfClass(elf_base);
|
||||
return cls == ELFCLASS32 ? FindElfSoNameFromDynamicSection<ElfClass32>(
|
||||
segment_start, segment_size, dynstr_start,
|
||||
dynstr_size, soname, soname_size)
|
||||
: FindElfSoNameFromDynamicSection<ElfClass64>(
|
||||
segment_start, segment_size, dynstr_start,
|
||||
dynstr_size, soname, soname_size);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
169
externals/breakpad/src/common/linux/elfutils.h
vendored
Normal file
169
externals/breakpad/src/common/linux/elfutils.h
vendored
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// elfutils.h: Utilities for dealing with ELF files.
|
||||
//
|
||||
|
||||
#ifndef COMMON_LINUX_ELFUTILS_H_
|
||||
#define COMMON_LINUX_ELFUTILS_H_
|
||||
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common/memory_allocator.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
typedef struct Elf32_Chdr {
|
||||
typedef Elf32_Word Type;
|
||||
typedef Elf32_Word Size;
|
||||
typedef Elf32_Addr Addr;
|
||||
|
||||
static_assert(sizeof (Type) == 4);
|
||||
static_assert(sizeof (Size) == 4);
|
||||
static_assert(sizeof (Addr) == 4);
|
||||
|
||||
Type ch_type; // Compression type
|
||||
Size ch_size; // Uncompressed data size in bytes
|
||||
Addr ch_addralign; // Uncompressed data alignment
|
||||
} Elf32_Chdr;
|
||||
|
||||
static_assert(sizeof (Elf32_Chdr) == 12);
|
||||
|
||||
typedef struct Elf64_Chdr {
|
||||
typedef Elf64_Word Type;
|
||||
typedef Elf64_Xword Size;
|
||||
typedef Elf64_Addr Addr;
|
||||
|
||||
static_assert(sizeof (Type) == 4);
|
||||
static_assert(sizeof (Size) == 8);
|
||||
static_assert(sizeof (Addr) == 8);
|
||||
|
||||
Type ch_type; // Compression type
|
||||
Type ch_reserved; // Padding
|
||||
Size ch_size; // Uncompressed data size in bytes
|
||||
Addr ch_addralign; // Uncompressed data alignment
|
||||
} Elf64_Chdr;
|
||||
|
||||
static_assert(sizeof (Elf64_Chdr) == 24);
|
||||
|
||||
// Traits classes so consumers can write templatized code to deal
|
||||
// with specific ELF bits.
|
||||
struct ElfClass32 {
|
||||
typedef Elf32_Addr Addr;
|
||||
typedef Elf32_Dyn Dyn;
|
||||
typedef Elf32_Ehdr Ehdr;
|
||||
typedef Elf32_Nhdr Nhdr;
|
||||
typedef Elf32_Phdr Phdr;
|
||||
typedef Elf32_Shdr Shdr;
|
||||
typedef Elf32_Chdr Chdr;
|
||||
typedef Elf32_Half Half;
|
||||
typedef Elf32_Off Off;
|
||||
typedef Elf32_Sym Sym;
|
||||
typedef Elf32_Word Word;
|
||||
|
||||
static const int kClass = ELFCLASS32;
|
||||
static const uint16_t kMachine = EM_386;
|
||||
static const size_t kAddrSize = sizeof(Elf32_Addr);
|
||||
static constexpr const char* kMachineName = "x86";
|
||||
};
|
||||
|
||||
struct ElfClass64 {
|
||||
typedef Elf64_Addr Addr;
|
||||
typedef Elf64_Dyn Dyn;
|
||||
typedef Elf64_Ehdr Ehdr;
|
||||
typedef Elf64_Nhdr Nhdr;
|
||||
typedef Elf64_Phdr Phdr;
|
||||
typedef Elf64_Shdr Shdr;
|
||||
typedef Elf64_Chdr Chdr;
|
||||
typedef Elf64_Half Half;
|
||||
typedef Elf64_Off Off;
|
||||
typedef Elf64_Sym Sym;
|
||||
typedef Elf64_Word Word;
|
||||
|
||||
static const int kClass = ELFCLASS64;
|
||||
static const uint16_t kMachine = EM_X86_64;
|
||||
static const size_t kAddrSize = sizeof(Elf64_Addr);
|
||||
static constexpr const char* kMachineName = "x86_64";
|
||||
};
|
||||
|
||||
bool IsValidElf(const void* elf_header);
|
||||
int ElfClass(const void* elf_base);
|
||||
|
||||
// Attempt to find a section named |section_name| of type |section_type|
|
||||
// in the ELF binary data at |elf_mapped_base|. On success, returns true
|
||||
// and sets |*section_start| to point to the start of the section data,
|
||||
// and |*section_size| to the size of the section's data.
|
||||
bool FindElfSection(const void* elf_mapped_base,
|
||||
const char* section_name,
|
||||
uint32_t section_type,
|
||||
const void** section_start,
|
||||
size_t* section_size);
|
||||
|
||||
// Internal helper method, exposed for convenience for callers
|
||||
// that already have more info.
|
||||
template<typename ElfClass>
|
||||
const typename ElfClass::Shdr*
|
||||
FindElfSectionByName(const char* name,
|
||||
typename ElfClass::Word section_type,
|
||||
const typename ElfClass::Shdr* sections,
|
||||
const char* section_names,
|
||||
const char* names_end,
|
||||
int nsection);
|
||||
|
||||
struct ElfSegment {
|
||||
const void* start;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
// Attempt to find all segments of type |segment_type| in the ELF
|
||||
// binary data at |elf_mapped_base|. On success, returns true and fills
|
||||
// |*segments| with a list of segments of the given type.
|
||||
bool FindElfSegments(const void* elf_mapped_base,
|
||||
uint32_t segment_type,
|
||||
wasteful_vector<ElfSegment>* segments);
|
||||
|
||||
// Convert an offset from an Elf header into a pointer to the mapped
|
||||
// address in the current process. Takes an extra template parameter
|
||||
// to specify the return type to avoid having to dynamic_cast the
|
||||
// result.
|
||||
template<typename ElfClass, typename T>
|
||||
const T*
|
||||
GetOffset(const typename ElfClass::Ehdr* elf_header,
|
||||
typename ElfClass::Off offset);
|
||||
|
||||
// Read the value of DT_SONAME from the elf file mapped at |elf_base|. Returns
|
||||
// true and fills |soname| with the result if found.
|
||||
bool ElfFileSoNameFromMappedFile(const void* elf_base,
|
||||
char* soname,
|
||||
size_t soname_size);
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_ELFUTILS_H_
|
||||
206
externals/breakpad/src/common/linux/file_id.cc
vendored
Normal file
206
externals/breakpad/src/common/linux/file_id.cc
vendored
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
// Copyright 2006 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// file_id.cc: Return a unique identifier for a file
|
||||
//
|
||||
// See file_id.h for documentation
|
||||
//
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/file_id.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "common/linux/elf_gnu_compat.h"
|
||||
#include "common/linux/elfutils.h"
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
#include "common/linux/memory_mapped_file.h"
|
||||
#include "common/using_std_string.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
namespace elf {
|
||||
|
||||
// Used in a few places for backwards-compatibility.
|
||||
const size_t kMDGUIDSize = sizeof(MDGUID);
|
||||
|
||||
FileID::FileID(const char* path) : path_(path) {}
|
||||
|
||||
// ELF note name and desc are 32-bits word padded.
|
||||
#define NOTE_PADDING(a) ((a + 3) & ~3)
|
||||
|
||||
// These functions are also used inside the crashed process, so be safe
|
||||
// and use the syscall/libc wrappers instead of direct syscalls or libc.
|
||||
|
||||
static bool ElfClassBuildIDNoteIdentifier(const void* section, size_t length,
|
||||
wasteful_vector<uint8_t>& identifier) {
|
||||
static_assert(sizeof(ElfClass32::Nhdr) == sizeof(ElfClass64::Nhdr),
|
||||
"Elf32_Nhdr and Elf64_Nhdr should be the same");
|
||||
typedef typename ElfClass32::Nhdr Nhdr;
|
||||
|
||||
const void* section_end = reinterpret_cast<const char*>(section) + length;
|
||||
const Nhdr* note_header = reinterpret_cast<const Nhdr*>(section);
|
||||
while (reinterpret_cast<const void*>(note_header) < section_end) {
|
||||
if (note_header->n_type == NT_GNU_BUILD_ID)
|
||||
break;
|
||||
note_header = reinterpret_cast<const Nhdr*>(
|
||||
reinterpret_cast<const char*>(note_header) + sizeof(Nhdr) +
|
||||
NOTE_PADDING(note_header->n_namesz) +
|
||||
NOTE_PADDING(note_header->n_descsz));
|
||||
}
|
||||
if (reinterpret_cast<const void*>(note_header) >= section_end ||
|
||||
note_header->n_descsz == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t* build_id = reinterpret_cast<const uint8_t*>(note_header) +
|
||||
sizeof(Nhdr) + NOTE_PADDING(note_header->n_namesz);
|
||||
identifier.insert(identifier.end(),
|
||||
build_id,
|
||||
build_id + note_header->n_descsz);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Attempt to locate a .note.gnu.build-id section in an ELF binary
|
||||
// and copy it into |identifier|.
|
||||
static bool FindElfBuildIDNote(const void* elf_mapped_base,
|
||||
wasteful_vector<uint8_t>& identifier) {
|
||||
PageAllocator allocator;
|
||||
// lld normally creates 2 PT_NOTEs, gold normally creates 1.
|
||||
auto_wasteful_vector<ElfSegment, 2> segs(&allocator);
|
||||
if (FindElfSegments(elf_mapped_base, PT_NOTE, &segs)) {
|
||||
for (ElfSegment& seg : segs) {
|
||||
if (ElfClassBuildIDNoteIdentifier(seg.start, seg.size, identifier)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* note_section;
|
||||
size_t note_size;
|
||||
if (FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE,
|
||||
(const void**)¬e_section, ¬e_size)) {
|
||||
return ElfClassBuildIDNoteIdentifier(note_section, note_size, identifier);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt to locate the .text section of an ELF binary and generate
|
||||
// a simple hash by XORing the first page worth of bytes into |identifier|.
|
||||
static bool HashElfTextSection(const void* elf_mapped_base,
|
||||
wasteful_vector<uint8_t>& identifier) {
|
||||
identifier.resize(kMDGUIDSize);
|
||||
|
||||
void* text_section;
|
||||
size_t text_size;
|
||||
if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS,
|
||||
(const void**)&text_section, &text_size) ||
|
||||
text_size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only provide |kMDGUIDSize| bytes to keep identifiers produced by this
|
||||
// function backwards-compatible.
|
||||
my_memset(&identifier[0], 0, kMDGUIDSize);
|
||||
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(text_section);
|
||||
const uint8_t* ptr_end = ptr + std::min(text_size, static_cast<size_t>(4096));
|
||||
while (ptr < ptr_end) {
|
||||
for (unsigned i = 0; i < kMDGUIDSize; i++)
|
||||
identifier[i] ^= ptr[i];
|
||||
ptr += kMDGUIDSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool FileID::ElfFileIdentifierFromMappedFile(const void* base,
|
||||
wasteful_vector<uint8_t>& identifier) {
|
||||
// Look for a build id note first.
|
||||
if (FindElfBuildIDNote(base, identifier))
|
||||
return true;
|
||||
|
||||
// Fall back on hashing the first page of the text section.
|
||||
return HashElfTextSection(base, identifier);
|
||||
}
|
||||
|
||||
bool FileID::ElfFileIdentifier(wasteful_vector<uint8_t>& identifier) {
|
||||
MemoryMappedFile mapped_file(path_.c_str(), 0);
|
||||
if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)?
|
||||
return false;
|
||||
|
||||
return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
|
||||
}
|
||||
|
||||
// These three functions are not ever called in an unsafe context, so it's OK
|
||||
// to allocate memory and use libc.
|
||||
static string bytes_to_hex_string(const uint8_t* bytes, size_t count) {
|
||||
string result;
|
||||
for (unsigned int idx = 0; idx < count; ++idx) {
|
||||
char buf[3];
|
||||
snprintf(buf, sizeof(buf), "%02X", bytes[idx]);
|
||||
result.append(buf);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
string FileID::ConvertIdentifierToUUIDString(
|
||||
const wasteful_vector<uint8_t>& identifier) {
|
||||
uint8_t identifier_swapped[kMDGUIDSize] = { 0 };
|
||||
|
||||
// Endian-ness swap to match dump processor expectation.
|
||||
memcpy(identifier_swapped, &identifier[0],
|
||||
std::min(kMDGUIDSize, identifier.size()));
|
||||
uint32_t* data1 = reinterpret_cast<uint32_t*>(identifier_swapped);
|
||||
*data1 = htonl(*data1);
|
||||
uint16_t* data2 = reinterpret_cast<uint16_t*>(identifier_swapped + 4);
|
||||
*data2 = htons(*data2);
|
||||
uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6);
|
||||
*data3 = htons(*data3);
|
||||
|
||||
return bytes_to_hex_string(identifier_swapped, kMDGUIDSize);
|
||||
}
|
||||
|
||||
// static
|
||||
string FileID::ConvertIdentifierToString(
|
||||
const wasteful_vector<uint8_t>& identifier) {
|
||||
return bytes_to_hex_string(&identifier[0], identifier.size());
|
||||
}
|
||||
|
||||
} // elf
|
||||
} // namespace google_breakpad
|
||||
89
externals/breakpad/src/common/linux/file_id.h
vendored
Normal file
89
externals/breakpad/src/common/linux/file_id.h
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright 2006 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// file_id.h: Return a unique identifier for a file
|
||||
//
|
||||
|
||||
#ifndef COMMON_LINUX_FILE_ID_H__
|
||||
#define COMMON_LINUX_FILE_ID_H__
|
||||
|
||||
#include <limits.h>
|
||||
#include <string>
|
||||
|
||||
#include "common/linux/guid_creator.h"
|
||||
#include "common/memory_allocator.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
namespace elf {
|
||||
|
||||
// GNU binutils' ld defaults to 'sha1', which is 160 bits == 20 bytes,
|
||||
// so this is enough to fit that, which most binaries will use.
|
||||
// This is just a sensible default for auto_wasteful_vector so most
|
||||
// callers can get away with stack allocation.
|
||||
static const size_t kDefaultBuildIdSize = 20;
|
||||
|
||||
class FileID {
|
||||
public:
|
||||
explicit FileID(const char* path);
|
||||
~FileID() {}
|
||||
|
||||
// Load the identifier for the elf file path specified in the constructor into
|
||||
// |identifier|.
|
||||
//
|
||||
// The current implementation will look for a .note.gnu.build-id
|
||||
// section and use that as the file id, otherwise it falls back to
|
||||
// XORing the first 4096 bytes of the .text section to generate an identifier.
|
||||
bool ElfFileIdentifier(wasteful_vector<uint8_t>& identifier);
|
||||
|
||||
// Load the identifier for the elf file mapped into memory at |base| into
|
||||
// |identifier|. Return false if the identifier could not be created for this
|
||||
// file.
|
||||
static bool ElfFileIdentifierFromMappedFile(
|
||||
const void* base,
|
||||
wasteful_vector<uint8_t>& identifier);
|
||||
|
||||
// Convert the |identifier| data to a string. The string will
|
||||
// be formatted as a UUID in all uppercase without dashes.
|
||||
// (e.g., 22F065BBFC9C49F780FE26A7CEBD7BCE).
|
||||
static string ConvertIdentifierToUUIDString(
|
||||
const wasteful_vector<uint8_t>& identifier);
|
||||
|
||||
// Convert the entire |identifier| data to a hex string.
|
||||
static string ConvertIdentifierToString(
|
||||
const wasteful_vector<uint8_t>& identifier);
|
||||
|
||||
private:
|
||||
// Storage for the path specified
|
||||
string path_;
|
||||
};
|
||||
|
||||
} // namespace elf
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_FILE_ID_H__
|
||||
386
externals/breakpad/src/common/linux/file_id_unittest.cc
vendored
Normal file
386
externals/breakpad/src/common/linux/file_id_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,386 @@
|
|||
// Copyright 2010 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Unit tests for FileID
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <elf.h>
|
||||
#include <spawn.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/linux/elf_gnu_compat.h"
|
||||
#include "common/linux/elfutils.h"
|
||||
#include "common/linux/file_id.h"
|
||||
#include "common/linux/safe_readlink.h"
|
||||
#include "common/linux/synth_elf.h"
|
||||
#include "common/test_assembler.h"
|
||||
#include "common/tests/auto_tempdir.h"
|
||||
#include "common/tests/file_utils.h"
|
||||
#include "common/using_std_string.h"
|
||||
#include "breakpad_googletest_includes.h"
|
||||
|
||||
using namespace google_breakpad;
|
||||
using google_breakpad::elf::FileID;
|
||||
using google_breakpad::elf::kDefaultBuildIdSize;
|
||||
using google_breakpad::synth_elf::ELF;
|
||||
using google_breakpad::synth_elf::Notes;
|
||||
using google_breakpad::test_assembler::kLittleEndian;
|
||||
using google_breakpad::test_assembler::Section;
|
||||
using std::vector;
|
||||
using ::testing::Types;
|
||||
|
||||
namespace {
|
||||
|
||||
// Simply calling Section::Append(size, byte) produces a uninteresting pattern
|
||||
// that tends to get hashed to 0000...0000. This populates the section with
|
||||
// data to produce better hashes.
|
||||
void PopulateSection(Section* section, int size, int prime_number) {
|
||||
for (int i = 0; i < size; i++)
|
||||
section->Append(1, (i % prime_number) % 256);
|
||||
}
|
||||
|
||||
typedef wasteful_vector<uint8_t> id_vector;
|
||||
|
||||
} // namespace
|
||||
|
||||
#ifndef __ANDROID__
|
||||
// This test is disabled on Android: It will always fail, since there is no
|
||||
// 'strip' binary installed on test devices.
|
||||
TEST(FileIDStripTest, StripSelf) {
|
||||
// Calculate the File ID of this binary using
|
||||
// FileID::ElfFileIdentifier, then make a copy of this binary,
|
||||
// strip it, and ensure that the result is the same.
|
||||
char exe_name[PATH_MAX];
|
||||
ASSERT_TRUE(SafeReadLink("/proc/self/exe", exe_name));
|
||||
|
||||
// copy our binary to a temp file, and strip it
|
||||
AutoTempDir temp_dir;
|
||||
string templ = temp_dir.path() + "/file-id-unittest";
|
||||
ASSERT_TRUE(CopyFile(exe_name, templ));
|
||||
pid_t pid;
|
||||
char* argv[] = {
|
||||
const_cast<char*>("strip"),
|
||||
const_cast<char*>(templ.c_str()),
|
||||
nullptr,
|
||||
};
|
||||
ASSERT_EQ(0, posix_spawnp(&pid, argv[0], nullptr, nullptr, argv, nullptr));
|
||||
int status;
|
||||
ASSERT_EQ(pid, waitpid(pid, &status, 0));
|
||||
ASSERT_TRUE(WIFEXITED(status));
|
||||
ASSERT_EQ(0, WEXITSTATUS(status));
|
||||
|
||||
PageAllocator allocator;
|
||||
id_vector identifier1(&allocator, kDefaultBuildIdSize);
|
||||
id_vector identifier2(&allocator, kDefaultBuildIdSize);
|
||||
|
||||
FileID fileid1(exe_name);
|
||||
EXPECT_TRUE(fileid1.ElfFileIdentifier(identifier1));
|
||||
FileID fileid2(templ.c_str());
|
||||
EXPECT_TRUE(fileid2.ElfFileIdentifier(identifier2));
|
||||
|
||||
string identifier_string1 =
|
||||
FileID::ConvertIdentifierToUUIDString(identifier1);
|
||||
string identifier_string2 =
|
||||
FileID::ConvertIdentifierToUUIDString(identifier2);
|
||||
EXPECT_EQ(identifier_string1, identifier_string2);
|
||||
}
|
||||
#endif // !__ANDROID__
|
||||
|
||||
template<typename ElfClass>
|
||||
class FileIDTest : public testing::Test {
|
||||
public:
|
||||
void GetElfContents(ELF& elf) {
|
||||
string contents;
|
||||
ASSERT_TRUE(elf.GetContents(&contents));
|
||||
ASSERT_LT(0U, contents.size());
|
||||
|
||||
elfdata_v.clear();
|
||||
elfdata_v.insert(elfdata_v.begin(), contents.begin(), contents.end());
|
||||
elfdata = &elfdata_v[0];
|
||||
}
|
||||
|
||||
id_vector make_vector() {
|
||||
return id_vector(&allocator, kDefaultBuildIdSize);
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
string get_file_id(const uint8_t (&data)[N]) {
|
||||
id_vector expected_identifier(make_vector());
|
||||
expected_identifier.insert(expected_identifier.end(),
|
||||
&data[0],
|
||||
data + N);
|
||||
return FileID::ConvertIdentifierToUUIDString(expected_identifier);
|
||||
}
|
||||
|
||||
vector<uint8_t> elfdata_v;
|
||||
uint8_t* elfdata;
|
||||
PageAllocator allocator;
|
||||
};
|
||||
|
||||
typedef Types<ElfClass32, ElfClass64> ElfClasses;
|
||||
|
||||
TYPED_TEST_SUITE(FileIDTest, ElfClasses);
|
||||
|
||||
TYPED_TEST(FileIDTest, ElfClass) {
|
||||
const char expected_identifier_string[] =
|
||||
"80808080808000000000008080808080";
|
||||
const size_t kTextSectionSize = 128;
|
||||
|
||||
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section text(kLittleEndian);
|
||||
for (size_t i = 0; i < kTextSectionSize; ++i) {
|
||||
text.D8(i * 3);
|
||||
}
|
||||
elf.AddSection(".text", text, SHT_PROGBITS);
|
||||
elf.Finish();
|
||||
this->GetElfContents(elf);
|
||||
|
||||
id_vector identifier(this->make_vector());
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier));
|
||||
|
||||
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
|
||||
EXPECT_EQ(expected_identifier_string, identifier_string);
|
||||
}
|
||||
|
||||
TYPED_TEST(FileIDTest, BuildID) {
|
||||
const uint8_t kExpectedIdentifierBytes[] =
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13};
|
||||
const string expected_identifier_string =
|
||||
this->get_file_id(kExpectedIdentifierBytes);
|
||||
|
||||
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section text(kLittleEndian);
|
||||
text.Append(4096, 0);
|
||||
elf.AddSection(".text", text, SHT_PROGBITS);
|
||||
Notes notes(kLittleEndian);
|
||||
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
|
||||
sizeof(kExpectedIdentifierBytes));
|
||||
elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
|
||||
elf.Finish();
|
||||
this->GetElfContents(elf);
|
||||
|
||||
id_vector identifier(this->make_vector());
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier));
|
||||
EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
|
||||
|
||||
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
|
||||
EXPECT_EQ(expected_identifier_string, identifier_string);
|
||||
}
|
||||
|
||||
// Test that a build id note with fewer bytes than usual is handled.
|
||||
TYPED_TEST(FileIDTest, BuildIDShort) {
|
||||
const uint8_t kExpectedIdentifierBytes[] =
|
||||
{0x00, 0x01, 0x02, 0x03};
|
||||
const string expected_identifier_string =
|
||||
this->get_file_id(kExpectedIdentifierBytes);
|
||||
|
||||
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section text(kLittleEndian);
|
||||
text.Append(4096, 0);
|
||||
elf.AddSection(".text", text, SHT_PROGBITS);
|
||||
Notes notes(kLittleEndian);
|
||||
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
|
||||
sizeof(kExpectedIdentifierBytes));
|
||||
elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
|
||||
elf.Finish();
|
||||
this->GetElfContents(elf);
|
||||
|
||||
id_vector identifier(this->make_vector());
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier));
|
||||
EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
|
||||
|
||||
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
|
||||
EXPECT_EQ(expected_identifier_string, identifier_string);
|
||||
}
|
||||
|
||||
// Test that a build id note with more bytes than usual is handled.
|
||||
TYPED_TEST(FileIDTest, BuildIDLong) {
|
||||
const uint8_t kExpectedIdentifierBytes[] =
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
|
||||
const string expected_identifier_string =
|
||||
this->get_file_id(kExpectedIdentifierBytes);
|
||||
|
||||
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section text(kLittleEndian);
|
||||
text.Append(4096, 0);
|
||||
elf.AddSection(".text", text, SHT_PROGBITS);
|
||||
Notes notes(kLittleEndian);
|
||||
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
|
||||
sizeof(kExpectedIdentifierBytes));
|
||||
elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
|
||||
elf.Finish();
|
||||
this->GetElfContents(elf);
|
||||
|
||||
id_vector identifier(this->make_vector());
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier));
|
||||
EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
|
||||
|
||||
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
|
||||
EXPECT_EQ(expected_identifier_string, identifier_string);
|
||||
}
|
||||
|
||||
TYPED_TEST(FileIDTest, BuildIDPH) {
|
||||
const uint8_t kExpectedIdentifierBytes[] =
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13};
|
||||
const string expected_identifier_string =
|
||||
this->get_file_id(kExpectedIdentifierBytes);
|
||||
|
||||
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section text(kLittleEndian);
|
||||
text.Append(4096, 0);
|
||||
elf.AddSection(".text", text, SHT_PROGBITS);
|
||||
Notes notes(kLittleEndian);
|
||||
notes.AddNote(0, "Linux",
|
||||
reinterpret_cast<const uint8_t*>("\0x42\0x02\0\0"), 4);
|
||||
notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
|
||||
sizeof(kExpectedIdentifierBytes));
|
||||
int note_idx = elf.AddSection(".note", notes, SHT_NOTE);
|
||||
elf.AddSegment(note_idx, note_idx, PT_NOTE);
|
||||
elf.Finish();
|
||||
this->GetElfContents(elf);
|
||||
|
||||
id_vector identifier(this->make_vector());
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier));
|
||||
EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
|
||||
|
||||
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
|
||||
EXPECT_EQ(expected_identifier_string, identifier_string);
|
||||
}
|
||||
|
||||
TYPED_TEST(FileIDTest, BuildIDMultiplePH) {
|
||||
const uint8_t kExpectedIdentifierBytes[] =
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13};
|
||||
const string expected_identifier_string =
|
||||
this->get_file_id(kExpectedIdentifierBytes);
|
||||
|
||||
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section text(kLittleEndian);
|
||||
text.Append(4096, 0);
|
||||
elf.AddSection(".text", text, SHT_PROGBITS);
|
||||
Notes notes1(kLittleEndian);
|
||||
notes1.AddNote(0, "Linux",
|
||||
reinterpret_cast<const uint8_t*>("\0x42\0x02\0\0"), 4);
|
||||
Notes notes2(kLittleEndian);
|
||||
notes2.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
|
||||
sizeof(kExpectedIdentifierBytes));
|
||||
int note1_idx = elf.AddSection(".note1", notes1, SHT_NOTE);
|
||||
int note2_idx = elf.AddSection(".note2", notes2, SHT_NOTE);
|
||||
elf.AddSegment(note1_idx, note1_idx, PT_NOTE);
|
||||
elf.AddSegment(note2_idx, note2_idx, PT_NOTE);
|
||||
elf.Finish();
|
||||
this->GetElfContents(elf);
|
||||
|
||||
id_vector identifier(this->make_vector());
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier));
|
||||
EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
|
||||
|
||||
string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
|
||||
EXPECT_EQ(expected_identifier_string, identifier_string);
|
||||
}
|
||||
|
||||
// Test to make sure two files with different text sections produce
|
||||
// different hashes when not using a build id.
|
||||
TYPED_TEST(FileIDTest, UniqueHashes) {
|
||||
{
|
||||
ELF elf1(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section foo_1(kLittleEndian);
|
||||
PopulateSection(&foo_1, 32, 5);
|
||||
elf1.AddSection(".foo", foo_1, SHT_PROGBITS);
|
||||
Section text_1(kLittleEndian);
|
||||
PopulateSection(&text_1, 4096, 17);
|
||||
elf1.AddSection(".text", text_1, SHT_PROGBITS);
|
||||
elf1.Finish();
|
||||
this->GetElfContents(elf1);
|
||||
}
|
||||
|
||||
id_vector identifier_1(this->make_vector());
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier_1));
|
||||
string identifier_string_1 =
|
||||
FileID::ConvertIdentifierToUUIDString(identifier_1);
|
||||
|
||||
{
|
||||
ELF elf2(EM_386, TypeParam::kClass, kLittleEndian);
|
||||
Section text_2(kLittleEndian);
|
||||
Section foo_2(kLittleEndian);
|
||||
PopulateSection(&foo_2, 32, 5);
|
||||
elf2.AddSection(".foo", foo_2, SHT_PROGBITS);
|
||||
PopulateSection(&text_2, 4096, 31);
|
||||
elf2.AddSection(".text", text_2, SHT_PROGBITS);
|
||||
elf2.Finish();
|
||||
this->GetElfContents(elf2);
|
||||
}
|
||||
|
||||
id_vector identifier_2(this->make_vector());
|
||||
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
|
||||
identifier_2));
|
||||
string identifier_string_2 =
|
||||
FileID::ConvertIdentifierToUUIDString(identifier_2);
|
||||
|
||||
EXPECT_NE(identifier_string_1, identifier_string_2);
|
||||
}
|
||||
|
||||
TYPED_TEST(FileIDTest, ConvertIdentifierToString) {
|
||||
const uint8_t kIdentifierBytes[] =
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
|
||||
const char* kExpected =
|
||||
"000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F";
|
||||
|
||||
id_vector identifier(this->make_vector());
|
||||
identifier.insert(identifier.end(),
|
||||
kIdentifierBytes,
|
||||
kIdentifierBytes + sizeof(kIdentifierBytes));
|
||||
ASSERT_EQ(kExpected,
|
||||
FileID::ConvertIdentifierToString(identifier));
|
||||
}
|
||||
212
externals/breakpad/src/common/linux/google_crashdump_uploader.cc
vendored
Normal file
212
externals/breakpad/src/common/linux/google_crashdump_uploader.cc
vendored
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
// Copyright 2009 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/google_crashdump_uploader.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
GoogleCrashdumpUploader::GoogleCrashdumpUploader(const string& product,
|
||||
const string& version,
|
||||
const string& guid,
|
||||
const string& ptime,
|
||||
const string& ctime,
|
||||
const string& email,
|
||||
const string& comments,
|
||||
const string& minidump_pathname,
|
||||
const string& crash_server,
|
||||
const string& proxy_host,
|
||||
const string& proxy_userpassword) {
|
||||
std::unique_ptr<LibcurlWrapper> http_layer{new LibcurlWrapper()};
|
||||
Init(product,
|
||||
version,
|
||||
guid,
|
||||
ptime,
|
||||
ctime,
|
||||
email,
|
||||
comments,
|
||||
minidump_pathname,
|
||||
crash_server,
|
||||
proxy_host,
|
||||
proxy_userpassword,
|
||||
std::move(http_layer));
|
||||
}
|
||||
|
||||
GoogleCrashdumpUploader::GoogleCrashdumpUploader(
|
||||
const string& product,
|
||||
const string& version,
|
||||
const string& guid,
|
||||
const string& ptime,
|
||||
const string& ctime,
|
||||
const string& email,
|
||||
const string& comments,
|
||||
const string& minidump_pathname,
|
||||
const string& crash_server,
|
||||
const string& proxy_host,
|
||||
const string& proxy_userpassword,
|
||||
std::unique_ptr<LibcurlWrapper> http_layer) {
|
||||
Init(product,
|
||||
version,
|
||||
guid,
|
||||
ptime,
|
||||
ctime,
|
||||
email,
|
||||
comments,
|
||||
minidump_pathname,
|
||||
crash_server,
|
||||
proxy_host,
|
||||
proxy_userpassword,
|
||||
std::move(http_layer));
|
||||
}
|
||||
|
||||
void GoogleCrashdumpUploader::Init(const string& product,
|
||||
const string& version,
|
||||
const string& guid,
|
||||
const string& ptime,
|
||||
const string& ctime,
|
||||
const string& email,
|
||||
const string& comments,
|
||||
const string& minidump_pathname,
|
||||
const string& crash_server,
|
||||
const string& proxy_host,
|
||||
const string& proxy_userpassword,
|
||||
std::unique_ptr<LibcurlWrapper> http_layer) {
|
||||
product_ = product;
|
||||
version_ = version;
|
||||
guid_ = guid;
|
||||
ptime_ = ptime;
|
||||
ctime_ = ctime;
|
||||
email_ = email;
|
||||
comments_ = comments;
|
||||
http_layer_ = std::move(http_layer);
|
||||
|
||||
crash_server_ = crash_server;
|
||||
proxy_host_ = proxy_host;
|
||||
proxy_userpassword_ = proxy_userpassword;
|
||||
minidump_pathname_ = minidump_pathname;
|
||||
std::cout << "Uploader initializing";
|
||||
std::cout << "\tProduct: " << product_;
|
||||
std::cout << "\tVersion: " << version_;
|
||||
std::cout << "\tGUID: " << guid_;
|
||||
if (!ptime_.empty()) {
|
||||
std::cout << "\tProcess uptime: " << ptime_;
|
||||
}
|
||||
if (!ctime_.empty()) {
|
||||
std::cout << "\tCumulative Process uptime: " << ctime_;
|
||||
}
|
||||
if (!email_.empty()) {
|
||||
std::cout << "\tEmail: " << email_;
|
||||
}
|
||||
if (!comments_.empty()) {
|
||||
std::cout << "\tComments: " << comments_;
|
||||
}
|
||||
}
|
||||
|
||||
bool GoogleCrashdumpUploader::CheckRequiredParametersArePresent() {
|
||||
string error_text;
|
||||
if (product_.empty()) {
|
||||
error_text.append("\nProduct name must be specified.");
|
||||
}
|
||||
|
||||
if (version_.empty()) {
|
||||
error_text.append("\nProduct version must be specified.");
|
||||
}
|
||||
|
||||
if (guid_.empty()) {
|
||||
error_text.append("\nClient ID must be specified.");
|
||||
}
|
||||
|
||||
if (minidump_pathname_.empty()) {
|
||||
error_text.append("\nMinidump pathname must be specified.");
|
||||
}
|
||||
|
||||
if (!error_text.empty()) {
|
||||
std::cout << error_text;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool GoogleCrashdumpUploader::Upload(int* http_status_code,
|
||||
string* http_response_header,
|
||||
string* http_response_body) {
|
||||
bool ok = http_layer_->Init();
|
||||
if (!ok) {
|
||||
std::cout << "http layer init failed";
|
||||
return ok;
|
||||
}
|
||||
|
||||
if (!CheckRequiredParametersArePresent()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct stat st;
|
||||
int err = stat(minidump_pathname_.c_str(), &st);
|
||||
if (err) {
|
||||
std::cout << minidump_pathname_ << " could not be found";
|
||||
return false;
|
||||
}
|
||||
|
||||
parameters_["prod"] = product_;
|
||||
parameters_["ver"] = version_;
|
||||
parameters_["guid"] = guid_;
|
||||
parameters_["ptime"] = ptime_;
|
||||
parameters_["ctime"] = ctime_;
|
||||
parameters_["email"] = email_;
|
||||
parameters_["comments_"] = comments_;
|
||||
if (!http_layer_->AddFile(minidump_pathname_,
|
||||
"upload_file_minidump")) {
|
||||
return false;
|
||||
}
|
||||
std::cout << "Sending request to " << crash_server_;
|
||||
long status_code;
|
||||
bool success = http_layer_->SendRequest(crash_server_,
|
||||
parameters_,
|
||||
&status_code,
|
||||
http_response_header,
|
||||
http_response_body);
|
||||
if (http_status_code) {
|
||||
*http_status_code = status_code;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
||||
106
externals/breakpad/src/common/linux/google_crashdump_uploader.h
vendored
Normal file
106
externals/breakpad/src/common/linux/google_crashdump_uploader.h
vendored
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2009 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
#ifndef COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_
|
||||
#define COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "common/linux/libcurl_wrapper.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
class GoogleCrashdumpUploader {
|
||||
public:
|
||||
GoogleCrashdumpUploader(const string& product,
|
||||
const string& version,
|
||||
const string& guid,
|
||||
const string& ptime,
|
||||
const string& ctime,
|
||||
const string& email,
|
||||
const string& comments,
|
||||
const string& minidump_pathname,
|
||||
const string& crash_server,
|
||||
const string& proxy_host,
|
||||
const string& proxy_userpassword);
|
||||
|
||||
GoogleCrashdumpUploader(const string& product,
|
||||
const string& version,
|
||||
const string& guid,
|
||||
const string& ptime,
|
||||
const string& ctime,
|
||||
const string& email,
|
||||
const string& comments,
|
||||
const string& minidump_pathname,
|
||||
const string& crash_server,
|
||||
const string& proxy_host,
|
||||
const string& proxy_userpassword,
|
||||
std::unique_ptr<LibcurlWrapper> http_layer);
|
||||
|
||||
void Init(const string& product,
|
||||
const string& version,
|
||||
const string& guid,
|
||||
const string& ptime,
|
||||
const string& ctime,
|
||||
const string& email,
|
||||
const string& comments,
|
||||
const string& minidump_pathname,
|
||||
const string& crash_server,
|
||||
const string& proxy_host,
|
||||
const string& proxy_userpassword,
|
||||
std::unique_ptr<LibcurlWrapper> http_layer);
|
||||
bool Upload(int* http_status_code,
|
||||
string* http_response_header,
|
||||
string* http_response_body);
|
||||
|
||||
private:
|
||||
bool CheckRequiredParametersArePresent();
|
||||
|
||||
std::unique_ptr<LibcurlWrapper> http_layer_;
|
||||
string product_;
|
||||
string version_;
|
||||
string guid_;
|
||||
string ptime_;
|
||||
string ctime_;
|
||||
string email_;
|
||||
string comments_;
|
||||
string minidump_pathname_;
|
||||
|
||||
string crash_server_;
|
||||
string proxy_host_;
|
||||
string proxy_userpassword_;
|
||||
|
||||
std::map<string, string> parameters_;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // COMMON_LINUX_GOOGLE_CRASHDUMP_UPLOADER_H_
|
||||
147
externals/breakpad/src/common/linux/google_crashdump_uploader_test.cc
vendored
Normal file
147
externals/breakpad/src/common/linux/google_crashdump_uploader_test.cc
vendored
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
// Copyright 2009 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Unit test for crash dump uploader.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "common/linux/google_crashdump_uploader.h"
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using ::testing::Return;
|
||||
using ::testing::_;
|
||||
|
||||
class MockLibcurlWrapper : public LibcurlWrapper {
|
||||
public:
|
||||
MOCK_METHOD0(Init, bool());
|
||||
MOCK_METHOD2(SetProxy, bool(const string& proxy_host,
|
||||
const string& proxy_userpwd));
|
||||
MOCK_METHOD2(AddFile, bool(const string& upload_file_path,
|
||||
const string& basename));
|
||||
MOCK_METHOD5(SendRequest,
|
||||
bool(const string& url,
|
||||
const std::map<string, string>& parameters,
|
||||
long* http_status_code,
|
||||
string* http_header_data,
|
||||
string* http_response_data));
|
||||
};
|
||||
|
||||
class GoogleCrashdumpUploaderTest : public ::testing::Test {
|
||||
};
|
||||
|
||||
TEST_F(GoogleCrashdumpUploaderTest, InitFailsCausesUploadFailure) {
|
||||
std::unique_ptr<MockLibcurlWrapper> m{new MockLibcurlWrapper()};
|
||||
EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(false));
|
||||
GoogleCrashdumpUploader uploader("foobar", "1.0", "AAA-BBB", "", "",
|
||||
"test@test.com", "none", "/tmp/foo.dmp",
|
||||
"http://foo.com", "", "", std::move(m));
|
||||
ASSERT_FALSE(uploader.Upload(NULL, NULL, NULL));
|
||||
}
|
||||
|
||||
TEST_F(GoogleCrashdumpUploaderTest, TestSendRequestHappensWithValidParameters) {
|
||||
// Create a temp file
|
||||
char tempfn[80] = "/tmp/googletest-upload-XXXXXX";
|
||||
int fd = mkstemp(tempfn);
|
||||
ASSERT_NE(fd, -1);
|
||||
close(fd);
|
||||
|
||||
std::unique_ptr<MockLibcurlWrapper> m{new MockLibcurlWrapper()};
|
||||
EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true));
|
||||
EXPECT_CALL(*m, AddFile(tempfn, _)).WillOnce(Return(true));
|
||||
EXPECT_CALL(*m, SendRequest("http://foo.com", _, _, _, _))
|
||||
.Times(1)
|
||||
.WillOnce(Return(true));
|
||||
GoogleCrashdumpUploader uploader("foobar", "1.0", "AAA-BBB", "", "",
|
||||
"test@test.com", "none", tempfn,
|
||||
"http://foo.com", "", "", std::move(m));
|
||||
ASSERT_TRUE(uploader.Upload(NULL, NULL, NULL));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(GoogleCrashdumpUploaderTest, InvalidPathname) {
|
||||
std::unique_ptr<MockLibcurlWrapper> m{new MockLibcurlWrapper()};
|
||||
EXPECT_CALL(*m, Init()).Times(1).WillOnce(Return(true));
|
||||
EXPECT_CALL(*m, SendRequest(_,_,_,_,_)).Times(0);
|
||||
GoogleCrashdumpUploader uploader("foobar", "1.0", "AAA-BBB", "", "",
|
||||
"test@test.com", "none", "/tmp/foo.dmp",
|
||||
"http://foo.com", "", "", std::move(m));
|
||||
ASSERT_FALSE(uploader.Upload(NULL, NULL, NULL));
|
||||
}
|
||||
|
||||
TEST_F(GoogleCrashdumpUploaderTest, TestRequiredParametersMustBePresent) {
|
||||
// Test with empty product name.
|
||||
GoogleCrashdumpUploader uploader("",
|
||||
"1.0",
|
||||
"AAA-BBB",
|
||||
"",
|
||||
"",
|
||||
"test@test.com",
|
||||
"none",
|
||||
"/tmp/foo.dmp",
|
||||
"http://foo.com",
|
||||
"",
|
||||
"");
|
||||
ASSERT_FALSE(uploader.Upload(NULL, NULL, NULL));
|
||||
|
||||
// Test with empty product version.
|
||||
GoogleCrashdumpUploader uploader1("product",
|
||||
"",
|
||||
"AAA-BBB",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"/tmp/foo.dmp",
|
||||
"",
|
||||
"",
|
||||
"");
|
||||
|
||||
ASSERT_FALSE(uploader1.Upload(NULL, NULL, NULL));
|
||||
|
||||
// Test with empty client GUID.
|
||||
GoogleCrashdumpUploader uploader2("product",
|
||||
"1.0",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"/tmp/foo.dmp",
|
||||
"",
|
||||
"",
|
||||
"");
|
||||
ASSERT_FALSE(uploader2.Upload(NULL, NULL, NULL));
|
||||
}
|
||||
}
|
||||
188
externals/breakpad/src/common/linux/guid_creator.cc
vendored
Normal file
188
externals/breakpad/src/common/linux/guid_creator.cc
vendored
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
// Copyright 2006 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/eintr_wrapper.h"
|
||||
#include "common/linux/guid_creator.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(HAVE_SYS_RANDOM_H)
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
|
||||
//
|
||||
// GUIDGenerator
|
||||
//
|
||||
// This class is used to generate random GUID.
|
||||
// Currently use random number to generate a GUID since Linux has
|
||||
// no native GUID generator. This should be OK since we don't expect
|
||||
// crash to happen very offen.
|
||||
//
|
||||
class GUIDGenerator {
|
||||
public:
|
||||
static uint32_t BytesToUInt32(const uint8_t bytes[]) {
|
||||
return ((uint32_t) bytes[0]
|
||||
| ((uint32_t) bytes[1] << 8)
|
||||
| ((uint32_t) bytes[2] << 16)
|
||||
| ((uint32_t) bytes[3] << 24));
|
||||
}
|
||||
|
||||
static void UInt32ToBytes(uint8_t bytes[], uint32_t n) {
|
||||
bytes[0] = n & 0xff;
|
||||
bytes[1] = (n >> 8) & 0xff;
|
||||
bytes[2] = (n >> 16) & 0xff;
|
||||
bytes[3] = (n >> 24) & 0xff;
|
||||
}
|
||||
|
||||
static bool CreateGUID(GUID *guid) {
|
||||
#if defined(HAVE_ARC4RANDOM) // Android, BSD, ...
|
||||
CreateGuidFromArc4Random(guid);
|
||||
#else // Linux
|
||||
bool success = false;
|
||||
|
||||
#if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM)
|
||||
success = CreateGUIDFromGetrandom(guid);
|
||||
#endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM
|
||||
if (!success) {
|
||||
success = CreateGUIDFromDevUrandom(guid);
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
CreateGUIDFromRand(guid);
|
||||
success = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Put in the version according to RFC 4122.
|
||||
guid->data3 &= 0x0fff;
|
||||
guid->data3 |= 0x4000;
|
||||
|
||||
// Put in the variant according to RFC 4122.
|
||||
guid->data4[0] &= 0x3f;
|
||||
guid->data4[0] |= 0x80;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef HAVE_ARC4RANDOM
|
||||
static void CreateGuidFromArc4Random(GUID *guid) {
|
||||
char *buf = reinterpret_cast<char*>(guid);
|
||||
|
||||
for (size_t i = 0; i < sizeof(GUID); i += sizeof(uint32_t)) {
|
||||
uint32_t random_data = arc4random();
|
||||
|
||||
memcpy(buf + i, &random_data, sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void InitOnce() {
|
||||
pthread_once(&once_control, &InitOnceImpl);
|
||||
}
|
||||
|
||||
static void InitOnceImpl() {
|
||||
// time(NULL) is a very poor seed, so lacking anything better mix an
|
||||
// address into it. We drop the four rightmost bits as they're likely to
|
||||
// be 0 on almost all architectures.
|
||||
srand(time(NULL) | ((uintptr_t)&once_control >> 4));
|
||||
}
|
||||
|
||||
static pthread_once_t once_control;
|
||||
|
||||
#if defined(HAVE_SYS_RANDOM_H) && defined(HAVE_GETRANDOM)
|
||||
static bool CreateGUIDFromGetrandom(GUID *guid) {
|
||||
char *buf = reinterpret_cast<char*>(guid);
|
||||
int read_bytes = getrandom(buf, sizeof(GUID), GRND_NONBLOCK);
|
||||
|
||||
return (read_bytes == static_cast<int>(sizeof(GUID)));
|
||||
}
|
||||
#endif // HAVE_SYS_RANDOM_H && HAVE_GETRANDOM
|
||||
|
||||
// Populate the GUID using random bytes read from /dev/urandom, returns false
|
||||
// if the GUID wasn't fully populated with random data.
|
||||
static bool CreateGUIDFromDevUrandom(GUID *guid) {
|
||||
char *buf = reinterpret_cast<char*>(guid);
|
||||
int fd = open("/dev/urandom", O_RDONLY | O_CLOEXEC);
|
||||
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ssize_t read_bytes = HANDLE_EINTR(read(fd, buf, sizeof(GUID)));
|
||||
close(fd);
|
||||
|
||||
return (read_bytes == static_cast<ssize_t>(sizeof(GUID)));
|
||||
}
|
||||
|
||||
// Populate the GUID using a stream of random bytes obtained from rand().
|
||||
static void CreateGUIDFromRand(GUID *guid) {
|
||||
char *buf = reinterpret_cast<char*>(guid);
|
||||
|
||||
InitOnce();
|
||||
|
||||
for (size_t i = 0; i < sizeof(GUID); i++) {
|
||||
buf[i] = rand();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef HAVE_ARC4RANDOM
|
||||
pthread_once_t GUIDGenerator::once_control = PTHREAD_ONCE_INIT;
|
||||
#endif
|
||||
|
||||
bool CreateGUID(GUID *guid) {
|
||||
return GUIDGenerator::CreateGUID(guid);
|
||||
}
|
||||
|
||||
// Parse guid to string.
|
||||
bool GUIDToString(const GUID *guid, char *buf, int buf_len) {
|
||||
// Should allow more space the the max length of GUID.
|
||||
assert(buf_len > kGUIDStringLength);
|
||||
int num = snprintf(buf, buf_len, kGUIDFormatString,
|
||||
guid->data1, guid->data2, guid->data3,
|
||||
GUIDGenerator::BytesToUInt32(&(guid->data4[0])),
|
||||
GUIDGenerator::BytesToUInt32(&(guid->data4[4])));
|
||||
if (num != kGUIDStringLength)
|
||||
return false;
|
||||
|
||||
buf[num] = '\0';
|
||||
return true;
|
||||
}
|
||||
47
externals/breakpad/src/common/linux/guid_creator.h
vendored
Normal file
47
externals/breakpad/src/common/linux/guid_creator.h
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright 2006 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef COMMON_LINUX_GUID_CREATOR_H__
|
||||
#define COMMON_LINUX_GUID_CREATOR_H__
|
||||
|
||||
#include "google_breakpad/common/minidump_format.h"
|
||||
|
||||
typedef MDGUID GUID;
|
||||
|
||||
// Format string for parsing GUID.
|
||||
#define kGUIDFormatString "%08x-%04x-%04x-%08x-%08x"
|
||||
// Length of GUID string. Don't count the ending '\0'.
|
||||
#define kGUIDStringLength 36
|
||||
|
||||
// Create a guid.
|
||||
bool CreateGUID(GUID *guid);
|
||||
|
||||
// Get the string from guid.
|
||||
bool GUIDToString(const GUID *guid, char *buf, int buf_len);
|
||||
|
||||
#endif
|
||||
233
externals/breakpad/src/common/linux/http_upload.cc
vendored
Normal file
233
externals/breakpad/src/common/linux/http_upload.cc
vendored
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
// Copyright 2006 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/http_upload.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
#include "third_party/curl/curl.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// Callback to get the response data from server.
|
||||
static size_t WriteCallback(void* ptr, size_t size,
|
||||
size_t nmemb, void* userp) {
|
||||
if (!userp)
|
||||
return 0;
|
||||
|
||||
string* response = reinterpret_cast<string*>(userp);
|
||||
size_t real_size = size * nmemb;
|
||||
response->append(reinterpret_cast<char*>(ptr), real_size);
|
||||
return real_size;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
static const char kUserAgent[] = "Breakpad/1.0 (Linux)";
|
||||
|
||||
// static
|
||||
bool HTTPUpload::SendRequest(const string& url,
|
||||
const map<string, string>& parameters,
|
||||
const map<string, string>& files,
|
||||
const string& proxy,
|
||||
const string& proxy_user_pwd,
|
||||
const string& ca_certificate_file,
|
||||
string* response_body,
|
||||
long* response_code,
|
||||
string* error_description) {
|
||||
if (response_code != NULL)
|
||||
*response_code = 0;
|
||||
|
||||
if (!CheckParameters(parameters))
|
||||
return false;
|
||||
|
||||
// We may have been linked statically; if curl_easy_init is in the
|
||||
// current binary, no need to search for a dynamic version.
|
||||
void* curl_lib = dlopen(NULL, RTLD_NOW);
|
||||
if (!CheckCurlLib(curl_lib)) {
|
||||
fprintf(stderr,
|
||||
"Failed to open curl lib from binary, use libcurl.so instead\n");
|
||||
dlerror(); // Clear dlerror before attempting to open libraries.
|
||||
dlclose(curl_lib);
|
||||
curl_lib = NULL;
|
||||
}
|
||||
if (!curl_lib) {
|
||||
curl_lib = dlopen("libcurl.so", RTLD_NOW);
|
||||
}
|
||||
if (!curl_lib) {
|
||||
if (error_description != NULL)
|
||||
*error_description = dlerror();
|
||||
curl_lib = dlopen("libcurl.so.4", RTLD_NOW);
|
||||
}
|
||||
if (!curl_lib) {
|
||||
// Debian gives libcurl a different name when it is built against GnuTLS
|
||||
// instead of OpenSSL.
|
||||
curl_lib = dlopen("libcurl-gnutls.so.4", RTLD_NOW);
|
||||
}
|
||||
if (!curl_lib) {
|
||||
curl_lib = dlopen("libcurl.so.3", RTLD_NOW);
|
||||
}
|
||||
if (!curl_lib) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CURL* (*curl_easy_init)(void);
|
||||
*(void**) (&curl_easy_init) = dlsym(curl_lib, "curl_easy_init");
|
||||
CURL* curl = (*curl_easy_init)();
|
||||
if (error_description != NULL)
|
||||
*error_description = "No Error";
|
||||
|
||||
if (!curl) {
|
||||
dlclose(curl_lib);
|
||||
return false;
|
||||
}
|
||||
|
||||
CURLcode err_code = CURLE_OK;
|
||||
CURLcode (*curl_easy_setopt)(CURL*, CURLoption, ...);
|
||||
*(void**) (&curl_easy_setopt) = dlsym(curl_lib, "curl_easy_setopt");
|
||||
(*curl_easy_setopt)(curl, CURLOPT_URL, url.c_str());
|
||||
(*curl_easy_setopt)(curl, CURLOPT_USERAGENT, kUserAgent);
|
||||
// Support multithread by disabling timeout handling, would get SIGSEGV with
|
||||
// Curl_resolv_timeout in stack trace otherwise.
|
||||
// See https://curl.haxx.se/libcurl/c/threadsafe.html
|
||||
(*curl_easy_setopt)(curl, CURLOPT_NOSIGNAL, 1);
|
||||
// Set proxy information if necessary.
|
||||
if (!proxy.empty())
|
||||
(*curl_easy_setopt)(curl, CURLOPT_PROXY, proxy.c_str());
|
||||
if (!proxy_user_pwd.empty())
|
||||
(*curl_easy_setopt)(curl, CURLOPT_PROXYUSERPWD, proxy_user_pwd.c_str());
|
||||
|
||||
if (!ca_certificate_file.empty())
|
||||
(*curl_easy_setopt)(curl, CURLOPT_CAINFO, ca_certificate_file.c_str());
|
||||
|
||||
struct curl_httppost* formpost = NULL;
|
||||
struct curl_httppost* lastptr = NULL;
|
||||
// Add form data.
|
||||
CURLFORMcode (*curl_formadd)(struct curl_httppost**, struct curl_httppost**, ...);
|
||||
*(void**) (&curl_formadd) = dlsym(curl_lib, "curl_formadd");
|
||||
map<string, string>::const_iterator iter = parameters.begin();
|
||||
for (; iter != parameters.end(); ++iter)
|
||||
(*curl_formadd)(&formpost, &lastptr,
|
||||
CURLFORM_COPYNAME, iter->first.c_str(),
|
||||
CURLFORM_COPYCONTENTS, iter->second.c_str(),
|
||||
CURLFORM_END);
|
||||
|
||||
// Add form files.
|
||||
for (iter = files.begin(); iter != files.end(); ++iter) {
|
||||
(*curl_formadd)(&formpost, &lastptr,
|
||||
CURLFORM_COPYNAME, iter->first.c_str(),
|
||||
CURLFORM_FILE, iter->second.c_str(),
|
||||
CURLFORM_END);
|
||||
}
|
||||
|
||||
(*curl_easy_setopt)(curl, CURLOPT_HTTPPOST, formpost);
|
||||
|
||||
// Disable 100-continue header.
|
||||
struct curl_slist* headerlist = NULL;
|
||||
char buf[] = "Expect:";
|
||||
struct curl_slist* (*curl_slist_append)(struct curl_slist*, const char*);
|
||||
*(void**) (&curl_slist_append) = dlsym(curl_lib, "curl_slist_append");
|
||||
headerlist = (*curl_slist_append)(headerlist, buf);
|
||||
(*curl_easy_setopt)(curl, CURLOPT_HTTPHEADER, headerlist);
|
||||
|
||||
if (response_body != NULL) {
|
||||
(*curl_easy_setopt)(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
(*curl_easy_setopt)(curl, CURLOPT_WRITEDATA,
|
||||
reinterpret_cast<void*>(response_body));
|
||||
}
|
||||
|
||||
// Fail if 400+ is returned from the web server.
|
||||
(*curl_easy_setopt)(curl, CURLOPT_FAILONERROR, 1);
|
||||
|
||||
CURLcode (*curl_easy_perform)(CURL*);
|
||||
*(void**) (&curl_easy_perform) = dlsym(curl_lib, "curl_easy_perform");
|
||||
err_code = (*curl_easy_perform)(curl);
|
||||
if (response_code != NULL) {
|
||||
CURLcode (*curl_easy_getinfo)(CURL*, CURLINFO, ...);
|
||||
*(void**) (&curl_easy_getinfo) = dlsym(curl_lib, "curl_easy_getinfo");
|
||||
(*curl_easy_getinfo)(curl, CURLINFO_RESPONSE_CODE, response_code);
|
||||
}
|
||||
const char* (*curl_easy_strerror)(CURLcode);
|
||||
*(void**) (&curl_easy_strerror) = dlsym(curl_lib, "curl_easy_strerror");
|
||||
#ifndef NDEBUG
|
||||
if (err_code != CURLE_OK)
|
||||
fprintf(stderr, "Failed to send http request to %s, error: %s\n",
|
||||
url.c_str(),
|
||||
(*curl_easy_strerror)(err_code));
|
||||
#endif
|
||||
if (error_description != NULL)
|
||||
*error_description = (*curl_easy_strerror)(err_code);
|
||||
|
||||
void (*curl_easy_cleanup)(CURL*);
|
||||
*(void**) (&curl_easy_cleanup) = dlsym(curl_lib, "curl_easy_cleanup");
|
||||
(*curl_easy_cleanup)(curl);
|
||||
if (formpost != NULL) {
|
||||
void (*curl_formfree)(struct curl_httppost*);
|
||||
*(void**) (&curl_formfree) = dlsym(curl_lib, "curl_formfree");
|
||||
(*curl_formfree)(formpost);
|
||||
}
|
||||
if (headerlist != NULL) {
|
||||
void (*curl_slist_free_all)(struct curl_slist*);
|
||||
*(void**) (&curl_slist_free_all) = dlsym(curl_lib, "curl_slist_free_all");
|
||||
(*curl_slist_free_all)(headerlist);
|
||||
}
|
||||
dlclose(curl_lib);
|
||||
return err_code == CURLE_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
bool HTTPUpload::CheckCurlLib(void* curl_lib) {
|
||||
return curl_lib &&
|
||||
dlsym(curl_lib, "curl_easy_init") &&
|
||||
dlsym(curl_lib, "curl_easy_setopt");
|
||||
}
|
||||
|
||||
// static
|
||||
bool HTTPUpload::CheckParameters(const map<string, string>& parameters) {
|
||||
for (map<string, string>::const_iterator pos = parameters.begin();
|
||||
pos != parameters.end(); ++pos) {
|
||||
const string& str = pos->first;
|
||||
if (str.size() == 0)
|
||||
return false; // disallow empty parameter names
|
||||
for (unsigned int i = 0; i < str.size(); ++i) {
|
||||
int c = str[i];
|
||||
if (c < 32 || c == '"' || c > 127) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
89
externals/breakpad/src/common/linux/http_upload.h
vendored
Normal file
89
externals/breakpad/src/common/linux/http_upload.h
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
// Copyright 2006 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// HTTPUpload provides a "nice" API to send a multipart HTTP(S) POST
|
||||
// request using libcurl. It currently supports requests that contain
|
||||
// a set of string parameters (key/value pairs), and a file to upload.
|
||||
|
||||
#ifndef COMMON_LINUX_HTTP_UPLOAD_H__
|
||||
#define COMMON_LINUX_HTTP_UPLOAD_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
using std::map;
|
||||
|
||||
class HTTPUpload {
|
||||
public:
|
||||
// Sends the given sets of parameters and files as a multipart POST
|
||||
// request to the given URL.
|
||||
// Each key in |files| is the name of the file part of the request
|
||||
// (i.e. it corresponds to the name= attribute on an <input type="file">.
|
||||
// Parameter names must contain only printable ASCII characters,
|
||||
// and may not contain a quote (") character.
|
||||
// Only HTTP(S) URLs are currently supported. Returns true on success.
|
||||
// If the request is successful and response_body is non-NULL,
|
||||
// the response body will be returned in response_body.
|
||||
// If response_code is non-NULL, it will be set to the HTTP response code
|
||||
// received (or 0 if the request failed before getting an HTTP response).
|
||||
// If the send fails, a description of the error will be
|
||||
// returned in error_description.
|
||||
static bool SendRequest(const string& url,
|
||||
const map<string, string>& parameters,
|
||||
const map<string, string>& files,
|
||||
const string& proxy,
|
||||
const string& proxy_user_pwd,
|
||||
const string& ca_certificate_file,
|
||||
string* response_body,
|
||||
long* response_code,
|
||||
string* error_description);
|
||||
|
||||
private:
|
||||
// Checks that the given list of parameters has only printable
|
||||
// ASCII characters in the parameter name, and does not contain
|
||||
// any quote (") characters. Returns true if so.
|
||||
static bool CheckParameters(const map<string, string>& parameters);
|
||||
|
||||
// Checks the curl_lib parameter points to a valid curl lib.
|
||||
static bool CheckCurlLib(void* curl_lib);
|
||||
|
||||
// No instances of this class should be created.
|
||||
// Disallow all constructors, destructors, and operator=.
|
||||
HTTPUpload();
|
||||
explicit HTTPUpload(const HTTPUpload&);
|
||||
void operator=(const HTTPUpload&);
|
||||
~HTTPUpload();
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_HTTP_UPLOAD_H__
|
||||
39
externals/breakpad/src/common/linux/ignore_ret.h
vendored
Normal file
39
externals/breakpad/src/common/linux/ignore_ret.h
vendored
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC 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_
|
||||
344
externals/breakpad/src/common/linux/libcurl_wrapper.cc
vendored
Normal file
344
externals/breakpad/src/common/linux/libcurl_wrapper.cc
vendored
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
// Copyright 2009 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "common/linux/libcurl_wrapper.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
LibcurlWrapper::LibcurlWrapper()
|
||||
: init_ok_(false),
|
||||
curl_lib_(nullptr),
|
||||
last_curl_error_(""),
|
||||
curl_(nullptr),
|
||||
formpost_(nullptr),
|
||||
lastptr_(nullptr),
|
||||
headerlist_(nullptr) {}
|
||||
|
||||
LibcurlWrapper::~LibcurlWrapper() {
|
||||
if (init_ok_) {
|
||||
(*easy_cleanup_)(curl_);
|
||||
(*global_cleanup_)();
|
||||
dlclose(curl_lib_);
|
||||
}
|
||||
}
|
||||
|
||||
bool LibcurlWrapper::SetProxy(const string& proxy_host,
|
||||
const string& proxy_userpwd) {
|
||||
if (!CheckInit()) return false;
|
||||
|
||||
// Set proxy information if necessary.
|
||||
if (!proxy_host.empty()) {
|
||||
(*easy_setopt_)(curl_, CURLOPT_PROXY, proxy_host.c_str());
|
||||
} else {
|
||||
std::cout << "SetProxy called with empty proxy host.";
|
||||
return false;
|
||||
}
|
||||
if (!proxy_userpwd.empty()) {
|
||||
(*easy_setopt_)(curl_, CURLOPT_PROXYUSERPWD, proxy_userpwd.c_str());
|
||||
} else {
|
||||
std::cout << "SetProxy called with empty proxy username/password.";
|
||||
return false;
|
||||
}
|
||||
std::cout << "Set proxy host to " << proxy_host;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibcurlWrapper::AddFile(const string& upload_file_path,
|
||||
const string& basename) {
|
||||
if (!CheckInit()) return false;
|
||||
|
||||
std::cout << "Adding " << upload_file_path << " to form upload.";
|
||||
// Add form file.
|
||||
(*formadd_)(&formpost_, &lastptr_,
|
||||
CURLFORM_COPYNAME, basename.c_str(),
|
||||
CURLFORM_FILE, upload_file_path.c_str(),
|
||||
CURLFORM_END);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Callback to get the response data from server.
|
||||
static size_t WriteCallback(void* ptr, size_t size,
|
||||
size_t nmemb, void* userp) {
|
||||
if (!userp)
|
||||
return 0;
|
||||
|
||||
string* response = reinterpret_cast<string*>(userp);
|
||||
size_t real_size = size * nmemb;
|
||||
response->append(reinterpret_cast<char*>(ptr), real_size);
|
||||
return real_size;
|
||||
}
|
||||
|
||||
bool LibcurlWrapper::SendRequest(const string& url,
|
||||
const std::map<string, string>& parameters,
|
||||
long* http_status_code,
|
||||
string* http_header_data,
|
||||
string* http_response_data) {
|
||||
if (!CheckInit()) return false;
|
||||
|
||||
std::map<string, string>::const_iterator iter = parameters.begin();
|
||||
for (; iter != parameters.end(); ++iter)
|
||||
(*formadd_)(&formpost_, &lastptr_,
|
||||
CURLFORM_COPYNAME, iter->first.c_str(),
|
||||
CURLFORM_COPYCONTENTS, iter->second.c_str(),
|
||||
CURLFORM_END);
|
||||
|
||||
(*easy_setopt_)(curl_, CURLOPT_HTTPPOST, formpost_);
|
||||
|
||||
return SendRequestInner(url, http_status_code, http_header_data,
|
||||
http_response_data);
|
||||
}
|
||||
|
||||
bool LibcurlWrapper::SendGetRequest(const string& url,
|
||||
long* http_status_code,
|
||||
string* http_header_data,
|
||||
string* http_response_data) {
|
||||
if (!CheckInit()) return false;
|
||||
|
||||
(*easy_setopt_)(curl_, CURLOPT_HTTPGET, 1L);
|
||||
|
||||
return SendRequestInner(url, http_status_code, http_header_data,
|
||||
http_response_data);
|
||||
}
|
||||
|
||||
bool LibcurlWrapper::SendPutRequest(const string& url,
|
||||
const string& path,
|
||||
long* http_status_code,
|
||||
string* http_header_data,
|
||||
string* http_response_data) {
|
||||
if (!CheckInit()) return false;
|
||||
|
||||
FILE* file = fopen(path.c_str(), "rb");
|
||||
(*easy_setopt_)(curl_, CURLOPT_UPLOAD, 1L);
|
||||
(*easy_setopt_)(curl_, CURLOPT_PUT, 1L);
|
||||
(*easy_setopt_)(curl_, CURLOPT_READDATA, file);
|
||||
|
||||
bool success = SendRequestInner(url, http_status_code, http_header_data,
|
||||
http_response_data);
|
||||
|
||||
fclose(file);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool LibcurlWrapper::SendSimplePostRequest(const string& url,
|
||||
const string& body,
|
||||
const string& content_type,
|
||||
long* http_status_code,
|
||||
string* http_header_data,
|
||||
string* http_response_data) {
|
||||
if (!CheckInit()) return false;
|
||||
|
||||
(*easy_setopt_)(curl_, CURLOPT_POSTFIELDSIZE, body.size());
|
||||
(*easy_setopt_)(curl_, CURLOPT_COPYPOSTFIELDS, body.c_str());
|
||||
|
||||
if (!content_type.empty()) {
|
||||
string content_type_header = "Content-Type: " + content_type;
|
||||
headerlist_ = (*slist_append_)(
|
||||
headerlist_,
|
||||
content_type_header.c_str());
|
||||
}
|
||||
|
||||
return SendRequestInner(url, http_status_code, http_header_data,
|
||||
http_response_data);
|
||||
}
|
||||
|
||||
bool LibcurlWrapper::Init() {
|
||||
// First check to see if libcurl was statically linked:
|
||||
curl_lib_ = dlopen(nullptr, RTLD_NOW);
|
||||
if (curl_lib_ &&
|
||||
(!dlsym(curl_lib_, "curl_easy_init") ||
|
||||
!dlsym(curl_lib_, "curl_easy_setopt"))) {
|
||||
// Not statically linked, try again below.
|
||||
dlerror(); // Clear dlerror before attempting to open libraries.
|
||||
dlclose(curl_lib_);
|
||||
curl_lib_ = nullptr;
|
||||
}
|
||||
if (!curl_lib_) {
|
||||
curl_lib_ = dlopen("libcurl.so", RTLD_NOW);
|
||||
}
|
||||
if (!curl_lib_) {
|
||||
curl_lib_ = dlopen("libcurl.so.4", RTLD_NOW);
|
||||
}
|
||||
if (!curl_lib_) {
|
||||
curl_lib_ = dlopen("libcurl.so.3", RTLD_NOW);
|
||||
}
|
||||
if (!curl_lib_) {
|
||||
std::cout << "Could not find libcurl via dlopen";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!SetFunctionPointers()) {
|
||||
std::cout << "Could not find function pointers";
|
||||
return false;
|
||||
}
|
||||
|
||||
curl_ = (*easy_init_)();
|
||||
|
||||
last_curl_error_ = "No Error";
|
||||
|
||||
if (!curl_) {
|
||||
dlclose(curl_lib_);
|
||||
std::cout << "Curl initialization failed";
|
||||
return false;
|
||||
}
|
||||
|
||||
init_ok_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
#define SET_AND_CHECK_FUNCTION_POINTER(var, function_name, type) \
|
||||
var = reinterpret_cast<type>(dlsym(curl_lib_, function_name)); \
|
||||
if (!var) { \
|
||||
std::cout << "Could not find libcurl function " << function_name; \
|
||||
init_ok_ = false; \
|
||||
return false; \
|
||||
}
|
||||
|
||||
bool LibcurlWrapper::SetFunctionPointers() {
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(easy_init_,
|
||||
"curl_easy_init",
|
||||
CURL*(*)());
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(easy_setopt_,
|
||||
"curl_easy_setopt",
|
||||
CURLcode(*)(CURL*, CURLoption, ...));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(formadd_, "curl_formadd",
|
||||
CURLFORMcode(*)(curl_httppost**, curl_httppost**, ...));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(slist_append_, "curl_slist_append",
|
||||
curl_slist*(*)(curl_slist*, const char*));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(easy_perform_,
|
||||
"curl_easy_perform",
|
||||
CURLcode(*)(CURL*));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(easy_cleanup_,
|
||||
"curl_easy_cleanup",
|
||||
void(*)(CURL*));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(easy_getinfo_,
|
||||
"curl_easy_getinfo",
|
||||
CURLcode(*)(CURL*, CURLINFO info, ...));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(easy_reset_,
|
||||
"curl_easy_reset",
|
||||
void(*)(CURL*));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(slist_free_all_,
|
||||
"curl_slist_free_all",
|
||||
void(*)(curl_slist*));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(formfree_,
|
||||
"curl_formfree",
|
||||
void(*)(curl_httppost*));
|
||||
|
||||
SET_AND_CHECK_FUNCTION_POINTER(global_cleanup_,
|
||||
"curl_global_cleanup",
|
||||
void(*)(void));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LibcurlWrapper::SendRequestInner(const string& url,
|
||||
long* http_status_code,
|
||||
string* http_header_data,
|
||||
string* http_response_data) {
|
||||
string url_copy(url);
|
||||
(*easy_setopt_)(curl_, CURLOPT_URL, url_copy.c_str());
|
||||
|
||||
// Disable 100-continue header.
|
||||
char buf[] = "Expect:";
|
||||
headerlist_ = (*slist_append_)(headerlist_, buf);
|
||||
(*easy_setopt_)(curl_, CURLOPT_HTTPHEADER, headerlist_);
|
||||
|
||||
if (http_response_data != nullptr) {
|
||||
http_response_data->clear();
|
||||
(*easy_setopt_)(curl_, CURLOPT_WRITEFUNCTION, WriteCallback);
|
||||
(*easy_setopt_)(curl_, CURLOPT_WRITEDATA,
|
||||
reinterpret_cast<void*>(http_response_data));
|
||||
}
|
||||
if (http_header_data != nullptr) {
|
||||
http_header_data->clear();
|
||||
(*easy_setopt_)(curl_, CURLOPT_HEADERFUNCTION, WriteCallback);
|
||||
(*easy_setopt_)(curl_, CURLOPT_HEADERDATA,
|
||||
reinterpret_cast<void*>(http_header_data));
|
||||
}
|
||||
CURLcode err_code = CURLE_OK;
|
||||
err_code = (*easy_perform_)(curl_);
|
||||
easy_strerror_ = reinterpret_cast<const char* (*)(CURLcode)>
|
||||
(dlsym(curl_lib_, "curl_easy_strerror"));
|
||||
|
||||
if (http_status_code != nullptr) {
|
||||
(*easy_getinfo_)(curl_, CURLINFO_RESPONSE_CODE, http_status_code);
|
||||
}
|
||||
|
||||
if (err_code != CURLE_OK)
|
||||
fprintf(stderr, "Failed to send http request to %s, error: %s\n",
|
||||
url.c_str(),
|
||||
(*easy_strerror_)(err_code));
|
||||
|
||||
Reset();
|
||||
|
||||
return err_code == CURLE_OK;
|
||||
}
|
||||
|
||||
void LibcurlWrapper::Reset() {
|
||||
if (headerlist_ != nullptr) {
|
||||
(*slist_free_all_)(headerlist_);
|
||||
headerlist_ = nullptr;
|
||||
}
|
||||
|
||||
if (formpost_ != nullptr) {
|
||||
(*formfree_)(formpost_);
|
||||
formpost_ = nullptr;
|
||||
}
|
||||
|
||||
(*easy_reset_)(curl_);
|
||||
}
|
||||
|
||||
bool LibcurlWrapper::CheckInit() {
|
||||
if (!init_ok_) {
|
||||
std::cout << "LibcurlWrapper: You must call Init(), and have it return "
|
||||
"'true' before invoking any other methods.\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
122
externals/breakpad/src/common/linux/libcurl_wrapper.h
vendored
Normal file
122
externals/breakpad/src/common/linux/libcurl_wrapper.h
vendored
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
// Copyright 2009 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// A wrapper for libcurl to do HTTP Uploads, to support easy mocking
|
||||
// and unit testing of the HTTPUpload class.
|
||||
|
||||
#ifndef COMMON_LINUX_LIBCURL_WRAPPER_H_
|
||||
#define COMMON_LINUX_LIBCURL_WRAPPER_H_
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
#include "third_party/curl/curl.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// This class is only safe to be used on single-threaded code because of its
|
||||
// usage of libcurl's curl_global_cleanup().
|
||||
class LibcurlWrapper {
|
||||
public:
|
||||
LibcurlWrapper();
|
||||
virtual ~LibcurlWrapper();
|
||||
virtual bool Init();
|
||||
virtual bool SetProxy(const string& proxy_host,
|
||||
const string& proxy_userpwd);
|
||||
virtual bool AddFile(const string& upload_file_path,
|
||||
const string& basename);
|
||||
virtual bool SendRequest(const string& url,
|
||||
const std::map<string, string>& parameters,
|
||||
long* http_status_code,
|
||||
string* http_header_data,
|
||||
string* http_response_data);
|
||||
bool SendGetRequest(const string& url,
|
||||
long* http_status_code,
|
||||
string* http_header_data,
|
||||
string* http_response_data);
|
||||
bool SendPutRequest(const string& url,
|
||||
const string& path,
|
||||
long* http_status_code,
|
||||
string* http_header_data,
|
||||
string* http_response_data);
|
||||
bool SendSimplePostRequest(const string& url,
|
||||
const string& body,
|
||||
const string& content_type,
|
||||
long* http_status_code,
|
||||
string* http_header_data,
|
||||
string* http_response_data);
|
||||
|
||||
private:
|
||||
// This function initializes class state corresponding to function
|
||||
// pointers into the CURL library.
|
||||
bool SetFunctionPointers();
|
||||
|
||||
bool SendRequestInner(const string& url,
|
||||
long* http_status_code,
|
||||
string* http_header_data,
|
||||
string* http_response_data);
|
||||
|
||||
void Reset();
|
||||
|
||||
bool CheckInit();
|
||||
|
||||
bool init_ok_; // Whether init succeeded
|
||||
void* curl_lib_; // Pointer to result of dlopen() on
|
||||
// curl library
|
||||
string last_curl_error_; // The text of the last error when
|
||||
// dealing
|
||||
// with CURL.
|
||||
|
||||
CURL* curl_; // Pointer for handle for CURL calls.
|
||||
|
||||
CURL* (*easy_init_)(void);
|
||||
|
||||
// Stateful pointers for calling into curl_formadd()
|
||||
struct curl_httppost* formpost_;
|
||||
struct curl_httppost* lastptr_;
|
||||
struct curl_slist* headerlist_;
|
||||
|
||||
// Function pointers into CURL library
|
||||
CURLcode (*easy_setopt_)(CURL*, CURLoption, ...);
|
||||
CURLFORMcode (*formadd_)(struct curl_httppost**,
|
||||
struct curl_httppost**, ...);
|
||||
struct curl_slist* (*slist_append_)(struct curl_slist*, const char*);
|
||||
void (*slist_free_all_)(struct curl_slist*);
|
||||
CURLcode (*easy_perform_)(CURL*);
|
||||
const char* (*easy_strerror_)(CURLcode);
|
||||
void (*easy_cleanup_)(CURL*);
|
||||
CURLcode (*easy_getinfo_)(CURL*, CURLINFO info, ...);
|
||||
void (*easy_reset_)(CURL*);
|
||||
void (*formfree_)(struct curl_httppost*);
|
||||
void (*global_cleanup_)(void);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif // COMMON_LINUX_LIBCURL_WRAPPER_H_
|
||||
240
externals/breakpad/src/common/linux/linux_libc_support.cc
vendored
Normal file
240
externals/breakpad/src/common/linux/linux_libc_support.cc
vendored
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
// Copyright 2012 Google LLC
|
||||
//
|
||||
// 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 LLC 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.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#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"
|
||||
95
externals/breakpad/src/common/linux/linux_libc_support.h
vendored
Normal file
95
externals/breakpad/src/common/linux/linux_libc_support.h
vendored
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2009 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// This header provides replacements for libc functions that we need. We if
|
||||
// call the libc functions directly we risk crashing in the dynamic linker as
|
||||
// it tries to resolve uncached PLT entries.
|
||||
|
||||
#ifndef CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_
|
||||
#define CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern size_t my_strlen(const char* s);
|
||||
|
||||
extern int my_strcmp(const char* a, const char* b);
|
||||
|
||||
extern int my_strncmp(const char* a, const char* b, size_t len);
|
||||
|
||||
// Parse a non-negative integer.
|
||||
// result: (output) the resulting non-negative integer
|
||||
// s: a NUL terminated string
|
||||
// Return true iff successful.
|
||||
extern bool my_strtoui(int* result, const char* s);
|
||||
|
||||
// Return the length of the given unsigned integer when expressed in base 10.
|
||||
extern unsigned my_uint_len(uintmax_t i);
|
||||
|
||||
// Convert an unsigned integer to a string
|
||||
// output: (output) the resulting string is written here. This buffer must be
|
||||
// large enough to hold the resulting string. Call |my_uint_len| to get the
|
||||
// required length.
|
||||
// i: the unsigned integer to serialise.
|
||||
// i_len: the length of the integer in base 10 (see |my_uint_len|).
|
||||
extern void my_uitos(char* output, uintmax_t i, unsigned i_len);
|
||||
|
||||
extern const char* my_strchr(const char* haystack, char needle);
|
||||
|
||||
extern const char* my_strrchr(const char* haystack, char needle);
|
||||
|
||||
// Read a hex value
|
||||
// result: (output) the resulting value
|
||||
// s: a string
|
||||
// Returns a pointer to the first invalid charactor.
|
||||
extern const char* my_read_hex_ptr(uintptr_t* result, const char* s);
|
||||
|
||||
extern const char* my_read_decimal_ptr(uintptr_t* result, const char* s);
|
||||
|
||||
extern void my_memset(void* ip, char c, size_t len);
|
||||
|
||||
extern void* my_memchr(const void* src, int c, size_t len);
|
||||
|
||||
// The following are considered safe to use in a compromised environment.
|
||||
// Besides, this gives the compiler an opportunity to optimize their calls.
|
||||
#define my_memcpy memcpy
|
||||
#define my_memmove memmove
|
||||
#define my_memcmp memcmp
|
||||
|
||||
extern size_t my_strlcpy(char* s1, const char* s2, size_t len);
|
||||
|
||||
extern size_t my_strlcat(char* s1, const char* s2, size_t len);
|
||||
|
||||
extern int my_isspace(int ch);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // CLIENT_LINUX_LINUX_LIBC_SUPPORT_H_
|
||||
216
externals/breakpad/src/common/linux/linux_libc_support_unittest.cc
vendored
Normal file
216
externals/breakpad/src/common/linux/linux_libc_support_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
// Copyright 2009 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/linux_libc_support.h"
|
||||
|
||||
namespace {
|
||||
typedef testing::Test LinuxLibcSupportTest;
|
||||
}
|
||||
|
||||
TEST(LinuxLibcSupportTest, strlen) {
|
||||
static const char* test_data[] = { "", "a", "aa", "aaa", "aabc", NULL };
|
||||
for (unsigned i = 0; ; ++i) {
|
||||
if (!test_data[i])
|
||||
break;
|
||||
ASSERT_EQ(strlen(test_data[i]), my_strlen(test_data[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LinuxLibcSupportTest, strcmp) {
|
||||
static const char* test_data[] = {
|
||||
"", "",
|
||||
"a", "",
|
||||
"", "a",
|
||||
"a", "b",
|
||||
"a", "a",
|
||||
"ab", "aa",
|
||||
"abc", "ab",
|
||||
"abc", "abc",
|
||||
NULL,
|
||||
};
|
||||
|
||||
for (unsigned i = 0; ; ++i) {
|
||||
if (!test_data[i*2])
|
||||
break;
|
||||
int libc_result = strcmp(test_data[i*2], test_data[i*2 + 1]);
|
||||
if (libc_result > 1)
|
||||
libc_result = 1;
|
||||
else if (libc_result < -1)
|
||||
libc_result = -1;
|
||||
ASSERT_EQ(my_strcmp(test_data[i*2], test_data[i*2 + 1]), libc_result);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(LinuxLibcSupportTest, strtoui) {
|
||||
int result;
|
||||
|
||||
ASSERT_FALSE(my_strtoui(&result, ""));
|
||||
ASSERT_FALSE(my_strtoui(&result, "-1"));
|
||||
ASSERT_FALSE(my_strtoui(&result, "-"));
|
||||
ASSERT_FALSE(my_strtoui(&result, "a"));
|
||||
ASSERT_FALSE(my_strtoui(&result, "23472893472938472987987398472398"));
|
||||
|
||||
ASSERT_TRUE(my_strtoui(&result, "0"));
|
||||
ASSERT_EQ(result, 0);
|
||||
ASSERT_TRUE(my_strtoui(&result, "1"));
|
||||
ASSERT_EQ(result, 1);
|
||||
ASSERT_TRUE(my_strtoui(&result, "12"));
|
||||
ASSERT_EQ(result, 12);
|
||||
ASSERT_TRUE(my_strtoui(&result, "123"));
|
||||
ASSERT_EQ(result, 123);
|
||||
ASSERT_TRUE(my_strtoui(&result, "0123"));
|
||||
ASSERT_EQ(result, 123);
|
||||
}
|
||||
|
||||
TEST(LinuxLibcSupportTest, uint_len) {
|
||||
ASSERT_EQ(my_uint_len(0), 1U);
|
||||
ASSERT_EQ(my_uint_len(2), 1U);
|
||||
ASSERT_EQ(my_uint_len(5), 1U);
|
||||
ASSERT_EQ(my_uint_len(9), 1U);
|
||||
ASSERT_EQ(my_uint_len(10), 2U);
|
||||
ASSERT_EQ(my_uint_len(99), 2U);
|
||||
ASSERT_EQ(my_uint_len(100), 3U);
|
||||
ASSERT_EQ(my_uint_len(101), 3U);
|
||||
ASSERT_EQ(my_uint_len(1000), 4U);
|
||||
// 0xFFFFFFFFFFFFFFFF
|
||||
ASSERT_EQ(my_uint_len(18446744073709551615LLU), 20U);
|
||||
}
|
||||
|
||||
TEST(LinuxLibcSupportTest, uitos) {
|
||||
char buf[32];
|
||||
|
||||
my_uitos(buf, 0, 1);
|
||||
ASSERT_EQ(0, memcmp(buf, "0", 1));
|
||||
|
||||
my_uitos(buf, 1, 1);
|
||||
ASSERT_EQ(0, memcmp(buf, "1", 1));
|
||||
|
||||
my_uitos(buf, 10, 2);
|
||||
ASSERT_EQ(0, memcmp(buf, "10", 2));
|
||||
|
||||
my_uitos(buf, 63, 2);
|
||||
ASSERT_EQ(0, memcmp(buf, "63", 2));
|
||||
|
||||
my_uitos(buf, 101, 3);
|
||||
ASSERT_EQ(0, memcmp(buf, "101", 2));
|
||||
|
||||
// 0xFFFFFFFFFFFFFFFF
|
||||
my_uitos(buf, 18446744073709551615LLU, 20);
|
||||
ASSERT_EQ(0, memcmp(buf, "18446744073709551615", 20));
|
||||
}
|
||||
|
||||
TEST(LinuxLibcSupportTest, strchr) {
|
||||
ASSERT_EQ(NULL, my_strchr("abc", 'd'));
|
||||
ASSERT_EQ(NULL, my_strchr("", 'd'));
|
||||
ASSERT_EQ(NULL, my_strchr("efghi", 'd'));
|
||||
|
||||
ASSERT_TRUE(my_strchr("a", 'a'));
|
||||
ASSERT_TRUE(my_strchr("abc", 'a'));
|
||||
ASSERT_TRUE(my_strchr("bcda", 'a'));
|
||||
ASSERT_TRUE(my_strchr("sdfasdf", 'a'));
|
||||
|
||||
static const char abc3[] = "abcabcabc";
|
||||
ASSERT_EQ(abc3, my_strchr(abc3, 'a'));
|
||||
}
|
||||
|
||||
TEST(LinuxLibcSupportTest, strrchr) {
|
||||
ASSERT_EQ(NULL, my_strrchr("abc", 'd'));
|
||||
ASSERT_EQ(NULL, my_strrchr("", 'd'));
|
||||
ASSERT_EQ(NULL, my_strrchr("efghi", 'd'));
|
||||
|
||||
ASSERT_TRUE(my_strrchr("a", 'a'));
|
||||
ASSERT_TRUE(my_strrchr("abc", 'a'));
|
||||
ASSERT_TRUE(my_strrchr("bcda", 'a'));
|
||||
ASSERT_TRUE(my_strrchr("sdfasdf", 'a'));
|
||||
|
||||
static const char abc3[] = "abcabcabc";
|
||||
ASSERT_EQ(abc3 + 6, my_strrchr(abc3, 'a'));
|
||||
}
|
||||
|
||||
TEST(LinuxLibcSupportTest, memchr) {
|
||||
ASSERT_EQ(NULL, my_memchr("abc", 'd', 3));
|
||||
ASSERT_EQ(NULL, my_memchr("abcd", 'd', 3));
|
||||
ASSERT_EQ(NULL, my_memchr("a", 'a', 0));
|
||||
|
||||
static const char abc3[] = "abcabcabc";
|
||||
ASSERT_EQ(abc3, my_memchr(abc3, 'a', 3));
|
||||
ASSERT_EQ(abc3, my_memchr(abc3, 'a', 9));
|
||||
ASSERT_EQ(abc3+1, my_memchr(abc3, 'b', 9));
|
||||
ASSERT_EQ(abc3+2, my_memchr(abc3, 'c', 9));
|
||||
}
|
||||
|
||||
TEST(LinuxLibcSupportTest, read_hex_ptr) {
|
||||
uintptr_t result;
|
||||
const char* last;
|
||||
|
||||
last = my_read_hex_ptr(&result, "");
|
||||
ASSERT_EQ(result, 0U);
|
||||
ASSERT_EQ(*last, 0);
|
||||
|
||||
last = my_read_hex_ptr(&result, "0");
|
||||
ASSERT_EQ(result, 0U);
|
||||
ASSERT_EQ(*last, 0);
|
||||
|
||||
last = my_read_hex_ptr(&result, "0123");
|
||||
ASSERT_EQ(result, 0x123U);
|
||||
ASSERT_EQ(*last, 0);
|
||||
|
||||
last = my_read_hex_ptr(&result, "0123a");
|
||||
ASSERT_EQ(result, 0x123aU);
|
||||
ASSERT_EQ(*last, 0);
|
||||
|
||||
last = my_read_hex_ptr(&result, "0123a-");
|
||||
ASSERT_EQ(result, 0x123aU);
|
||||
ASSERT_EQ(*last, '-');
|
||||
}
|
||||
|
||||
TEST(LinuxLibcSupportTest, read_decimal_ptr) {
|
||||
uintptr_t result;
|
||||
const char* last;
|
||||
|
||||
last = my_read_decimal_ptr(&result, "0");
|
||||
ASSERT_EQ(result, 0U);
|
||||
ASSERT_EQ(*last, 0);
|
||||
|
||||
last = my_read_decimal_ptr(&result, "0123");
|
||||
ASSERT_EQ(result, 123U);
|
||||
ASSERT_EQ(*last, 0);
|
||||
|
||||
last = my_read_decimal_ptr(&result, "1234");
|
||||
ASSERT_EQ(result, 1234U);
|
||||
ASSERT_EQ(*last, 0);
|
||||
|
||||
last = my_read_decimal_ptr(&result, "01234-");
|
||||
ASSERT_EQ(result, 1234U);
|
||||
ASSERT_EQ(*last, '-');
|
||||
}
|
||||
115
externals/breakpad/src/common/linux/memory_mapped_file.cc
vendored
Normal file
115
externals/breakpad/src/common/linux/memory_mapped_file.cc
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// memory_mapped_file.cc: Implement google_breakpad::MemoryMappedFile.
|
||||
// See memory_mapped_file.h for details.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/memory_mapped_file.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#if defined(__ANDROID__)
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/memory_range.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
MemoryMappedFile::MemoryMappedFile() {}
|
||||
|
||||
MemoryMappedFile::MemoryMappedFile(const char* path, size_t offset) {
|
||||
Map(path, offset);
|
||||
}
|
||||
|
||||
MemoryMappedFile::~MemoryMappedFile() {
|
||||
Unmap();
|
||||
}
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
bool MemoryMappedFile::Map(const char* path, size_t offset) {
|
||||
Unmap();
|
||||
// Based on https://pubs.opengroup.org/onlinepubs/7908799/xsh/open.html
|
||||
// If O_NONBLOCK is set: The open() function will return without blocking
|
||||
// for the device to be ready or available. Setting this value will provent
|
||||
// hanging if file is not avilable.
|
||||
int fd = sys_open(path, O_RDONLY | O_NONBLOCK, 0);
|
||||
if (fd == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(__aarch64__) || \
|
||||
(defined(__mips__) && _MIPS_SIM == _ABI64) || \
|
||||
(defined(__riscv) && __riscv_xlen == 64)
|
||||
|
||||
struct kernel_stat st;
|
||||
if (sys_fstat(fd, &st) == -1 || st.st_size < 0) {
|
||||
#else
|
||||
struct kernel_stat64 st;
|
||||
if (sys_fstat64(fd, &st) == -1 || st.st_size < 0) {
|
||||
#endif
|
||||
sys_close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Strangely file size can be negative, but we check above that it is not.
|
||||
size_t file_len = static_cast<size_t>(st.st_size);
|
||||
// If the file does not extend beyond the offset, simply use an empty
|
||||
// MemoryRange and return true. Don't bother to call mmap()
|
||||
// even though mmap() can handle an empty file on some platforms.
|
||||
if (offset >= file_len) {
|
||||
sys_close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t content_len = file_len - offset;
|
||||
void* data = sys_mmap(NULL, content_len, PROT_READ, MAP_PRIVATE, fd, offset);
|
||||
sys_close(fd);
|
||||
if (data == MAP_FAILED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
content_.Set(data, content_len);
|
||||
return true;
|
||||
}
|
||||
|
||||
void MemoryMappedFile::Unmap() {
|
||||
if (content_.data()) {
|
||||
sys_munmap(const_cast<uint8_t*>(content_.data()), content_.length());
|
||||
content_.Set(NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
87
externals/breakpad/src/common/linux/memory_mapped_file.h
vendored
Normal file
87
externals/breakpad/src/common/linux/memory_mapped_file.h
vendored
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// memory_mapped_file.h: Define the google_breakpad::MemoryMappedFile
|
||||
// class, which maps a file into memory for read-only access.
|
||||
|
||||
#ifndef COMMON_LINUX_MEMORY_MAPPED_FILE_H_
|
||||
#define COMMON_LINUX_MEMORY_MAPPED_FILE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "common/memory_range.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// A utility class for mapping a file into memory for read-only access of
|
||||
// the file content. Its implementation avoids calling into libc functions
|
||||
// by directly making system calls for open, close, mmap, and munmap.
|
||||
class MemoryMappedFile {
|
||||
public:
|
||||
MemoryMappedFile();
|
||||
|
||||
// Constructor that calls Map() to map a file at |path| into memory.
|
||||
// If Map() fails, the object behaves as if it is default constructed.
|
||||
MemoryMappedFile(const char* path, size_t offset);
|
||||
|
||||
MemoryMappedFile(const MemoryMappedFile&) = delete;
|
||||
void operator=(const MemoryMappedFile&) = delete;
|
||||
|
||||
~MemoryMappedFile();
|
||||
|
||||
// Maps a file at |path| into memory, which can then be accessed via
|
||||
// content() as a MemoryRange object or via data(), and returns true on
|
||||
// success. Mapping an empty file will succeed but with data() and size()
|
||||
// returning NULL and 0, respectively. An existing mapping is unmapped
|
||||
// before a new mapping is created.
|
||||
bool Map(const char* path, size_t offset);
|
||||
|
||||
// Unmaps the memory for the mapped file. It's a no-op if no file is
|
||||
// mapped.
|
||||
void Unmap();
|
||||
|
||||
// Returns a MemoryRange object that covers the memory for the mapped
|
||||
// file. The MemoryRange object is empty if no file is mapped.
|
||||
const MemoryRange& content() const { return content_; }
|
||||
|
||||
// Returns a pointer to the beginning of the memory for the mapped file.
|
||||
// or NULL if no file is mapped or the mapped file is empty.
|
||||
const void* data() const { return content_.data(); }
|
||||
|
||||
// Returns the size in bytes of the mapped file, or zero if no file
|
||||
// is mapped.
|
||||
size_t size() const { return content_.length(); }
|
||||
|
||||
private:
|
||||
// Mapped file content as a MemoryRange object.
|
||||
MemoryRange content_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_MEMORY_MAPPED_FILE_H_
|
||||
211
externals/breakpad/src/common/linux/memory_mapped_file_unittest.cc
vendored
Normal file
211
externals/breakpad/src/common/linux/memory_mapped_file_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// memory_mapped_file_unittest.cc:
|
||||
// Unit tests for google_breakpad::MemoryMappedFile.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/memory_mapped_file.h"
|
||||
#include "common/tests/auto_tempdir.h"
|
||||
#include "common/tests/file_utils.h"
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
using google_breakpad::AutoTempDir;
|
||||
using google_breakpad::MemoryMappedFile;
|
||||
using google_breakpad::WriteFile;
|
||||
|
||||
namespace {
|
||||
|
||||
class MemoryMappedFileTest : public testing::Test {
|
||||
protected:
|
||||
void ExpectNoMappedData(const MemoryMappedFile& mapped_file) {
|
||||
EXPECT_TRUE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() == NULL);
|
||||
EXPECT_EQ(0U, mapped_file.size());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(MemoryMappedFileTest, DefaultConstructor) {
|
||||
MemoryMappedFile mapped_file;
|
||||
ExpectNoMappedData(mapped_file);
|
||||
}
|
||||
|
||||
TEST_F(MemoryMappedFileTest, UnmapWithoutMap) {
|
||||
MemoryMappedFile mapped_file;
|
||||
mapped_file.Unmap();
|
||||
}
|
||||
|
||||
TEST_F(MemoryMappedFileTest, MapNonexistentFile) {
|
||||
{
|
||||
MemoryMappedFile mapped_file("nonexistent-file", 0);
|
||||
ExpectNoMappedData(mapped_file);
|
||||
}
|
||||
{
|
||||
MemoryMappedFile mapped_file;
|
||||
EXPECT_FALSE(mapped_file.Map("nonexistent-file", 0));
|
||||
ExpectNoMappedData(mapped_file);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MemoryMappedFileTest, MapEmptyFile) {
|
||||
AutoTempDir temp_dir;
|
||||
string test_file = temp_dir.path() + "/empty_file";
|
||||
ASSERT_TRUE(WriteFile(test_file.c_str(), NULL, 0));
|
||||
|
||||
{
|
||||
MemoryMappedFile mapped_file(test_file.c_str(), 0);
|
||||
ExpectNoMappedData(mapped_file);
|
||||
}
|
||||
{
|
||||
MemoryMappedFile mapped_file;
|
||||
EXPECT_TRUE(mapped_file.Map(test_file.c_str(), 0));
|
||||
ExpectNoMappedData(mapped_file);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MemoryMappedFileTest, MapNonEmptyFile) {
|
||||
char data[256];
|
||||
size_t data_size = sizeof(data);
|
||||
for (size_t i = 0; i < data_size; ++i) {
|
||||
data[i] = i;
|
||||
}
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string test_file = temp_dir.path() + "/test_file";
|
||||
ASSERT_TRUE(WriteFile(test_file.c_str(), data, data_size));
|
||||
|
||||
{
|
||||
MemoryMappedFile mapped_file(test_file.c_str(), 0);
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data_size, mapped_file.size());
|
||||
EXPECT_EQ(0, memcmp(data, mapped_file.data(), data_size));
|
||||
}
|
||||
{
|
||||
MemoryMappedFile mapped_file;
|
||||
EXPECT_TRUE(mapped_file.Map(test_file.c_str(), 0));
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data_size, mapped_file.size());
|
||||
EXPECT_EQ(0, memcmp(data, mapped_file.data(), data_size));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MemoryMappedFileTest, RemapAfterMap) {
|
||||
char data1[256];
|
||||
size_t data1_size = sizeof(data1);
|
||||
for (size_t i = 0; i < data1_size; ++i) {
|
||||
data1[i] = i;
|
||||
}
|
||||
|
||||
char data2[50];
|
||||
size_t data2_size = sizeof(data2);
|
||||
for (size_t i = 0; i < data2_size; ++i) {
|
||||
data2[i] = 255 - i;
|
||||
}
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string test_file1 = temp_dir.path() + "/test_file1";
|
||||
string test_file2 = temp_dir.path() + "/test_file2";
|
||||
ASSERT_TRUE(WriteFile(test_file1.c_str(), data1, data1_size));
|
||||
ASSERT_TRUE(WriteFile(test_file2.c_str(), data2, data2_size));
|
||||
|
||||
{
|
||||
MemoryMappedFile mapped_file(test_file1.c_str(), 0);
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data1_size, mapped_file.size());
|
||||
EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size));
|
||||
|
||||
mapped_file.Map(test_file2.c_str(), 0);
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data2_size, mapped_file.size());
|
||||
EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size));
|
||||
}
|
||||
{
|
||||
MemoryMappedFile mapped_file;
|
||||
EXPECT_TRUE(mapped_file.Map(test_file1.c_str(), 0));
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data1_size, mapped_file.size());
|
||||
EXPECT_EQ(0, memcmp(data1, mapped_file.data(), data1_size));
|
||||
|
||||
mapped_file.Map(test_file2.c_str(), 0);
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data2_size, mapped_file.size());
|
||||
EXPECT_EQ(0, memcmp(data2, mapped_file.data(), data2_size));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MemoryMappedFileTest, MapWithOffset) {
|
||||
// Put more data in the test file this time. Offsets can only be
|
||||
// done on page boundaries, so we need a two page file to test this.
|
||||
const int page_size = 4096;
|
||||
char data1[2 * page_size];
|
||||
size_t data1_size = sizeof(data1);
|
||||
for (size_t i = 0; i < data1_size; ++i) {
|
||||
data1[i] = i & 0x7f;
|
||||
}
|
||||
|
||||
AutoTempDir temp_dir;
|
||||
string test_file1 = temp_dir.path() + "/test_file1";
|
||||
ASSERT_TRUE(WriteFile(test_file1.c_str(), data1, data1_size));
|
||||
{
|
||||
MemoryMappedFile mapped_file(test_file1.c_str(), page_size);
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data1_size - page_size, mapped_file.size());
|
||||
EXPECT_EQ(
|
||||
0,
|
||||
memcmp(data1 + page_size, mapped_file.data(), data1_size - page_size));
|
||||
}
|
||||
{
|
||||
MemoryMappedFile mapped_file;
|
||||
mapped_file.Map(test_file1.c_str(), page_size);
|
||||
EXPECT_FALSE(mapped_file.content().IsEmpty());
|
||||
EXPECT_TRUE(mapped_file.data() != NULL);
|
||||
EXPECT_EQ(data1_size - page_size, mapped_file.size());
|
||||
EXPECT_EQ(
|
||||
0,
|
||||
memcmp(data1 + page_size, mapped_file.data(), data1_size - page_size));
|
||||
}
|
||||
}
|
||||
56
externals/breakpad/src/common/linux/safe_readlink.cc
vendored
Normal file
56
externals/breakpad/src/common/linux/safe_readlink.cc
vendored
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// safe_readlink.cc: Implement google_breakpad::SafeReadLink.
|
||||
// See safe_readlink.h for details.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
bool SafeReadLink(const char* path, char* buffer, size_t buffer_size) {
|
||||
// sys_readlink() does not add a NULL byte to |buffer|. In order to return
|
||||
// a NULL-terminated string in |buffer|, |buffer_size| should be at least
|
||||
// one byte longer than the expected path length. Also, sys_readlink()
|
||||
// returns the actual path length on success, which does not count the
|
||||
// NULL byte, so |result_size| should be less than |buffer_size|.
|
||||
ssize_t result_size = sys_readlink(path, buffer, buffer_size);
|
||||
if (result_size >= 0 && static_cast<size_t>(result_size) < buffer_size) {
|
||||
buffer[result_size] = '\0';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
64
externals/breakpad/src/common/linux/safe_readlink.h
vendored
Normal file
64
externals/breakpad/src/common/linux/safe_readlink.h
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// safe_readlink.h: Define the google_breakpad::SafeReadLink function,
|
||||
// which wraps sys_readlink and gurantees the result is NULL-terminated.
|
||||
|
||||
#ifndef COMMON_LINUX_SAFE_READLINK_H_
|
||||
#define COMMON_LINUX_SAFE_READLINK_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// This function wraps sys_readlink() and performs the same functionalty,
|
||||
// but guarantees |buffer| is NULL-terminated if sys_readlink() returns
|
||||
// no error. It takes the same arguments as sys_readlink(), but unlike
|
||||
// sys_readlink(), it returns true on success.
|
||||
//
|
||||
// |buffer_size| specifies the size of |buffer| in bytes. As this function
|
||||
// always NULL-terminates |buffer| on success, |buffer_size| should be
|
||||
// at least one byte longer than the expected path length (e.g. PATH_MAX,
|
||||
// which is typically defined as the maximum length of a path name
|
||||
// including the NULL byte).
|
||||
//
|
||||
// The implementation of this function calls sys_readlink() instead of
|
||||
// readlink(), it can thus be used in the context where calling to libc
|
||||
// functions is discouraged.
|
||||
bool SafeReadLink(const char* path, char* buffer, size_t buffer_size);
|
||||
|
||||
// Same as the three-argument version of SafeReadLink() but deduces the
|
||||
// size of |buffer| if it is a char array of known size.
|
||||
template <size_t N>
|
||||
bool SafeReadLink(const char* path, char (&buffer)[N]) {
|
||||
return SafeReadLink(path, buffer, sizeof(buffer));
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_SAFE_READLINK_H_
|
||||
92
externals/breakpad/src/common/linux/safe_readlink_unittest.cc
vendored
Normal file
92
externals/breakpad/src/common/linux/safe_readlink_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
// Copyright 2011 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// safe_readlink_unittest.cc: Unit tests for google_breakpad::SafeReadLink.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
#include "common/linux/safe_readlink.h"
|
||||
|
||||
using google_breakpad::SafeReadLink;
|
||||
|
||||
TEST(SafeReadLinkTest, ZeroBufferSize) {
|
||||
char buffer[1];
|
||||
EXPECT_FALSE(SafeReadLink("/proc/self/exe", buffer, 0));
|
||||
}
|
||||
|
||||
TEST(SafeReadLinkTest, BufferSizeTooSmall) {
|
||||
char buffer[1];
|
||||
EXPECT_FALSE(SafeReadLink("/proc/self/exe", buffer, 1));
|
||||
}
|
||||
|
||||
TEST(SafeReadLinkTest, BoundaryBufferSize) {
|
||||
char buffer[PATH_MAX];
|
||||
EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer, sizeof(buffer)));
|
||||
size_t path_length = strlen(buffer);
|
||||
EXPECT_LT(0U, path_length);
|
||||
EXPECT_GT(sizeof(buffer), path_length);
|
||||
|
||||
// Buffer size equals to the expected path length plus 1 for the NULL byte.
|
||||
char buffer2[PATH_MAX];
|
||||
EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer2, path_length + 1));
|
||||
EXPECT_EQ(path_length, strlen(buffer2));
|
||||
EXPECT_EQ(0, strncmp(buffer, buffer2, PATH_MAX));
|
||||
|
||||
// Buffer size equals to the expected path length.
|
||||
EXPECT_FALSE(SafeReadLink("/proc/self/exe", buffer, path_length));
|
||||
}
|
||||
|
||||
TEST(SafeReadLinkTest, NonexistentPath) {
|
||||
char buffer[PATH_MAX];
|
||||
EXPECT_FALSE(SafeReadLink("nonexistent_path", buffer, sizeof(buffer)));
|
||||
}
|
||||
|
||||
TEST(SafeReadLinkTest, NonSymbolicLinkPath) {
|
||||
char actual_path[PATH_MAX];
|
||||
EXPECT_TRUE(SafeReadLink("/proc/self/exe", actual_path, sizeof(actual_path)));
|
||||
|
||||
char buffer[PATH_MAX];
|
||||
EXPECT_FALSE(SafeReadLink(actual_path, buffer, sizeof(buffer)));
|
||||
}
|
||||
|
||||
TEST(SafeReadLinkTest, DeduceBufferSizeFromCharArray) {
|
||||
char buffer[PATH_MAX];
|
||||
char* buffer_pointer = buffer;
|
||||
EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer_pointer, sizeof(buffer)));
|
||||
size_t path_length = strlen(buffer);
|
||||
|
||||
// Use the template version of SafeReadLink to deduce the buffer size
|
||||
// from the char array.
|
||||
char buffer2[PATH_MAX];
|
||||
EXPECT_TRUE(SafeReadLink("/proc/self/exe", buffer2));
|
||||
EXPECT_EQ(path_length, strlen(buffer2));
|
||||
EXPECT_EQ(0, strncmp(buffer, buffer2, PATH_MAX));
|
||||
}
|
||||
132
externals/breakpad/src/common/linux/scoped_pipe.cc
vendored
Normal file
132
externals/breakpad/src/common/linux/scoped_pipe.cc
vendored
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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 LLC nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/scoped_pipe.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/linux/eintr_wrapper.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
ScopedPipe::ScopedPipe() {
|
||||
fds_[0] = -1;
|
||||
fds_[1] = -1;
|
||||
}
|
||||
|
||||
ScopedPipe::~ScopedPipe() {
|
||||
CloseReadFd();
|
||||
CloseWriteFd();
|
||||
}
|
||||
|
||||
bool ScopedPipe::Init() {
|
||||
return pipe(fds_) == 0;
|
||||
}
|
||||
|
||||
void ScopedPipe::CloseReadFd() {
|
||||
if (fds_[0] != -1) {
|
||||
close(fds_[0]);
|
||||
fds_[0] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void ScopedPipe::CloseWriteFd() {
|
||||
if (fds_[1] != -1) {
|
||||
close(fds_[1]);
|
||||
fds_[1] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool ScopedPipe::ReadLine(std::string& line) {
|
||||
// Simple buffered file read. `read_buffer_` stores previously read bytes, and
|
||||
// we either return a line from this buffer, or we append blocks of read bytes
|
||||
// to the buffer until we have a complete line.
|
||||
size_t eol_index = read_buffer_.find('\n');
|
||||
|
||||
// While we don't have a full line, and read pipe is valid.
|
||||
while (eol_index == std::string::npos && GetReadFd() != -1) {
|
||||
// Read a block of 128 bytes from the read pipe.
|
||||
char read_buf[128];
|
||||
ssize_t read_len = HANDLE_EINTR(
|
||||
read(GetReadFd(), read_buf, sizeof(read_buf)));
|
||||
if (read_len <= 0) {
|
||||
// Pipe error, or pipe has been closed.
|
||||
CloseReadFd();
|
||||
break;
|
||||
}
|
||||
|
||||
// Append the block, and check if we have a full line now.
|
||||
read_buffer_.append(read_buf, read_len);
|
||||
eol_index = read_buffer_.find('\n');
|
||||
}
|
||||
|
||||
if (eol_index != std::string::npos) {
|
||||
// We have a full line to output.
|
||||
line = read_buffer_.substr(0, eol_index);
|
||||
if (eol_index < read_buffer_.size()) {
|
||||
read_buffer_ = read_buffer_.substr(eol_index + 1);
|
||||
} else {
|
||||
read_buffer_ = "";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (read_buffer_.size()) {
|
||||
// We don't have a full line to output, but we can only reach here if the
|
||||
// pipe has closed and there are some bytes left at the end, so we should
|
||||
// return those bytes.
|
||||
line = std::move(read_buffer_);
|
||||
read_buffer_ = "";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// We don't have any buffered data left, and the pipe has closed.
|
||||
return false;
|
||||
}
|
||||
|
||||
int ScopedPipe::Dup2WriteFd(int new_fd) const {
|
||||
return dup2(fds_[1], new_fd);
|
||||
}
|
||||
|
||||
bool ScopedPipe::WriteForTesting(const void* bytes, size_t bytes_len) {
|
||||
ssize_t r = HANDLE_EINTR(write(GetWriteFd(), bytes, bytes_len));
|
||||
if (r != static_cast<ssize_t>(bytes_len)) {
|
||||
CloseWriteFd();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
115
externals/breakpad/src/common/linux/scoped_pipe.h
vendored
Normal file
115
externals/breakpad/src/common/linux/scoped_pipe.h
vendored
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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 LLC 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_SCOPED_PIPE_H_
|
||||
#define COMMON_LINUX_SCOPED_PIPE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Small RAII wrapper for a pipe pair.
|
||||
//
|
||||
// Example (both ends of pipe in same process):
|
||||
// ScopedPipe tmp;
|
||||
// std::string line;
|
||||
// if (tmp.Init() && tmp.Write(bytes, bytes_len)) {
|
||||
// tmp.CloseWriteFd();
|
||||
// while (tmp.ReadLine(&line)) {
|
||||
// std::cerr << line << std::endl;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Example (reading output from a child process):
|
||||
// ScopedPipe tmp;
|
||||
// if (fork()) {
|
||||
// // Parent process, read from the read end of the pipe.
|
||||
// std::string line;
|
||||
// while (tmp.ReadLine(line)) {
|
||||
// // Process output...
|
||||
// }
|
||||
// // Close read pipe once done processing the output that we wanted, this
|
||||
// // should ensure that the child process exits even if we didn't read all
|
||||
// // of the output.
|
||||
// tmp.CloseReadFd();
|
||||
// // Parent process should handle waiting for child to exit here...
|
||||
// } else {
|
||||
// // Child process, close the read fd and dup the write fd before exec'ing.
|
||||
// tmp.CloseReadFd();
|
||||
// tmp.Dup2WriteFd(STDOUT_FILENO);
|
||||
// tmp.Dup2WriteFd(STDERR_FILENO);
|
||||
// execl("some-command", "some-arguments");
|
||||
// }
|
||||
class ScopedPipe {
|
||||
public:
|
||||
ScopedPipe();
|
||||
~ScopedPipe();
|
||||
|
||||
// Creates the pipe pair - returns false on error.
|
||||
bool Init();
|
||||
|
||||
// Close the read pipe. This only needs to be used when the read pipe needs to
|
||||
// be closed earlier.
|
||||
void CloseReadFd();
|
||||
|
||||
// Close the write pipe. This only needs to be used when the write pipe needs
|
||||
// to be closed earlier.
|
||||
void CloseWriteFd();
|
||||
|
||||
// Reads characters until newline or end of pipe. On read failure this will
|
||||
// close the read pipe, but continue to return true and read buffered lines
|
||||
// until the internal buffering is exhausted. This will block if there is no
|
||||
// data available on the read pipe.
|
||||
bool ReadLine(std::string& line);
|
||||
|
||||
// Writes bytes to the write end of the pipe, returns false and closes write
|
||||
// pipe on failure.
|
||||
bool WriteForTesting(const void* bytes, size_t bytes_len);
|
||||
|
||||
// Calls the dup2 system call to replace any existing open file descriptor
|
||||
// with number new_fd with a copy of the current write end file descriptor
|
||||
// for the pipe.
|
||||
int Dup2WriteFd(int new_fd) const;
|
||||
|
||||
private:
|
||||
int GetReadFd() const {
|
||||
return fds_[0];
|
||||
}
|
||||
|
||||
int GetWriteFd() const {
|
||||
return fds_[1];
|
||||
}
|
||||
|
||||
int fds_[2];
|
||||
std::string read_buffer_;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_SCOPED_PIPE_H_
|
||||
75
externals/breakpad/src/common/linux/scoped_pipe_unittest.cc
vendored
Normal file
75
externals/breakpad/src/common/linux/scoped_pipe_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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 LLC 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.
|
||||
|
||||
// scoped_pipe_unittest.cc: Unit tests for google_breakpad::ScopedPipe.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/scoped_pipe.h"
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
TEST(ScopedPipeTest, WriteAndClose) {
|
||||
const char kTestData[] = "One\nTwo\nThree";
|
||||
ScopedPipe pipe;
|
||||
std::string line;
|
||||
|
||||
ASSERT_TRUE(pipe.Init());
|
||||
ASSERT_TRUE(pipe.WriteForTesting(kTestData, strlen(kTestData)));
|
||||
pipe.CloseWriteFd();
|
||||
|
||||
ASSERT_TRUE(pipe.ReadLine(line));
|
||||
ASSERT_EQ(line, "One");
|
||||
ASSERT_TRUE(pipe.ReadLine(line));
|
||||
ASSERT_EQ(line, "Two");
|
||||
ASSERT_TRUE(pipe.ReadLine(line));
|
||||
ASSERT_EQ(line, "Three");
|
||||
ASSERT_FALSE(pipe.ReadLine(line));
|
||||
}
|
||||
|
||||
TEST(ScopedPipeTest, MultipleWrites) {
|
||||
const char kTestDataOne[] = "One\n";
|
||||
const char kTestDataTwo[] = "Two\n";
|
||||
ScopedPipe pipe;
|
||||
std::string line;
|
||||
|
||||
ASSERT_TRUE(pipe.Init());
|
||||
ASSERT_TRUE(pipe.WriteForTesting(kTestDataOne, strlen(kTestDataOne)));
|
||||
ASSERT_TRUE(pipe.ReadLine(line));
|
||||
ASSERT_EQ(line, "One");
|
||||
|
||||
ASSERT_TRUE(pipe.WriteForTesting(kTestDataTwo, strlen(kTestDataTwo)));
|
||||
ASSERT_TRUE(pipe.ReadLine(line));
|
||||
ASSERT_EQ(line, "Two");
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
103
externals/breakpad/src/common/linux/scoped_tmpfile.cc
vendored
Normal file
103
externals/breakpad/src/common/linux/scoped_tmpfile.cc
vendored
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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 LLC 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 that is deleted in the
|
||||
// destructor.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/scoped_tmpfile.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "common/linux/eintr_wrapper.h"
|
||||
|
||||
#if !defined(__ANDROID__)
|
||||
#define TEMPDIR "/tmp"
|
||||
#else
|
||||
#define TEMPDIR "/data/local/tmp"
|
||||
#endif
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
ScopedTmpFile::ScopedTmpFile() = default;
|
||||
|
||||
ScopedTmpFile::~ScopedTmpFile() {
|
||||
if (fd_ >= 0) {
|
||||
close(fd_);
|
||||
fd_ = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool ScopedTmpFile::InitEmpty() {
|
||||
// Prevent calling Init when fd_ is already valid, leaking the file.
|
||||
if (fd_ != -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Respect the TMPDIR environment variable.
|
||||
const char* tempdir = getenv("TMPDIR");
|
||||
if (!tempdir) {
|
||||
tempdir = TEMPDIR;
|
||||
}
|
||||
|
||||
// Create a temporary file that is not linked in to the filesystem, and that
|
||||
// is only accessible by the current user.
|
||||
fd_ = open(tempdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
|
||||
|
||||
return fd_ >= 0;
|
||||
}
|
||||
|
||||
bool ScopedTmpFile::InitString(const char* text) {
|
||||
return InitData(text, strlen(text));
|
||||
}
|
||||
|
||||
bool ScopedTmpFile::InitData(const void* data, size_t data_len) {
|
||||
if (!InitEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return SetContents(data, data_len);
|
||||
}
|
||||
|
||||
bool ScopedTmpFile::SetContents(const void* data, size_t data_len) {
|
||||
ssize_t r = HANDLE_EINTR(write(fd_, data, data_len));
|
||||
if (r != static_cast<ssize_t>(data_len)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return 0 == lseek(fd_, 0, SEEK_SET);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
85
externals/breakpad/src/common/linux/scoped_tmpfile.h
vendored
Normal file
85
externals/breakpad/src/common/linux/scoped_tmpfile.h
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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 LLC 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 that is deleted in the
|
||||
// destructor.
|
||||
|
||||
#ifndef COMMON_LINUX_SCOPED_TMPFILE_H_
|
||||
#define COMMON_LINUX_SCOPED_TMPFILE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
// Small RAII wrapper for temporary files.
|
||||
//
|
||||
// Example:
|
||||
// ScopedTmpFile tmp;
|
||||
// if (tmp.Init("Some file contents")) {
|
||||
// ...
|
||||
// }
|
||||
class ScopedTmpFile {
|
||||
public:
|
||||
// Initialize the ScopedTmpFile object - this does not create the temporary
|
||||
// file until Init is called.
|
||||
ScopedTmpFile();
|
||||
|
||||
// Destroy temporary file on scope exit.
|
||||
~ScopedTmpFile();
|
||||
|
||||
// Creates the empty temporary file - returns true iff the temporary file was
|
||||
// created successfully. Should always be checked before using the file.
|
||||
bool InitEmpty();
|
||||
|
||||
// Creates the temporary file with the provided C string. The terminating null
|
||||
// is not written. Returns true iff the temporary file was created
|
||||
// successfully and the contents were written successfully.
|
||||
bool InitString(const char* text);
|
||||
|
||||
// Creates the temporary file with the provided data. Returns true iff the
|
||||
// temporary file was created successfully and the contents were written
|
||||
// successfully.
|
||||
bool InitData(const void* data, size_t data_len);
|
||||
|
||||
// Returns the Posix file descriptor for the test file, or -1 if Init()
|
||||
// returned false. Note: on Windows, this always returns -1.
|
||||
int GetFd() const {
|
||||
return fd_;
|
||||
}
|
||||
|
||||
private:
|
||||
// Set the contents of the temporary file, and seek back to the start of the
|
||||
// file. On failure, returns false.
|
||||
bool SetContents(const void* data, size_t data_len);
|
||||
|
||||
int fd_ = -1;
|
||||
};
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
#endif // COMMON_LINUX_SCOPED_TMPFILE_H_
|
||||
50
externals/breakpad/src/common/linux/scoped_tmpfile_unittest.cc
vendored
Normal file
50
externals/breakpad/src/common/linux/scoped_tmpfile_unittest.cc
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2022 Google LLC
|
||||
//
|
||||
// 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 LLC 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.
|
||||
|
||||
// scoped_tmpfile_unittest.cc: Unit tests for google_breakpad::ScopedTmpfile.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // Must come first
|
||||
#endif
|
||||
|
||||
#include "common/linux/scoped_tmpfile.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
|
||||
using google_breakpad::ScopedTmpFile;
|
||||
|
||||
TEST(ScopedTmpFileTest, CheckContentsMatch) {
|
||||
ScopedTmpFile file;
|
||||
ASSERT_TRUE(file.InitString("Test"));
|
||||
|
||||
char file_contents[5] = {0};
|
||||
ASSERT_EQ(4, read(file.GetFd(), file_contents, sizeof(file_contents)));
|
||||
EXPECT_STREQ(file_contents, "Test");
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue