- Remove crash dumper (unused yet..)
- Fix random crashes on custom controls
This commit is contained in:
khanhduytran0
2020-11-30 19:12:26 +07:00
parent a08a0cd46d
commit 4089fa270c
161 changed files with 8 additions and 21782 deletions

View File

@@ -128,6 +128,7 @@ public class PojavLoginActivity extends BaseActivity
if (revokeCount >= 3) {
Toast.makeText(PojavLoginActivity.this, R.string.toast_permission_denied, Toast.LENGTH_LONG).show();
finish();
return 0;
}
requestStoragePermission();

View File

@@ -156,7 +156,12 @@ public class ControlButton extends Button implements OnLongClickListener, OnTouc
if (getParent() != null) {
((ControlLayout) getParent()).hideAllHandleViews();
}
mHandleView.show();
try {
mHandleView.show();
} catch (Throwable th) {
th.printStackTrace();
}
}
}

View File

@@ -39,6 +39,7 @@ public class ControlLayout extends FrameLayout
public void loadLayout(CustomControls controlLayout) {
if (mModifiable) {
hideAllHandleViews();
removeAllViews();
}

View File

@@ -78,7 +78,6 @@ JNIEXPORT jint JNICALL Java_sun_awt_X11GraphicsEnvironment_getNumScreens(JNIEnv
* 0 otherwise
*/
JNIEXPORT jint JNICALL Java_sun_awt_X11GraphicsEnvironment_checkShmExt(JNIEnv *env, jclass cls, jboolean verbose) {
// This could be return 0 once MITShm implementation added
return (jint) -1;
}

View File

@@ -1,15 +0,0 @@
BasedOnStyle: Google
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
IndentWidth: 2
ContinuationIndentWidth: 2
PointerAlignment: Left
TabWidth: 2
UseTab: Never
PenaltyExcessCharacter: 32
Cpp11BracedListStyle: false

View File

@@ -1,79 +0,0 @@
LOCAL_PATH := $(call my-dir)
common_cppflags := \
-std=gnu++11 \
-W \
-Wall \
-Wextra \
-Wunused \
-Werror \
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
backtrace.cpp \
debuggerd.cpp \
elf_utils.cpp \
getevent.cpp \
signal_sender.cpp \
tombstone.cpp \
utility.cpp \
selinux_fake.cpp
LOCAL_SRC_FILES_arm := arm/machine.cpp
LOCAL_SRC_FILES_arm64 := arm64/machine.cpp
LOCAL_SRC_FILES_x86 := x86/machine.cpp
LOCAL_SRC_FILES_x86_64 := x86_64/machine.cpp
LOCAL_CPPFLAGS := $(common_cppflags) \
-I$(HERE_PATH)/crash_dump/libbase/include
LOCAL_INIT_RC_32 := debuggerd.rc
LOCAL_INIT_RC_64 := debuggerd64.rc
ifeq ($(TARGET_IS_64_BIT),true)
LOCAL_CPPFLAGS += -DTARGET_IS_64_BIT
endif
LOCAL_LDLIBS := -llog
LOCAL_SHARED_LIBRARIES := \
libbacktrace \
libcrashdumpbase
LOCAL_CLANG := true
LOCAL_MODULE := crashdump
LOCAL_MULTILIB := both
include $(BUILD_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := crasher.c
LOCAL_SRC_FILES_arm := arm/crashglue.S
LOCAL_SRC_FILES_arm64 := arm64/crashglue.S
LOCAL_SRC_FILES_mips := mips/crashglue.S
LOCAL_SRC_FILES_mips64 := mips64/crashglue.S
LOCAL_SRC_FILES_x86 := x86/crashglue.S
LOCAL_SRC_FILES_x86_64 := x86_64/crashglue.S
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += -fstack-protector-all -Werror -Wno-free-nonheap-object -Wno-date-time \
-I$(HERE_PATH)/crash_dump/libbase/include
#LOCAL_FORCE_STATIC_EXECUTABLE := true
LOCAL_SHARED_LIBRARIES := libcutils liblog libc
# The arm emulator has VFP but not VFPv3-D32.
ifeq ($(ARCH_ARM_HAVE_VFP_D32),true)
LOCAL_ASFLAGS_arm += -DHAS_VFP_D32
endif
LOCAL_MODULE := crasher
LOCAL_MODULE_STEM_32 := crasher
LOCAL_MODULE_STEM_64 := crasher64
LOCAL_MULTILIB := both
# include $(BUILD_EXECUTABLE)

View File

@@ -1,190 +0,0 @@
Copyright (c) 2005-2008, The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@@ -1,64 +0,0 @@
.globl crash1
.type crash1, %function
crash1:
ldr r0, =0xa5a50000
ldr r1, =0xa5a50001
ldr r2, =0xa5a50002
ldr r3, =0xa5a50003
ldr r4, =0xa5a50004
ldr r5, =0xa5a50005
ldr r6, =0xa5a50006
ldr r7, =0xa5a50007
ldr r8, =0xa5a50008
ldr r9, =0xa5a50009
ldr r10, =0xa5a50010
ldr r11, =0xa5a50011
ldr r12, =0xa5a50012
fconstd d0, #0
fconstd d1, #1
fconstd d2, #2
fconstd d3, #3
fconstd d4, #4
fconstd d5, #5
fconstd d6, #6
fconstd d7, #7
fconstd d8, #8
fconstd d9, #9
fconstd d10, #10
fconstd d11, #11
fconstd d12, #12
fconstd d13, #13
fconstd d14, #14
fconstd d15, #15
#if defined(HAS_VFP_D32)
fconstd d16, #16
fconstd d17, #17
fconstd d18, #18
fconstd d19, #19
fconstd d20, #20
fconstd d21, #21
fconstd d22, #22
fconstd d23, #23
fconstd d24, #24
fconstd d25, #25
fconstd d26, #26
fconstd d27, #27
fconstd d28, #28
fconstd d29, #29
fconstd d30, #30
fconstd d31, #31
#endif
mov lr, #0
ldr lr, [lr]
b .
.globl crashnostack
.type crashnostack, %function
crashnostack:
mov sp, #0
mov r0, #0
ldr r0, [r0]
b .

View File

@@ -1,83 +0,0 @@
/*
*
* Copyright 2006, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "DEBUG"
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <sys/ptrace.h>
#include <backtrace/Backtrace.h>
#include <log/log.h>
#include "machine.h"
#include "utility.h"
void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
pt_regs regs;
if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &regs)) {
ALOGE("cannot get registers: %s\n", strerror(errno));
return;
}
static const char reg_names[] = "r0r1r2r3r4r5r6r7r8r9slfpipsp";
for (int reg = 0; reg < 14; reg++) {
dump_memory(log, backtrace, regs.uregs[reg], "memory near %.2s:", &reg_names[reg * 2]);
}
dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_pc), "code around pc:");
if (regs.ARM_pc != regs.ARM_lr) {
dump_memory(log, backtrace, static_cast<uintptr_t>(regs.ARM_lr), "code around lr:");
}
}
void dump_registers(log_t* log, pid_t tid) {
pt_regs r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r)) {
ALOGE("cannot get registers: %s\n", strerror(errno));
return;
}
_LOG(log, logtype::REGISTERS, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
static_cast<uint32_t>(r.ARM_r0), static_cast<uint32_t>(r.ARM_r1),
static_cast<uint32_t>(r.ARM_r2), static_cast<uint32_t>(r.ARM_r3));
_LOG(log, logtype::REGISTERS, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
static_cast<uint32_t>(r.ARM_r4), static_cast<uint32_t>(r.ARM_r5),
static_cast<uint32_t>(r.ARM_r6), static_cast<uint32_t>(r.ARM_r7));
_LOG(log, logtype::REGISTERS, " r8 %08x r9 %08x sl %08x fp %08x\n",
static_cast<uint32_t>(r.ARM_r8), static_cast<uint32_t>(r.ARM_r9),
static_cast<uint32_t>(r.ARM_r10), static_cast<uint32_t>(r.ARM_fp));
_LOG(log, logtype::REGISTERS, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
static_cast<uint32_t>(r.ARM_ip), static_cast<uint32_t>(r.ARM_sp),
static_cast<uint32_t>(r.ARM_lr), static_cast<uint32_t>(r.ARM_pc),
static_cast<uint32_t>(r.ARM_cpsr));
user_vfp vfp_regs;
if (ptrace(PTRACE_GETVFPREGS, tid, 0, &vfp_regs)) {
ALOGE("cannot get FP registers: %s\n", strerror(errno));
return;
}
for (size_t i = 0; i < 32; i += 2) {
_LOG(log, logtype::FP_REGISTERS, " d%-2d %016llx d%-2d %016llx\n",
i, vfp_regs.fpregs[i], i+1, vfp_regs.fpregs[i+1]);
}
_LOG(log, logtype::FP_REGISTERS, " scr %08lx\n", vfp_regs.fpscr);
}

View File

@@ -1,79 +0,0 @@
.globl crash1
.type crash1, %function
crash1:
ldr x0, =0xa5a50000
ldr x1, =0xa5a50001
ldr x2, =0xa5a50002
ldr x3, =0xa5a50003
ldr x4, =0xa5a50004
ldr x5, =0xa5a50005
ldr x6, =0xa5a50006
ldr x7, =0xa5a50007
ldr x8, =0xa5a50008
ldr x9, =0xa5a50009
ldr x10, =0xa5a50010
ldr x11, =0xa5a50011
ldr x12, =0xa5a50012
ldr x13, =0xa5a50013
ldr x14, =0xa5a50014
ldr x15, =0xa5a50015
ldr x16, =0xa5a50016
ldr x17, =0xa5a50017
ldr x18, =0xa5a50018
ldr x19, =0xa5a50019
ldr x20, =0xa5a50020
ldr x21, =0xa5a50021
ldr x22, =0xa5a50022
ldr x23, =0xa5a50023
ldr x24, =0xa5a50024
ldr x25, =0xa5a50025
ldr x26, =0xa5a50026
ldr x27, =0xa5a50027
ldr x28, =0xa5a50028
ldr x29, =0xa5a50029
fmov d0, -1.0 // -1 is more convincing than 0.
fmov d1, 1.0
fmov d2, 2.0
fmov d3, 3.0
fmov d4, 4.0
fmov d5, 5.0
fmov d6, 6.0
fmov d7, 7.0
fmov d8, 8.0
fmov d9, 9.0
fmov d10, 10.0
fmov d11, 11.0
fmov d12, 12.0
fmov d13, 13.0
fmov d14, 14.0
fmov d15, 15.0
fmov d16, 16.0
fmov d17, 17.0
fmov d18, 18.0
fmov d19, 19.0
fmov d20, 20.0
fmov d21, 21.0
fmov d22, 22.0
fmov d23, 23.0
fmov d24, 24.0
fmov d25, 25.0
fmov d26, 26.0
fmov d27, 27.0
fmov d28, 28.0
fmov d29, 29.0
fmov d30, 30.0
fmov d31, 31.0
mov x30, xzr
ldr x30, [x30]
b .
.globl crashnostack
.type crashnostack, %function
crashnostack:
mov x0, xzr
add sp, x0, xzr
ldr x0, [x0]
b .

View File

@@ -1,101 +0,0 @@
/*
*
* Copyright 2014, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "DEBUG"
#include <elf.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <sys/ptrace.h>
#include <sys/uio.h>
#include <backtrace/Backtrace.h>
#include <log/log.h>
#include "machine.h"
#include "utility.h"
void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
struct user_pt_regs regs;
struct iovec io;
io.iov_base = &regs;
io.iov_len = sizeof(regs);
if (ptrace(PTRACE_GETREGSET, backtrace->Tid(), reinterpret_cast<void*>(NT_PRSTATUS), &io) == -1) {
ALOGE("ptrace failed to get registers: %s", strerror(errno));
return;
}
for (int reg = 0; reg < 31; reg++) {
dump_memory(log, backtrace, regs.regs[reg], "memory near x%d:", reg);
}
dump_memory(log, backtrace, static_cast<uintptr_t>(regs.pc), "code around pc:");
if (regs.pc != regs.sp) {
dump_memory(log, backtrace, static_cast<uintptr_t>(regs.sp), "code around sp:");
}
}
void dump_registers(log_t* log, pid_t tid) {
struct user_pt_regs r;
struct iovec io;
io.iov_base = &r;
io.iov_len = sizeof(r);
if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRSTATUS, (void*) &io) == -1) {
ALOGE("ptrace error: %s\n", strerror(errno));
return;
}
for (int i = 0; i < 28; i += 4) {
_LOG(log, logtype::REGISTERS,
" x%-2d %016llx x%-2d %016llx x%-2d %016llx x%-2d %016llx\n",
i, r.regs[i],
i+1, r.regs[i+1],
i+2, r.regs[i+2],
i+3, r.regs[i+3]);
}
_LOG(log, logtype::REGISTERS, " x28 %016llx x29 %016llx x30 %016llx\n",
r.regs[28], r.regs[29], r.regs[30]);
_LOG(log, logtype::REGISTERS, " sp %016llx pc %016llx pstate %016llx\n",
r.sp, r.pc, r.pstate);
struct user_fpsimd_state f;
io.iov_base = &f;
io.iov_len = sizeof(f);
if (ptrace(PTRACE_GETREGSET, tid, (void*) NT_PRFPREG, (void*) &io) == -1) {
ALOGE("ptrace error: %s\n", strerror(errno));
return;
}
for (int i = 0; i < 32; i += 2) {
_LOG(log, logtype::FP_REGISTERS,
" v%-2d %016" PRIx64 "%016" PRIx64 " v%-2d %016" PRIx64 "%016" PRIx64 "\n",
i,
static_cast<uint64_t>(f.vregs[i] >> 64),
static_cast<uint64_t>(f.vregs[i]),
i+1,
static_cast<uint64_t>(f.vregs[i+1] >> 64),
static_cast<uint64_t>(f.vregs[i+1]));
}
_LOG(log, logtype::FP_REGISTERS, " fpsr %08x fpcr %08x\n", f.fpsr, f.fpcr);
}

View File

@@ -1,120 +0,0 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "DEBUG"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <limits.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <memory>
#include <string>
#include <backtrace/Backtrace.h>
#include <log/log.h>
#include "backtrace.h"
#include "utility.h"
static void dump_process_header(log_t* log, pid_t pid) {
char path[PATH_MAX];
char procnamebuf[1024];
char* procname = NULL;
FILE* fp;
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
if ((fp = fopen(path, "r"))) {
procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
fclose(fp);
}
time_t t = time(NULL);
struct tm tm;
localtime_r(&t, &tm);
char timestr[64];
strftime(timestr, sizeof(timestr), "%F %T", &tm);
_LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
if (procname) {
_LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", procname);
}
_LOG(log, logtype::BACKTRACE, "ABI: '%s'\n", ABI_STRING);
}
static void dump_process_footer(log_t* log, pid_t pid) {
_LOG(log, logtype::BACKTRACE, "\n----- end %d -----\n", pid);
}
static void dump_thread(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid) {
char path[PATH_MAX];
char threadnamebuf[1024];
char* threadname = NULL;
FILE* fp;
snprintf(path, sizeof(path), "/proc/%d/comm", tid);
if ((fp = fopen(path, "r"))) {
threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp);
fclose(fp);
if (threadname) {
size_t len = strlen(threadname);
if (len && threadname[len - 1] == '\n') {
threadname[len - 1] = '\0';
}
}
}
_LOG(log, logtype::BACKTRACE, "\n\"%s\" sysTid=%d\n", threadname ? threadname : "<unknown>", tid);
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
if (backtrace->Unwind(0)) {
dump_backtrace_to_log(backtrace.get(), log, " ");
} else {
ALOGE("Unwind failed: tid = %d: %s", tid,
backtrace->GetErrorString(backtrace->GetError()).c_str());
}
}
void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid,
const std::set<pid_t>& siblings, std::string* amfd_data) {
log_t log;
log.tfd = fd;
log.amfd_data = amfd_data;
dump_process_header(&log, pid);
dump_thread(&log, map, pid, tid);
for (pid_t sibling : siblings) {
dump_thread(&log, map, pid, sibling);
}
dump_process_footer(&log, pid);
}
void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix) {
for (size_t i = 0; i < backtrace->NumFrames(); i++) {
_LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, backtrace->FormatFrameData(i).c_str());
}
}

View File

@@ -1,38 +0,0 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DEBUGGERD_BACKTRACE_H
#define _DEBUGGERD_BACKTRACE_H
#include <sys/types.h>
#include <set>
#include <string>
#include "utility.h"
class Backtrace;
class BacktraceMap;
// Dumps a backtrace using a format similar to what Dalvik uses so that the result
// can be intermixed in a bug report.
void dump_backtrace(int fd, BacktraceMap* map, pid_t pid, pid_t tid,
const std::set<pid_t>& siblings, std::string* amfd_data);
/* Dumps the backtrace in the backtrace data structure to the log. */
void dump_backtrace_to_log(Backtrace* backtrace, log_t* log, const char* prefix);
#endif // _DEBUGGERD_BACKTRACE_H

View File

@@ -1,215 +0,0 @@
#include <assert.h>
#include <errno.h>
#include <pthread.h>
#include <sched.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cutils/sockets.h>
#include <log/log.h>
#ifndef __unused
#define __unused __attribute__((__unused__))
#endif
extern const char* __progname;
void crash1(void);
void crashnostack(void);
static int do_action(const char* arg);
static void maybe_abort() {
if (time(0) != 42) {
abort();
}
}
static char* smash_stack_dummy_buf;
__attribute__ ((noinline)) static void smash_stack_dummy_function(volatile int* plen) {
smash_stack_dummy_buf[*plen] = 0;
}
// This must be marked with "__attribute__ ((noinline))", to ensure the
// compiler generates the proper stack guards around this function.
// Assign local array address to global variable to force stack guards.
// Use another noinline function to corrupt the stack.
__attribute__ ((noinline)) static int smash_stack(volatile int* plen) {
printf("crasher: deliberately corrupting stack...\n");
char buf[128];
smash_stack_dummy_buf = buf;
// This should corrupt stack guards and make process abort.
smash_stack_dummy_function(plen);
return 0;
}
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Winfinite-recursion"
#endif
static void* global = 0; // So GCC doesn't optimize the tail recursion out of overflow_stack.
__attribute__((noinline)) static void overflow_stack(void* p) {
void* buf[1];
buf[0] = p;
global = buf;
overflow_stack(&buf);
}
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
static void *noisy(void *x)
{
char c = (uintptr_t) x;
for(;;) {
usleep(250*1000);
write(2, &c, 1);
if(c == 'C') *((volatile unsigned*) 0) = 42;
}
return NULL;
}
static int ctest()
{
pthread_t thr;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&thr, &attr, noisy, (void*) 'A');
pthread_create(&thr, &attr, noisy, (void*) 'B');
pthread_create(&thr, &attr, noisy, (void*) 'C');
for(;;) ;
return 0;
}
static void* thread_callback(void* raw_arg)
{
return (void*) (uintptr_t) do_action((const char*) raw_arg);
}
static int do_action_on_thread(const char* arg)
{
pthread_t t;
pthread_create(&t, NULL, thread_callback, (void*) arg);
void* result = NULL;
pthread_join(t, &result);
return (int) (uintptr_t) result;
}
__attribute__((noinline)) static int crash3(int a) {
*((int*) 0xdead) = a;
return a*4;
}
__attribute__((noinline)) static int crash2(int a) {
a = crash3(a) + 2;
return a*3;
}
__attribute__((noinline)) static int crash(int a) {
a = crash2(a) + 1;
return a*2;
}
static void abuse_heap() {
char buf[16];
free((void*) buf); // GCC is smart enough to warn about this, but we're doing it deliberately.
}
static void sigsegv_non_null() {
int* a = (int *)(&do_action);
*a = 42;
}
static int do_action(const char* arg)
{
fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid());
if (!strncmp(arg, "thread-", strlen("thread-"))) {
return do_action_on_thread(arg + strlen("thread-"));
} else if (!strcmp(arg, "SIGSEGV-non-null")) {
sigsegv_non_null();
} else if (!strcmp(arg, "smash-stack")) {
volatile int len = 128;
return smash_stack(&len);
} else if (!strcmp(arg, "stack-overflow")) {
overflow_stack(NULL);
} else if (!strcmp(arg, "nostack")) {
crashnostack();
} else if (!strcmp(arg, "ctest")) {
return ctest();
} else if (!strcmp(arg, "exit")) {
exit(1);
} else if (!strcmp(arg, "crash") || !strcmp(arg, "SIGSEGV")) {
return crash(42);
} else if (!strcmp(arg, "abort")) {
maybe_abort();
} else if (!strcmp(arg, "assert")) {
__assert("some_file.c", 123, "false");
} else if (!strcmp(arg, "assert2")) {
__assert2("some_file.c", 123, "some_function", "false");
} else if (!strcmp(arg, "LOG_ALWAYS_FATAL")) {
LOG_ALWAYS_FATAL("hello %s", "world");
} else if (!strcmp(arg, "LOG_ALWAYS_FATAL_IF")) {
LOG_ALWAYS_FATAL_IF(true, "hello %s", "world");
} else if (!strcmp(arg, "SIGFPE")) {
raise(SIGFPE);
return EXIT_SUCCESS;
} else if (!strcmp(arg, "SIGTRAP")) {
raise(SIGTRAP);
return EXIT_SUCCESS;
} else if (!strcmp(arg, "heap-usage")) {
abuse_heap();
} else if (!strcmp(arg, "SIGSEGV-unmapped")) {
char* map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
munmap(map, sizeof(int));
map[0] = '8';
}
fprintf(stderr, "%s OP\n", __progname);
fprintf(stderr, "where OP is:\n");
fprintf(stderr, " smash-stack overwrite a stack-guard canary\n");
fprintf(stderr, " stack-overflow recurse until the stack overflows\n");
fprintf(stderr, " heap-corruption cause a libc abort by corrupting the heap\n");
fprintf(stderr, " heap-usage cause a libc abort by abusing a heap function\n");
fprintf(stderr, " nostack crash with a NULL stack pointer\n");
fprintf(stderr, " ctest (obsoleted by thread-crash?)\n");
fprintf(stderr, " exit call exit(1)\n");
fprintf(stderr, " abort call abort()\n");
fprintf(stderr, " assert call assert() without a function\n");
fprintf(stderr, " assert2 call assert() with a function\n");
fprintf(stderr, " LOG_ALWAYS_FATAL call LOG_ALWAYS_FATAL\n");
fprintf(stderr, " LOG_ALWAYS_FATAL_IF call LOG_ALWAYS_FATAL\n");
fprintf(stderr, " SIGFPE cause a SIGFPE\n");
fprintf(stderr, " SIGSEGV cause a SIGSEGV at address 0x0 (synonym: crash)\n");
fprintf(stderr, " SIGSEGV-non-null cause a SIGSEGV at a non-zero address\n");
fprintf(stderr, " SIGSEGV-unmapped mmap/munmap a region of memory and then attempt to access it\n");
fprintf(stderr, " SIGTRAP cause a SIGTRAP\n");
fprintf(stderr, "prefix any of the above with 'thread-' to not run\n");
fprintf(stderr, "on the process' main thread.\n");
return EXIT_SUCCESS;
}
int main(int argc, char **argv)
{
fprintf(stderr,"crasher: built at " __TIME__ "!@\n");
if(argc > 1) {
return do_action(argv[1]);
} else {
crash1();
}
return 0;
}

View File

@@ -1,950 +0,0 @@
/*
* Copyright 2006, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <arpa/inet.h>
#include <dirent.h>
#include <elf.h>
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <sys/poll.h>
#include <sys/prctl.h>
#include <sys/ptrace.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <time.h>
#include <memory>
#include <set>
#include <string>
#include <selinux/android.h>
#include <log/logger.h>
#include <android-base/file.h>
#include <android-base/unique_fd.h>
#include <cutils/debugger.h>
#include <cutils/properties.h>
#include <cutils/sockets.h>
#include <nativehelper/ScopedFd.h>
#include <linux/input.h>
#include <private/android_filesystem_config.h>
#include "backtrace.h"
#include "getevent.h"
#include "signal_sender.h"
#include "tombstone.h"
#include "utility.h"
// If the 32 bit executable is compiled on a 64 bit system,
// use the 32 bit socket name.
#if defined(TARGET_IS_64_BIT) && !defined(__LP64__)
#define SOCKET_NAME DEBUGGER32_SOCKET_NAME
#else
#define SOCKET_NAME DEBUGGER_SOCKET_NAME
#endif
struct debugger_request_t {
debugger_action_t action;
pid_t pid, tid;
uid_t uid, gid;
uintptr_t abort_msg_address;
int32_t original_si_code;
};
static void wait_for_user_action(const debugger_request_t& request) {
// Explain how to attach the debugger.
ALOGI("***********************************************************\n"
"* Process %d has been suspended while crashing.\n"
"* To attach gdbserver and start gdb, run this on the host:\n"
"*\n"
"* gdbclient.py -p %d\n"
"*\n"
"* Wait for gdb to start, then press the VOLUME DOWN key\n"
"* to let the process continue crashing.\n"
"***********************************************************",
request.pid, request.tid);
// Wait for VOLUME DOWN.
while (true) {
input_event e;
if (get_event(&e, -1) == 0) {
if (e.type == EV_KEY && e.code == KEY_VOLUMEDOWN && e.value == 0) {
break;
}
}
}
ALOGI("debuggerd resuming process %d", request.pid);
}
static int get_process_info(pid_t tid, pid_t* out_pid, uid_t* out_uid, uid_t* out_gid) {
char path[64];
snprintf(path, sizeof(path), "/proc/%d/status", tid);
FILE* fp = fopen(path, "r");
if (!fp) {
return -1;
}
int fields = 0;
char line[1024];
while (fgets(line, sizeof(line), fp)) {
size_t len = strlen(line);
if (len > 6 && !memcmp(line, "Tgid:\t", 6)) {
*out_pid = atoi(line + 6);
fields |= 1;
} else if (len > 5 && !memcmp(line, "Uid:\t", 5)) {
*out_uid = atoi(line + 5);
fields |= 2;
} else if (len > 5 && !memcmp(line, "Gid:\t", 5)) {
*out_gid = atoi(line + 5);
fields |= 4;
}
}
fclose(fp);
return fields == 7 ? 0 : -1;
}
/*
* Corresponds with debugger_action_t enum type in
* include/cutils/debugger.h.
*/
static const char *debuggerd_perms[] = {
NULL, /* crash is only used on self, no check applied */
"dump_tombstone",
"dump_backtrace"
};
static int audit_callback(void* data, security_class_t /* cls */, char* buf, size_t len)
{
struct debugger_request_t* req = reinterpret_cast<debugger_request_t*>(data);
if (!req) {
ALOGE("No debuggerd request audit data");
return 0;
}
snprintf(buf, len, "pid=%d uid=%d gid=%d", req->pid, req->uid, req->gid);
return 0;
}
static bool selinux_action_allowed(int s, debugger_request_t* request)
{
char *scon = NULL, *tcon = NULL;
const char *tclass = "debuggerd";
const char *perm;
bool allowed = false;
if (request->action <= 0 || request->action >= (sizeof(debuggerd_perms)/sizeof(debuggerd_perms[0]))) {
ALOGE("SELinux: No permission defined for debugger action %d", request->action);
return false;
}
perm = debuggerd_perms[request->action];
if (getpeercon(s, &scon) < 0) {
ALOGE("Cannot get peer context from socket\n");
goto out;
}
if (getpidcon(request->tid, &tcon) < 0) {
ALOGE("Cannot get context for tid %d\n", request->tid);
goto out;
}
allowed = true; // (selinux_check_access(scon, tcon, tclass, perm, reinterpret_cast<void*>(request)) == 0);
out:
freecon(scon);
freecon(tcon);
return allowed;
}
static bool pid_contains_tid(pid_t pid, pid_t tid) {
char task_path[PATH_MAX];
if (snprintf(task_path, PATH_MAX, "/proc/%d/task/%d", pid, tid) >= PATH_MAX) {
ALOGE("debuggerd: task path overflow (pid = %d, tid = %d)\n", pid, tid);
exit(1);
}
return access(task_path, F_OK) == 0;
}
static int read_request(int fd, debugger_request_t* out_request) {
ucred cr;
socklen_t len = sizeof(cr);
int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);
if (status != 0) {
ALOGE("cannot get credentials");
return -1;
}
ALOGV("reading tid");
fcntl(fd, F_SETFL, O_NONBLOCK);
pollfd pollfds[1];
pollfds[0].fd = fd;
pollfds[0].events = POLLIN;
pollfds[0].revents = 0;
status = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));
if (status != 1) {
ALOGE("timed out reading tid (from pid=%d uid=%d)\n", cr.pid, cr.uid);
return -1;
}
debugger_msg_t msg;
memset(&msg, 0, sizeof(msg));
status = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));
if (status < 0) {
ALOGE("read failure? %s (pid=%d uid=%d)\n", strerror(errno), cr.pid, cr.uid);
return -1;
}
if (status != sizeof(debugger_msg_t)) {
ALOGE("invalid crash request of size %d (from pid=%d uid=%d)\n", status, cr.pid, cr.uid);
return -1;
}
out_request->action = static_cast<debugger_action_t>(msg.action);
out_request->tid = msg.tid;
out_request->pid = cr.pid;
out_request->uid = cr.uid;
out_request->gid = cr.gid;
out_request->abort_msg_address = msg.abort_msg_address;
out_request->original_si_code = msg.original_si_code;
if (msg.action == DEBUGGER_ACTION_CRASH) {
// Ensure that the tid reported by the crashing process is valid.
// This check needs to happen again after ptracing the requested thread to prevent a race.
if (!pid_contains_tid(out_request->pid, out_request->tid)) {
ALOGE("tid %d does not exist in pid %d. ignoring debug request\n", out_request->tid,
out_request->pid);
return -1;
}
} else if (cr.uid == 0 || (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) {
// Only root or system can ask us to attach to any process and dump it explicitly.
// However, system is only allowed to collect backtraces but cannot dump tombstones.
status = get_process_info(out_request->tid, &out_request->pid,
&out_request->uid, &out_request->gid);
if (status < 0) {
ALOGE("tid %d does not exist. ignoring explicit dump request\n", out_request->tid);
return -1;
}
if (!selinux_action_allowed(fd, out_request))
return -1;
} else {
// No one else is allowed to dump arbitrary processes.
return -1;
}
return 0;
}
static int activity_manager_connect() {
android::base::unique_fd amfd(socket(PF_UNIX, SOCK_STREAM, 0));
if (amfd.get() < -1) {
ALOGE("debuggerd: Unable to connect to activity manager (socket failed: %s)", strerror(errno));
return -1;
}
struct sockaddr_un address;
memset(&address, 0, sizeof(address));
address.sun_family = AF_UNIX;
// The path used here must match the value defined in NativeCrashListener.java.
strncpy(address.sun_path, "/data/system/ndebugsocket", sizeof(address.sun_path));
if (TEMP_FAILURE_RETRY(connect(amfd.get(), reinterpret_cast<struct sockaddr*>(&address),
sizeof(address))) == -1) {
ALOGE("debuggerd: Unable to connect to activity manager (connect failed: %s)", strerror(errno));
return -1;
}
struct timeval tv;
memset(&tv, 0, sizeof(tv));
tv.tv_sec = 1; // tight leash
if (setsockopt(amfd.get(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
ALOGE("debuggerd: Unable to connect to activity manager (setsockopt SO_SNDTIMEO failed: %s)",
strerror(errno));
return -1;
}
tv.tv_sec = 3; // 3 seconds on handshake read
if (setsockopt(amfd.get(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
ALOGE("debuggerd: Unable to connect to activity manager (setsockopt SO_RCVTIMEO failed: %s)",
strerror(errno));
return -1;
}
return amfd.release();
}
static void activity_manager_write(int pid, int signal, int amfd, const std::string& amfd_data) {
if (amfd == -1) {
return;
}
// Activity Manager protocol: binary 32-bit network-byte-order ints for the
// pid and signal number, followed by the raw text of the dump, culminating
// in a zero byte that marks end-of-data.
uint32_t datum = htonl(pid);
if (!android::base::WriteFully(amfd, &datum, 4)) {
ALOGE("AM pid write failed: %s\n", strerror(errno));
return;
}
datum = htonl(signal);
if (!android::base::WriteFully(amfd, &datum, 4)) {
ALOGE("AM signal write failed: %s\n", strerror(errno));
return;
}
if (!android::base::WriteFully(amfd, amfd_data.c_str(), amfd_data.size())) {
ALOGE("AM data write failed: %s\n", strerror(errno));
return;
}
// Send EOD to the Activity Manager, then wait for its ack to avoid racing
// ahead and killing the target out from under it.
uint8_t eodMarker = 0;
if (!android::base::WriteFully(amfd, &eodMarker, 1)) {
ALOGE("AM eod write failed: %s\n", strerror(errno));
return;
}
// 3 sec timeout reading the ack; we're fine if the read fails.
android::base::ReadFully(amfd, &eodMarker, 1);
}
static bool should_attach_gdb(const debugger_request_t& request) {
if (request.action == DEBUGGER_ACTION_CRASH) {
return property_get_bool("debug.debuggerd.wait_for_gdb", false);
}
return false;
}
#if defined(__LP64__)
static bool is32bit(pid_t tid) {
char* exeline;
if (asprintf(&exeline, "/proc/%d/exe", tid) == -1) {
return false;
}
int fd = TEMP_FAILURE_RETRY(open(exeline, O_RDONLY | O_CLOEXEC));
int saved_errno = errno;
free(exeline);
if (fd == -1) {
ALOGW("Failed to open /proc/%d/exe %s", tid, strerror(saved_errno));
return false;
}
char ehdr[EI_NIDENT];
ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &ehdr, sizeof(ehdr)));
close(fd);
if (bytes != (ssize_t) sizeof(ehdr) || memcmp(ELFMAG, ehdr, SELFMAG) != 0) {
return false;
}
if (ehdr[EI_CLASS] == ELFCLASS32) {
return true;
}
return false;
}
static void redirect_to_32(int fd, debugger_request_t* request) {
debugger_msg_t msg;
memset(&msg, 0, sizeof(msg));
msg.tid = request->tid;
msg.action = request->action;
int sock_fd = socket_local_client(DEBUGGER32_SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
SOCK_STREAM | SOCK_CLOEXEC);
if (sock_fd < 0) {
ALOGE("Failed to connect to debuggerd32: %s", strerror(errno));
return;
}
if (TEMP_FAILURE_RETRY(write(sock_fd, &msg, sizeof(msg))) != (ssize_t) sizeof(msg)) {
ALOGE("Failed to write request to debuggerd32 socket: %s", strerror(errno));
close(sock_fd);
return;
}
char ack;
if (TEMP_FAILURE_RETRY(read(sock_fd, &ack, 1)) == -1) {
ALOGE("Failed to read ack from debuggerd32 socket: %s", strerror(errno));
close(sock_fd);
return;
}
char buffer[1024];
ssize_t bytes_read;
while ((bytes_read = TEMP_FAILURE_RETRY(read(sock_fd, buffer, sizeof(buffer)))) > 0) {
ssize_t bytes_to_send = bytes_read;
ssize_t bytes_written;
do {
bytes_written = TEMP_FAILURE_RETRY(write(fd, buffer + bytes_read - bytes_to_send,
bytes_to_send));
if (bytes_written == -1) {
if (errno == EAGAIN) {
// Retry the write.
continue;
}
ALOGE("Error while writing data to fd: %s", strerror(errno));
break;
}
bytes_to_send -= bytes_written;
} while (bytes_written != 0 && bytes_to_send > 0);
if (bytes_to_send != 0) {
ALOGE("Failed to write all data to fd: read %zd, sent %zd", bytes_read, bytes_to_send);
break;
}
}
close(sock_fd);
}
#endif
// Attach to a thread, and verify that it's still a member of the given process
static bool ptrace_attach_thread(pid_t pid, pid_t tid) {
if (ptrace(PTRACE_ATTACH, tid, 0, 0) != 0) {
return false;
}
// Make sure that the task we attached to is actually part of the pid we're dumping.
if (!pid_contains_tid(pid, tid)) {
if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
ALOGE("debuggerd: failed to detach from thread '%d'", tid);
exit(1);
}
return false;
}
return true;
}
static void ptrace_siblings(pid_t pid, pid_t main_tid, std::set<pid_t>& tids) {
char task_path[PATH_MAX];
if (snprintf(task_path, PATH_MAX, "/proc/%d/task", pid) >= PATH_MAX) {
ALOGE("debuggerd: task path overflow (pid = %d)\n", pid);
abort();
}
std::unique_ptr<DIR, int (*)(DIR*)> d(opendir(task_path), closedir);
// Bail early if the task directory cannot be opened.
if (!d) {
ALOGE("debuggerd: failed to open /proc/%d/task: %s", pid, strerror(errno));
return;
}
struct dirent* de;
while ((de = readdir(d.get())) != NULL) {
// Ignore "." and "..".
if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
continue;
}
char* end;
pid_t tid = strtoul(de->d_name, &end, 10);
if (*end) {
continue;
}
if (tid == main_tid) {
continue;
}
if (!ptrace_attach_thread(pid, tid)) {
ALOGE("debuggerd: ptrace attach to %d failed: %s", tid, strerror(errno));
continue;
}
tids.insert(tid);
}
}
static bool perform_dump(const debugger_request_t& request, int fd, int tombstone_fd,
BacktraceMap* backtrace_map, const std::set<pid_t>& siblings,
int* crash_signal, std::string* amfd_data) {
if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
ALOGE("debuggerd: failed to respond to client: %s\n", strerror(errno));
return false;
}
int total_sleep_time_usec = 0;
while (true) {
int signal = wait_for_signal(request.tid, &total_sleep_time_usec);
switch (signal) {
case -1:
ALOGE("debuggerd: timed out waiting for signal");
return false;
case SIGSTOP:
if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
ALOGV("debuggerd: stopped -- dumping to tombstone");
engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal,
request.original_si_code, request.abort_msg_address, amfd_data);
} else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
ALOGV("debuggerd: stopped -- dumping to fd");
dump_backtrace(fd, backtrace_map, request.pid, request.tid, siblings, nullptr);
} else {
ALOGV("debuggerd: stopped -- continuing");
if (ptrace(PTRACE_CONT, request.tid, 0, 0) != 0) {
ALOGE("debuggerd: ptrace continue failed: %s", strerror(errno));
return false;
}
continue; // loop again
}
break;
case SIGABRT:
case SIGBUS:
case SIGFPE:
case SIGILL:
case SIGSEGV:
#ifdef SIGSTKFLT
case SIGSTKFLT:
#endif
case SIGSYS:
case SIGTRAP:
ALOGV("stopped -- fatal signal\n");
*crash_signal = signal;
engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal,
request.original_si_code, request.abort_msg_address, amfd_data);
break;
default:
ALOGE("debuggerd: process stopped due to unexpected signal %d\n", signal);
break;
}
break;
}
return true;
}
static bool drop_privileges() {
// AID_LOG: for reading the logs data associated with the crashing process.
// AID_READPROC: for reading /proc/<PID>/{comm,cmdline}.
gid_t groups[] = { AID_DEBUGGERD, AID_LOG, AID_READPROC };
if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) {
ALOGE("debuggerd: failed to setgroups: %s", strerror(errno));
return false;
}
if (setresgid(AID_DEBUGGERD, AID_DEBUGGERD, AID_DEBUGGERD) != 0) {
ALOGE("debuggerd: failed to setresgid: %s", strerror(errno));
return false;
}
if (setresuid(AID_DEBUGGERD, AID_DEBUGGERD, AID_DEBUGGERD) != 0) {
ALOGE("debuggerd: failed to setresuid: %s", strerror(errno));
return false;
}
return true;
}
static void worker_process(int fd, debugger_request_t& request) {
// Open the tombstone file if we need it.
std::string tombstone_path;
int tombstone_fd = -1;
switch (request.action) {
case DEBUGGER_ACTION_DUMP_TOMBSTONE:
case DEBUGGER_ACTION_CRASH:
tombstone_fd = open_tombstone(&tombstone_path);
if (tombstone_fd == -1) {
ALOGE("debuggerd: failed to open tombstone file: %s\n", strerror(errno));
exit(1);
}
break;
case DEBUGGER_ACTION_DUMP_BACKTRACE:
break;
default:
ALOGE("debuggerd: unexpected request action: %d", request.action);
exit(1);
}
// At this point, the thread that made the request is blocked in
// a read() call. If the thread has crashed, then this gives us
// time to PTRACE_ATTACH to it before it has a chance to really fault.
//
// The PTRACE_ATTACH sends a SIGSTOP to the target process, but it
// won't necessarily have stopped by the time ptrace() returns. (We
// currently assume it does.) We write to the file descriptor to
// ensure that it can run as soon as we call PTRACE_CONT below.
// See details in bionic/libc/linker/debugger.c, in function
// debugger_signal_handler().
// Attach to the target process.
if (!ptrace_attach_thread(request.pid, request.tid)) {
ALOGE("debuggerd: ptrace attach failed: %s", strerror(errno));
exit(1);
}
// DEBUGGER_ACTION_CRASH requests can come from arbitrary processes and the tid field in the
// request is sent from the other side. If an attacker can cause a process to be spawned with the
// pid of their process, they could trick debuggerd into dumping that process by exiting after
// sending the request. Validate the trusted request.uid/gid to defend against this.
if (request.action == DEBUGGER_ACTION_CRASH) {
pid_t pid;
uid_t uid;
gid_t gid;
if (get_process_info(request.tid, &pid, &uid, &gid) != 0) {
ALOGE("debuggerd: failed to get process info for tid '%d'", request.tid);
exit(1);
}
if (pid != request.pid || uid != request.uid || gid != request.gid) {
ALOGE(
"debuggerd: attached task %d does not match request: "
"expected pid=%d,uid=%d,gid=%d, actual pid=%d,uid=%d,gid=%d",
request.tid, request.pid, request.uid, request.gid, pid, uid, gid);
exit(1);
}
}
// Don't attach to the sibling threads if we want to attach gdb.
// Supposedly, it makes the process less reliable.
bool attach_gdb = should_attach_gdb(request);
if (attach_gdb) {
// Open all of the input devices we need to listen for VOLUMEDOWN before dropping privileges.
if (init_getevent() != 0) {
ALOGE("debuggerd: failed to initialize input device, not waiting for gdb");
attach_gdb = false;
}
}
std::set<pid_t> siblings;
if (!attach_gdb) {
ptrace_siblings(request.pid, request.tid, siblings);
}
// Generate the backtrace map before dropping privileges.
std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));
int amfd = -1;
std::unique_ptr<std::string> amfd_data;
if (request.action == DEBUGGER_ACTION_CRASH) {
// Connect to the activity manager before dropping privileges.
amfd = activity_manager_connect();
amfd_data.reset(new std::string);
}
bool succeeded = false;
// Now that we've done everything that requires privileges, we can drop them.
if (!drop_privileges()) {
ALOGE("debuggerd: failed to drop privileges, exiting");
_exit(1);
}
int crash_signal = SIGKILL;
succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings,
&crash_signal, amfd_data.get());
if (succeeded) {
if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
if (!tombstone_path.empty()) {
android::base::WriteFully(fd, tombstone_path.c_str(), tombstone_path.length());
}
}
}
if (attach_gdb) {
// Tell the signal process to send SIGSTOP to the target.
if (!send_signal(request.pid, 0, SIGSTOP)) {
ALOGE("debuggerd: failed to stop process for gdb attach: %s", strerror(errno));
attach_gdb = false;
}
}
if (!attach_gdb) {
// Tell the Activity Manager about the crashing process. If we are
// waiting for gdb to attach, do not send this or Activity Manager
// might kill the process before anyone can attach.
activity_manager_write(request.pid, crash_signal, amfd, *amfd_data.get());
}
if (ptrace(PTRACE_DETACH, request.tid, 0, 0) != 0) {
ALOGE("debuggerd: ptrace detach from %d failed: %s", request.tid, strerror(errno));
}
for (pid_t sibling : siblings) {
ptrace(PTRACE_DETACH, sibling, 0, 0);
}
// Send the signal back to the process if it crashed and we're not waiting for gdb.
if (!attach_gdb && request.action == DEBUGGER_ACTION_CRASH) {
if (!send_signal(request.pid, request.tid, crash_signal)) {
ALOGE("debuggerd: failed to kill process %d: %s", request.pid, strerror(errno));
}
}
// Wait for gdb, if requested.
if (attach_gdb) {
wait_for_user_action(request);
// Now tell the activity manager about this process.
activity_manager_write(request.pid, crash_signal, amfd, *amfd_data.get());
// Tell the signal process to send SIGCONT to the target.
if (!send_signal(request.pid, 0, SIGCONT)) {
ALOGE("debuggerd: failed to resume process %d: %s", request.pid, strerror(errno));
}
uninit_getevent();
}
close(amfd);
exit(!succeeded);
}
static void monitor_worker_process(int child_pid, const debugger_request_t& request) {
struct timespec timeout = {.tv_sec = 10, .tv_nsec = 0 };
if (should_attach_gdb(request)) {
// If wait_for_gdb is enabled, set the timeout to something large.
timeout.tv_sec = INT_MAX;
}
sigset_t signal_set;
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGCHLD);
bool kill_worker = false;
bool kill_target = false;
bool kill_self = false;
int status;
siginfo_t siginfo;
int signal = TEMP_FAILURE_RETRY(sigtimedwait(&signal_set, &siginfo, &timeout));
if (signal == SIGCHLD) {
pid_t rc = waitpid(-1, &status, WNOHANG | WUNTRACED);
if (rc != child_pid) {
ALOGE("debuggerd: waitpid returned unexpected pid (%d), committing murder-suicide", rc);
if (WIFEXITED(status)) {
ALOGW("debuggerd: pid %d exited with status %d", rc, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
ALOGW("debuggerd: pid %d received signal %d", rc, WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
ALOGW("debuggerd: pid %d stopped by signal %d", rc, WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
ALOGW("debuggerd: pid %d continued", rc);
}
kill_worker = true;
kill_target = true;
kill_self = true;
} else if (WIFSIGNALED(status)) {
ALOGE("debuggerd: worker process %d terminated due to signal %d", child_pid, WTERMSIG(status));
kill_worker = false;
kill_target = true;
} else if (WIFSTOPPED(status)) {
ALOGE("debuggerd: worker process %d stopped due to signal %d", child_pid, WSTOPSIG(status));
kill_worker = true;
kill_target = true;
}
} else {
ALOGE("debuggerd: worker process %d timed out", child_pid);
kill_worker = true;
kill_target = true;
}
if (kill_worker) {
// Something bad happened, kill the worker.
if (kill(child_pid, SIGKILL) != 0) {
ALOGE("debuggerd: failed to kill worker process %d: %s", child_pid, strerror(errno));
} else {
waitpid(child_pid, &status, 0);
}
}
int exit_signal = SIGCONT;
if (kill_target && request.action == DEBUGGER_ACTION_CRASH) {
ALOGE("debuggerd: killing target %d", request.pid);
exit_signal = SIGKILL;
} else {
ALOGW("debuggerd: resuming target %d", request.pid);
}
if (kill(request.pid, exit_signal) != 0) {
ALOGE("debuggerd: failed to send signal %d to target: %s", exit_signal, strerror(errno));
}
if (kill_self) {
stop_signal_sender();
_exit(1);
}
}
static void handle_request(int fd) {
ALOGV("handle_request(%d)\n", fd);
ScopedFd closer(fd);
debugger_request_t request;
memset(&request, 0, sizeof(request));
int status = read_request(fd, &request);
if (status != 0) {
return;
}
ALOGW("debuggerd: handling request: pid=%d uid=%d gid=%d tid=%d\n", request.pid, request.uid,
request.gid, request.tid);
#if defined(__LP64__)
// On 64 bit systems, requests to dump 32 bit and 64 bit tids come
// to the 64 bit debuggerd. If the process is a 32 bit executable,
// redirect the request to the 32 bit debuggerd.
if (is32bit(request.tid)) {
// Only dump backtrace and dump tombstone requests can be redirected.
if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE ||
request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
redirect_to_32(fd, &request);
} else {
ALOGE("debuggerd: Not allowed to redirect action %d to 32 bit debuggerd\n", request.action);
}
return;
}
#endif
// Fork a child to handle the rest of the request.
pid_t fork_pid = fork();
if (fork_pid == -1) {
ALOGE("debuggerd: failed to fork: %s\n", strerror(errno));
} else if (fork_pid == 0) {
worker_process(fd, request);
} else {
monitor_worker_process(fork_pid, request);
}
}
static int do_server() {
// debuggerd crashes can't be reported to debuggerd.
// Reset all of the crash handlers.
signal(SIGABRT, SIG_DFL);
signal(SIGBUS, SIG_DFL);
signal(SIGFPE, SIG_DFL);
signal(SIGILL, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
#ifdef SIGSTKFLT
signal(SIGSTKFLT, SIG_DFL);
#endif
signal(SIGTRAP, SIG_DFL);
// Ignore failed writes to closed sockets
signal(SIGPIPE, SIG_IGN);
// Block SIGCHLD so we can sigtimedwait for it.
sigset_t sigchld;
sigemptyset(&sigchld);
sigaddset(&sigchld, SIGCHLD);
sigprocmask(SIG_SETMASK, &sigchld, nullptr);
int s = socket_local_server(SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
SOCK_STREAM | SOCK_CLOEXEC);
if (s == -1) return 1;
// Fork a process that stays root, and listens on a pipe to pause and resume the target.
if (!start_signal_sender()) {
ALOGE("debuggerd: failed to fork signal sender");
return 1;
}
ALOGI("debuggerd: starting\n");
for (;;) {
sockaddr_storage ss;
sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
socklen_t alen = sizeof(ss);
ALOGV("waiting for connection\n");
int fd = accept4(s, addrp, &alen, SOCK_CLOEXEC);
if (fd == -1) {
ALOGE("accept failed: %s\n", strerror(errno));
continue;
}
handle_request(fd);
}
return 0;
}
static int do_explicit_dump(pid_t tid, bool dump_backtrace) {
fprintf(stdout, "Sending request to dump task %d.\n", tid);
if (dump_backtrace) {
fflush(stdout);
if (dump_backtrace_to_file(tid, fileno(stdout)) < 0) {
fputs("Error dumping backtrace.\n", stderr);
return 1;
}
} else {
char tombstone_path[PATH_MAX];
if (dump_tombstone(tid, tombstone_path, sizeof(tombstone_path)) < 0) {
fputs("Error dumping tombstone.\n", stderr);
return 1;
}
fprintf(stderr, "Tombstone written to: %s\n", tombstone_path);
}
return 0;
}
static void usage() {
fputs("Usage: -b [<tid>]\n"
" -b dump backtrace to console, otherwise dump full tombstone file\n"
"\n"
"If tid specified, sends a request to debuggerd to dump that task.\n"
"Otherwise, starts the debuggerd server.\n", stderr);
}
int main(int argc, char** argv) {
union selinux_callback cb;
if (argc == 1) {
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
cb.func_log = selinux_log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
return do_server();
}
bool dump_backtrace = false;
bool have_tid = false;
pid_t tid = 0;
for (int i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-b")) {
dump_backtrace = true;
} else if (!have_tid) {
tid = atoi(argv[i]);
have_tid = true;
} else {
usage();
return 1;
}
}
if (!have_tid) {
usage();
return 1;
}
return do_explicit_dump(tid, dump_backtrace);
}

View File

@@ -1,3 +0,0 @@
service debuggerd /system/bin/debuggerd
group root readproc
writepid /dev/cpuset/system-background/tasks

View File

@@ -1,3 +0,0 @@
service debuggerd64 /system/bin/debuggerd64
group root readproc
writepid /dev/cpuset/system-background/tasks

View File

@@ -1,121 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "DEBUG"
#include <elf.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <backtrace/Backtrace.h>
#include <android-base/stringprintf.h>
#include <log/log.h>
#include "elf_utils.h"
#define NOTE_ALIGN(size) ((size + 3) & ~3)
template <typename HdrType, typename PhdrType, typename NhdrType>
static bool get_build_id(
Backtrace* backtrace, uintptr_t base_addr, uint8_t* e_ident, std::string* build_id) {
HdrType hdr;
memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT);
// First read the rest of the header.
if (backtrace->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT,
sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) {
return false;
}
for (size_t i = 0; i < hdr.e_phnum; i++) {
PhdrType phdr;
if (backtrace->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize,
reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) {
return false;
}
// Looking for the .note.gnu.build-id note.
if (phdr.p_type == PT_NOTE) {
size_t hdr_size = phdr.p_filesz;
uintptr_t addr = base_addr + phdr.p_offset;
while (hdr_size >= sizeof(NhdrType)) {
NhdrType nhdr;
if (backtrace->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) {
return false;
}
addr += sizeof(nhdr);
if (nhdr.n_type == NT_GNU_BUILD_ID) {
// Skip the name (which is the owner and should be "GNU").
addr += NOTE_ALIGN(nhdr.n_namesz);
uint8_t build_id_data[160];
if (nhdr.n_descsz > sizeof(build_id_data)) {
ALOGE("Possible corrupted note, desc size value is too large: %u",
nhdr.n_descsz);
return false;
}
if (backtrace->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) {
return false;
}
build_id->clear();
for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) {
*build_id += android::base::StringPrintf("%02x", build_id_data[bytes]);
}
return true;
} else {
// Move past the extra note data.
hdr_size -= sizeof(nhdr);
size_t skip_bytes = NOTE_ALIGN(nhdr.n_namesz) + NOTE_ALIGN(nhdr.n_descsz);
addr += skip_bytes;
if (hdr_size < skip_bytes) {
break;
}
hdr_size -= skip_bytes;
}
}
}
}
return false;
}
bool elf_get_build_id(Backtrace* backtrace, uintptr_t addr, std::string* build_id) {
// Read and verify the elf magic number first.
uint8_t e_ident[EI_NIDENT];
if (backtrace->Read(addr, e_ident, SELFMAG) != SELFMAG) {
return false;
}
if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
return false;
}
// Read the rest of EI_NIDENT.
if (backtrace->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) {
return false;
}
if (e_ident[EI_CLASS] == ELFCLASS32) {
return get_build_id<Elf32_Ehdr, Elf32_Phdr, Elf32_Nhdr>(backtrace, addr, e_ident, build_id);
} else if (e_ident[EI_CLASS] == ELFCLASS64) {
return get_build_id<Elf64_Ehdr, Elf64_Phdr, Elf64_Nhdr>(backtrace, addr, e_ident, build_id);
}
return false;
}

View File

@@ -1,27 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DEBUGGERD_ELF_UTILS_H
#define _DEBUGGERD_ELF_UTILS_H
#include <stdint.h>
#include <string>
class Backtrace;
bool elf_get_build_id(Backtrace*, uintptr_t, std::string*);
#endif // _DEBUGGERD_ELF_UTILS_H

View File

@@ -1,222 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <dirent.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/inotify.h>
#include <sys/limits.h>
#include <sys/poll.h>
#include <linux/input.h>
#include <errno.h>
#include <cutils/log.h>
static struct pollfd* ufds;
static char** device_names;
static int nfds;
static int open_device(const char* device) {
int version;
int fd;
struct pollfd* new_ufds;
char** new_device_names;
char name[80];
char location[80];
char idstr[80];
struct input_id id;
fd = open(device, O_RDWR);
if (fd < 0) {
return -1;
}
if (ioctl(fd, EVIOCGVERSION, &version)) {
return -1;
}
if (ioctl(fd, EVIOCGID, &id)) {
return -1;
}
name[sizeof(name) - 1] = '\0';
location[sizeof(location) - 1] = '\0';
idstr[sizeof(idstr) - 1] = '\0';
if (ioctl(fd, EVIOCGNAME(sizeof(name) - 1), &name) < 1) {
name[0] = '\0';
}
if (ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) {
location[0] = '\0';
}
if (ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) {
idstr[0] = '\0';
}
new_ufds = reinterpret_cast<pollfd*>(realloc(ufds, sizeof(ufds[0]) * (nfds + 1)));
if (new_ufds == NULL) {
fprintf(stderr, "out of memory\n");
return -1;
}
ufds = new_ufds;
new_device_names = reinterpret_cast<char**>(realloc(
device_names, sizeof(device_names[0]) * (nfds + 1)));
if (new_device_names == NULL) {
fprintf(stderr, "out of memory\n");
return -1;
}
device_names = new_device_names;
ufds[nfds].fd = fd;
ufds[nfds].events = POLLIN;
device_names[nfds] = strdup(device);
nfds++;
return 0;
}
int close_device(const char* device) {
int i;
for (i = 1; i < nfds; i++) {
if (strcmp(device_names[i], device) == 0) {
int count = nfds - i - 1;
free(device_names[i]);
memmove(device_names + i, device_names + i + 1, sizeof(device_names[0]) * count);
memmove(ufds + i, ufds + i + 1, sizeof(ufds[0]) * count);
nfds--;
return 0;
}
}
return -1;
}
static int read_notify(const char* dirname, int nfd) {
int res;
char devname[PATH_MAX];
char* filename;
char event_buf[512];
int event_size;
int event_pos = 0;
struct inotify_event *event;
res = read(nfd, event_buf, sizeof(event_buf));
if (res < (int)sizeof(*event)) {
if (errno == EINTR)
return 0;
fprintf(stderr, "could not get event, %s\n", strerror(errno));
return 1;
}
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
while (res >= (int)sizeof(*event)) {
event = reinterpret_cast<struct inotify_event*>(event_buf + event_pos);
if (event->len) {
strcpy(filename, event->name);
if (event->mask & IN_CREATE) {
open_device(devname);
} else {
close_device(devname);
}
}
event_size = sizeof(*event) + event->len;
res -= event_size;
event_pos += event_size;
}
return 0;
}
static int scan_dir(const char* dirname) {
char devname[PATH_MAX];
char* filename;
DIR* dir;
struct dirent* de;
dir = opendir(dirname);
if (dir == NULL)
return -1;
strcpy(devname, dirname);
filename = devname + strlen(devname);
*filename++ = '/';
while ((de = readdir(dir))) {
if ((de->d_name[0] == '.' && de->d_name[1] == '\0') ||
(de->d_name[1] == '.' && de->d_name[2] == '\0'))
continue;
strcpy(filename, de->d_name);
open_device(devname);
}
closedir(dir);
return 0;
}
int init_getevent() {
int res;
const char* device_path = "/dev/input";
nfds = 1;
ufds = reinterpret_cast<pollfd*>(calloc(1, sizeof(ufds[0])));
ufds[0].fd = inotify_init();
ufds[0].events = POLLIN;
res = inotify_add_watch(ufds[0].fd, device_path, IN_DELETE | IN_CREATE);
if (res < 0) {
return 1;
}
res = scan_dir(device_path);
if (res < 0) {
return 1;
}
return 0;
}
void uninit_getevent() {
int i;
for (i = 0; i < nfds; i++) {
close(ufds[i].fd);
}
free(ufds);
ufds = 0;
nfds = 0;
}
int get_event(struct input_event* event, int timeout) {
int res;
int i;
int pollres;
const char* device_path = "/dev/input";
while (1) {
pollres = poll(ufds, nfds, timeout);
if (pollres == 0) {
return 1;
}
if (ufds[0].revents & POLLIN) {
read_notify(device_path, ufds[0].fd);
}
for (i = 1; i < nfds; i++) {
if (ufds[i].revents) {
if (ufds[i].revents & POLLIN) {
res = read(ufds[i].fd, event, sizeof(*event));
if (res < static_cast<int>(sizeof(event))) {
fprintf(stderr, "could not get event\n");
return -1;
}
return 0;
}
}
}
}
return 0;
}

View File

@@ -1,24 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DEBUGGERD_GETEVENT_H
#define _DEBUGGERD_GETEVENT_H
int init_getevent();
void uninit_getevent();
int get_event(struct input_event* event, int timeout);
#endif // _DEBUGGERD_GETEVENT_H

View File

@@ -1,29 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DEBUGGERD_MACHINE_H
#define _DEBUGGERD_MACHINE_H
#include <sys/types.h>
#include <backtrace/Backtrace.h>
#include "utility.h"
void dump_memory_and_code(log_t* log, Backtrace* backtrace);
void dump_registers(log_t* log, pid_t tid);
#endif // _DEBUGGERD_MACHINE_H

View File

@@ -1,45 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <string>
#include <unordered_map>
#include "sys/system_properties.h"
std::unordered_map<std::string, std::string> g_properties;
extern "C" int property_set(const char* name, const char* value) {
if (g_properties.count(name) != 0) {
g_properties.erase(name);
}
g_properties[name] = value;
return 0;
}
extern "C" int property_get(const char* key, char* value, const char* default_value) {
if (g_properties.count(key) == 0) {
if (default_value == nullptr) {
return 0;
}
strncpy(value, default_value, PROP_VALUE_MAX-1);
} else {
strncpy(value, g_properties[key].c_str(), PROP_VALUE_MAX-1);
}
value[PROP_VALUE_MAX-1] = '\0';
return strlen(value);
}

View File

@@ -1,17 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
extern "C" int selinux_android_restorecon(const char*, unsigned int);

View File

@@ -1,19 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
extern "C" int selinux_android_restorecon(const char*, unsigned int) {
return 0;
}

View File

@@ -1,180 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <log/logger.h>
#include "signal_sender.h"
static int signal_fd = -1;
static pid_t signal_pid;
struct signal_message {
pid_t pid;
pid_t tid;
int signal;
};
static void set_signal_sender_process_name() {
#if defined(__LP64__)
static constexpr char long_process_name[] = "debuggerd64:signaller";
static constexpr char short_process_name[] = "debuggerd64:sig";
static_assert(sizeof(long_process_name) <= sizeof("/system/bin/debuggerd64"), "");
#else
static constexpr char long_process_name[] = "debuggerd:signaller";
static constexpr char short_process_name[] = "debuggerd:sig";
static_assert(sizeof(long_process_name) <= sizeof("/system/bin/debuggerd"), "");
#endif
// pthread_setname_np has a maximum length of 16 chars, including null terminator.
static_assert(sizeof(short_process_name) <= 16, "");
pthread_setname_np(pthread_self(), short_process_name);
char* progname = const_cast<char*>(getprogname());
if (strlen(progname) <= strlen(long_process_name)) {
ALOGE("debuggerd: unexpected progname %s", progname);
return;
}
memset(progname, 0, strlen(progname));
strcpy(progname, long_process_name);
}
// Fork a process to send signals for the worker processes to use after they've dropped privileges.
bool start_signal_sender() {
if (signal_pid != 0) {
ALOGE("debuggerd: attempted to start signal sender multiple times");
return false;
}
int sfd[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sfd) != 0) {
ALOGE("debuggerd: failed to create socketpair for signal sender: %s", strerror(errno));
return false;
}
pid_t parent = getpid();
pid_t fork_pid = fork();
if (fork_pid == -1) {
ALOGE("debuggerd: failed to initialize signal sender: fork failed: %s", strerror(errno));
return false;
} else if (fork_pid == 0) {
close(sfd[1]);
set_signal_sender_process_name();
while (true) {
signal_message msg;
int rc = TEMP_FAILURE_RETRY(read(sfd[0], &msg, sizeof(msg)));
if (rc < 0) {
ALOGE("debuggerd: signal sender failed to read from socket");
break;
} else if (rc != sizeof(msg)) {
ALOGE("debuggerd: signal sender read unexpected number of bytes: %d", rc);
break;
}
// Report success after sending a signal
int err = 0;
if (msg.tid > 0) {
if (syscall(SYS_tgkill, msg.pid, msg.tid, msg.signal) != 0) {
err = errno;
}
} else {
if (kill(msg.pid, msg.signal) != 0) {
err = errno;
}
}
if (TEMP_FAILURE_RETRY(write(sfd[0], &err, sizeof(err))) < 0) {
ALOGE("debuggerd: signal sender failed to write: %s", strerror(errno));
}
}
// Our parent proably died, but if not, kill them.
if (getppid() == parent) {
kill(parent, SIGKILL);
}
_exit(1);
} else {
close(sfd[0]);
signal_fd = sfd[1];
signal_pid = fork_pid;
return true;
}
}
bool stop_signal_sender() {
if (signal_pid <= 0) {
return false;
}
if (kill(signal_pid, SIGKILL) != 0) {
ALOGE("debuggerd: failed to kill signal sender: %s", strerror(errno));
return false;
}
close(signal_fd);
signal_fd = -1;
int status;
waitpid(signal_pid, &status, 0);
signal_pid = 0;
return true;
}
bool send_signal(pid_t pid, pid_t tid, int signal) {
if (signal_fd == -1) {
ALOGE("debuggerd: attempted to send signal before signal sender was started");
errno = EHOSTUNREACH;
return false;
}
signal_message msg = {.pid = pid, .tid = tid, .signal = signal };
if (TEMP_FAILURE_RETRY(write(signal_fd, &msg, sizeof(msg))) < 0) {
ALOGE("debuggerd: failed to send message to signal sender: %s", strerror(errno));
errno = EHOSTUNREACH;
return false;
}
int response;
ssize_t rc = TEMP_FAILURE_RETRY(read(signal_fd, &response, sizeof(response)));
if (rc == 0) {
ALOGE("debuggerd: received EOF from signal sender");
errno = EHOSTUNREACH;
return false;
} else if (rc < 0) {
ALOGE("debuggerd: failed to receive response from signal sender: %s", strerror(errno));
errno = EHOSTUNREACH;
return false;
}
if (response == 0) {
return true;
}
errno = response;
return false;
}

View File

@@ -1,30 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DEBUGGERD_SIGNAL_SENDER_H
#define _DEBUGGERD_SIGNAL_SENDER_H
#include <sys/types.h>
bool start_signal_sender();
bool stop_signal_sender();
// Sends a signal to a target process or thread.
// If tid is greater than zero, this performs tgkill(pid, tid, signal).
// Otherwise, it performs kill(pid, signal).
bool send_signal(pid_t pid, pid_t tid, int signal);
#endif

View File

@@ -1,38 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (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 _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
#define _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H
// This is just enough to get the property code to compile on
// the host.
#define PROP_NAME_MAX 32
#define PROP_VALUE_MAX 92
#endif // _DEBUGGERD_TEST_SYS_SYSTEM_PROPERTIES_H

View File

@@ -1,702 +0,0 @@
/*
* Copyright (C) 2012-2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "DEBUG"
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/ptrace.h>
#include <sys/stat.h>
#include <memory>
#include <string>
#include <private/android_filesystem_config.h>
#include <android-base/stringprintf.h>
#include <cutils/properties.h>
#include <log/log.h>
#include <log/logger.h>
#include <log/logprint.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include <selinux/android.h>
#include "backtrace.h"
#include "elf_utils.h"
#include "machine.h"
#include "tombstone.h"
#define STACK_WORDS 16
#define MAX_TOMBSTONES 10
#define TOMBSTONE_DIR "/data/tombstones"
#define TOMBSTONE_TEMPLATE (TOMBSTONE_DIR"/tombstone_%02d")
static bool signal_has_si_addr(int sig) {
switch (sig) {
case SIGBUS:
case SIGFPE:
case SIGILL:
case SIGSEGV:
case SIGTRAP:
return true;
default:
return false;
}
}
static const char* get_signame(int sig) {
switch(sig) {
case SIGABRT: return "SIGABRT";
case SIGBUS: return "SIGBUS";
case SIGFPE: return "SIGFPE";
case SIGILL: return "SIGILL";
case SIGSEGV: return "SIGSEGV";
#if defined(SIGSTKFLT)
case SIGSTKFLT: return "SIGSTKFLT";
#endif
case SIGSTOP: return "SIGSTOP";
case SIGTRAP: return "SIGTRAP";
default: return "?";
}
}
static const char* get_sigcode(int signo, int code) {
// Try the signal-specific codes...
switch (signo) {
case SIGILL:
switch (code) {
case ILL_ILLOPC: return "ILL_ILLOPC";
case ILL_ILLOPN: return "ILL_ILLOPN";
case ILL_ILLADR: return "ILL_ILLADR";
case ILL_ILLTRP: return "ILL_ILLTRP";
case ILL_PRVOPC: return "ILL_PRVOPC";
case ILL_PRVREG: return "ILL_PRVREG";
case ILL_COPROC: return "ILL_COPROC";
case ILL_BADSTK: return "ILL_BADSTK";
}
static_assert(NSIGILL == ILL_BADSTK, "missing ILL_* si_code");
break;
case SIGBUS:
switch (code) {
case BUS_ADRALN: return "BUS_ADRALN";
case BUS_ADRERR: return "BUS_ADRERR";
case BUS_OBJERR: return "BUS_OBJERR";
case BUS_MCEERR_AR: return "BUS_MCEERR_AR";
case BUS_MCEERR_AO: return "BUS_MCEERR_AO";
}
static_assert(NSIGBUS == BUS_MCEERR_AO, "missing BUS_* si_code");
break;
case SIGFPE:
switch (code) {
case FPE_INTDIV: return "FPE_INTDIV";
case FPE_INTOVF: return "FPE_INTOVF";
case FPE_FLTDIV: return "FPE_FLTDIV";
case FPE_FLTOVF: return "FPE_FLTOVF";
case FPE_FLTUND: return "FPE_FLTUND";
case FPE_FLTRES: return "FPE_FLTRES";
case FPE_FLTINV: return "FPE_FLTINV";
case FPE_FLTSUB: return "FPE_FLTSUB";
}
static_assert(NSIGFPE == FPE_FLTSUB, "missing FPE_* si_code");
break;
case SIGSEGV:
switch (code) {
case SEGV_MAPERR: return "SEGV_MAPERR";
case SEGV_ACCERR: return "SEGV_ACCERR";
#if defined(SEGV_BNDERR)
case SEGV_BNDERR: return "SEGV_BNDERR";
#endif
}
#if defined(SEGV_BNDERR)
static_assert(NSIGSEGV == SEGV_BNDERR, "missing SEGV_* si_code");
#else
static_assert(NSIGSEGV == SEGV_ACCERR, "missing SEGV_* si_code");
#endif
break;
case SIGTRAP:
switch (code) {
case TRAP_BRKPT: return "TRAP_BRKPT";
case TRAP_TRACE: return "TRAP_TRACE";
case TRAP_BRANCH: return "TRAP_BRANCH";
case TRAP_HWBKPT: return "TRAP_HWBKPT";
}
static_assert(NSIGTRAP == TRAP_HWBKPT, "missing TRAP_* si_code");
break;
}
// Then the other codes...
switch (code) {
case SI_USER: return "SI_USER";
case SI_KERNEL: return "SI_KERNEL";
case SI_QUEUE: return "SI_QUEUE";
case SI_TIMER: return "SI_TIMER";
case SI_MESGQ: return "SI_MESGQ";
case SI_ASYNCIO: return "SI_ASYNCIO";
case SI_SIGIO: return "SI_SIGIO";
case SI_TKILL: return "SI_TKILL";
case SI_DETHREAD: return "SI_DETHREAD";
}
// Then give up...
return "?";
}
static void dump_header_info(log_t* log) {
char fingerprint[PROPERTY_VALUE_MAX];
char revision[PROPERTY_VALUE_MAX];
property_get("ro.build.fingerprint", fingerprint, "unknown");
property_get("ro.revision", revision, "unknown");
_LOG(log, logtype::HEADER, "Build fingerprint: '%s'\n", fingerprint);
_LOG(log, logtype::HEADER, "Revision: '%s'\n", revision);
_LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING);
}
static void dump_signal_info(log_t* log, pid_t tid, int signal, int si_code) {
siginfo_t si;
memset(&si, 0, sizeof(si));
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) == -1) {
ALOGE("cannot get siginfo: %s\n", strerror(errno));
return;
}
// bionic has to re-raise some signals, which overwrites the si_code with SI_TKILL.
si.si_code = si_code;
char addr_desc[32]; // ", fault addr 0x1234"
if (signal_has_si_addr(signal)) {
snprintf(addr_desc, sizeof(addr_desc), "%p", si.si_addr);
} else {
snprintf(addr_desc, sizeof(addr_desc), "--------");
}
_LOG(log, logtype::HEADER, "signal %d (%s), code %d (%s), fault addr %s\n",
signal, get_signame(signal), si.si_code, get_sigcode(signal, si.si_code), addr_desc);
}
static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {
char path[64];
char threadnamebuf[1024];
char* threadname = nullptr;
FILE *fp;
snprintf(path, sizeof(path), "/proc/%d/comm", tid);
if ((fp = fopen(path, "r"))) {
threadname = fgets(threadnamebuf, sizeof(threadnamebuf), fp);
fclose(fp);
if (threadname) {
size_t len = strlen(threadname);
if (len && threadname[len - 1] == '\n') {
threadname[len - 1] = '\0';
}
}
}
// Blacklist logd, logd.reader, logd.writer, logd.auditd, logd.control ...
static const char logd[] = "logd";
if (threadname != nullptr && !strncmp(threadname, logd, sizeof(logd) - 1)
&& (!threadname[sizeof(logd) - 1] || (threadname[sizeof(logd) - 1] == '.'))) {
log->should_retrieve_logcat = false;
}
char procnamebuf[1024];
char* procname = nullptr;
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
if ((fp = fopen(path, "r"))) {
procname = fgets(procnamebuf, sizeof(procnamebuf), fp);
fclose(fp);
}
_LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", pid, tid,
threadname ? threadname : "UNKNOWN", procname ? procname : "UNKNOWN");
}
static void dump_stack_segment(
Backtrace* backtrace, log_t* log, uintptr_t* sp, size_t words, int label) {
// Read the data all at once.
word_t stack_data[words];
size_t bytes_read = backtrace->Read(*sp, reinterpret_cast<uint8_t*>(&stack_data[0]), sizeof(word_t) * words);
words = bytes_read / sizeof(word_t);
std::string line;
for (size_t i = 0; i < words; i++) {
line = " ";
if (i == 0 && label >= 0) {
// Print the label once.
line += android::base::StringPrintf("#%02d ", label);
} else {
line += " ";
}
line += android::base::StringPrintf("%" PRIPTR " %" PRIPTR, *sp, stack_data[i]);
backtrace_map_t map;
backtrace->FillInMap(stack_data[i], &map);
if (BacktraceMap::IsValid(map) && !map.name.empty()) {
line += " " + map.name;
uintptr_t offset = 0;
std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset));
if (!func_name.empty()) {
line += " (" + func_name;
if (offset) {
line += android::base::StringPrintf("+%" PRIuPTR, offset);
}
line += ')';
}
}
_LOG(log, logtype::STACK, "%s\n", line.c_str());
*sp += sizeof(word_t);
}
}
static void dump_stack(Backtrace* backtrace, log_t* log) {
size_t first = 0, last;
for (size_t i = 0; i < backtrace->NumFrames(); i++) {
const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
if (frame->sp) {
if (!first) {
first = i+1;
}
last = i;
}
}
if (!first) {
return;
}
first--;
// Dump a few words before the first frame.
word_t sp = backtrace->GetFrame(first)->sp - STACK_WORDS * sizeof(word_t);
dump_stack_segment(backtrace, log, &sp, STACK_WORDS, -1);
// Dump a few words from all successive frames.
// Only log the first 3 frames, put the rest in the tombstone.
for (size_t i = first; i <= last; i++) {
const backtrace_frame_data_t* frame = backtrace->GetFrame(i);
if (sp != frame->sp) {
_LOG(log, logtype::STACK, " ........ ........\n");
sp = frame->sp;
}
if (i == last) {
dump_stack_segment(backtrace, log, &sp, STACK_WORDS, i);
if (sp < frame->sp + frame->stack_size) {
_LOG(log, logtype::STACK, " ........ ........\n");
}
} else {
size_t words = frame->stack_size / sizeof(word_t);
if (words == 0) {
words = 1;
} else if (words > STACK_WORDS) {
words = STACK_WORDS;
}
dump_stack_segment(backtrace, log, &sp, words, i);
}
}
}
static std::string get_addr_string(uintptr_t addr) {
std::string addr_str;
#if defined(__LP64__)
addr_str = android::base::StringPrintf("%08x'%08x",
static_cast<uint32_t>(addr >> 32),
static_cast<uint32_t>(addr & 0xffffffff));
#else
addr_str = android::base::StringPrintf("%08x", addr);
#endif
return addr_str;
}
static void dump_abort_message(Backtrace* backtrace, log_t* log, uintptr_t address) {
if (address == 0) {
return;
}
address += sizeof(size_t); // Skip the buffer length.
char msg[512];
memset(msg, 0, sizeof(msg));
char* p = &msg[0];
while (p < &msg[sizeof(msg)]) {
word_t data;
size_t len = sizeof(word_t);
if (!backtrace->ReadWord(address, &data)) {
break;
}
address += sizeof(word_t);
while (len > 0 && (*p++ = (data >> (sizeof(word_t) - len) * 8) & 0xff) != 0) {
len--;
}
}
msg[sizeof(msg) - 1] = '\0';
_LOG(log, logtype::HEADER, "Abort message: '%s'\n", msg);
}
static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, pid_t tid) {
bool print_fault_address_marker = false;
uintptr_t addr = 0;
siginfo_t si;
memset(&si, 0, sizeof(si));
if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si) != -1) {
print_fault_address_marker = signal_has_si_addr(si.si_signo);
addr = reinterpret_cast<uintptr_t>(si.si_addr);
} else {
ALOGE("Cannot get siginfo for %d: %s\n", tid, strerror(errno));
}
_LOG(log, logtype::MAPS, "\n");
if (!print_fault_address_marker) {
_LOG(log, logtype::MAPS, "memory map:\n");
} else {
_LOG(log, logtype::MAPS, "memory map: (fault address prefixed with --->)\n");
if (map->begin() != map->end() && addr < map->begin()->start) {
_LOG(log, logtype::MAPS, "--->Fault address falls at %s before any mapped regions\n",
get_addr_string(addr).c_str());
print_fault_address_marker = false;
}
}
std::string line;
for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
line = " ";
if (print_fault_address_marker) {
if (addr < it->start) {
_LOG(log, logtype::MAPS, "--->Fault address falls at %s between mapped regions\n",
get_addr_string(addr).c_str());
print_fault_address_marker = false;
} else if (addr >= it->start && addr < it->end) {
line = "--->";
print_fault_address_marker = false;
}
}
line += get_addr_string(it->start) + '-' + get_addr_string(it->end - 1) + ' ';
if (it->flags & PROT_READ) {
line += 'r';
} else {
line += '-';
}
if (it->flags & PROT_WRITE) {
line += 'w';
} else {
line += '-';
}
if (it->flags & PROT_EXEC) {
line += 'x';
} else {
line += '-';
}
line += android::base::StringPrintf(" %8" PRIxPTR " %8" PRIxPTR,
it->offset, it->end - it->start);
bool space_needed = true;
if (it->name.length() > 0) {
space_needed = false;
line += " " + it->name;
std::string build_id;
if ((it->flags & PROT_READ) && elf_get_build_id(backtrace, it->start, &build_id)) {
line += " (BuildId: " + build_id + ")";
}
}
if (it->load_base != 0) {
if (space_needed) {
line += ' ';
}
line += android::base::StringPrintf(" (load base 0x%" PRIxPTR ")", it->load_base);
}
_LOG(log, logtype::MAPS, "%s\n", line.c_str());
}
if (print_fault_address_marker) {
_LOG(log, logtype::MAPS, "--->Fault address falls at %s after any mapped regions\n",
get_addr_string(addr).c_str());
}
}
static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log) {
if (backtrace->NumFrames()) {
_LOG(log, logtype::BACKTRACE, "\nbacktrace:\n");
dump_backtrace_to_log(backtrace, log, " ");
_LOG(log, logtype::STACK, "\nstack:\n");
dump_stack(backtrace, log);
}
}
static void dump_thread(log_t* log, pid_t pid, pid_t tid, BacktraceMap* map, int signal,
int si_code, uintptr_t abort_msg_address, bool primary_thread) {
log->current_tid = tid;
if (!primary_thread) {
_LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
}
dump_thread_info(log, pid, tid);
if (signal) {
dump_signal_info(log, tid, signal, si_code);
}
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
if (primary_thread) {
dump_abort_message(backtrace.get(), log, abort_msg_address);
}
dump_registers(log, tid);
if (backtrace->Unwind(0)) {
dump_backtrace_and_stack(backtrace.get(), log);
} else {
ALOGE("Unwind failed: pid = %d, tid = %d", pid, tid);
}
if (primary_thread) {
dump_memory_and_code(log, backtrace.get());
if (map) {
dump_all_maps(backtrace.get(), map, log, tid);
}
}
log->current_tid = log->crashed_tid;
}
// Reads the contents of the specified log device, filters out the entries
// that don't match the specified pid, and writes them to the tombstone file.
//
// If "tail" is non-zero, log the last "tail" number of lines.
static EventTagMap* g_eventTagMap = NULL;
static void dump_log_file(
log_t* log, pid_t pid, const char* filename, unsigned int tail) {
bool first = true;
struct logger_list* logger_list;
if (!log->should_retrieve_logcat) {
return;
}
logger_list = android_logger_list_open(
android_name_to_log_id(filename), ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, tail, pid);
if (!logger_list) {
ALOGE("Unable to open %s: %s\n", filename, strerror(errno));
return;
}
struct log_msg log_entry;
while (true) {
ssize_t actual = android_logger_list_read(logger_list, &log_entry);
struct logger_entry* entry;
if (actual < 0) {
if (actual == -EINTR) {
// interrupted by signal, retry
continue;
} else if (actual == -EAGAIN) {
// non-blocking EOF; we're done
break;
} else {
ALOGE("Error while reading log: %s\n", strerror(-actual));
break;
}
} else if (actual == 0) {
ALOGE("Got zero bytes while reading log: %s\n", strerror(errno));
break;
}
// NOTE: if you ALOGV something here, this will spin forever,
// because you will be writing as fast as you're reading. Any
// high-frequency debug diagnostics should just be written to
// the tombstone file.
entry = &log_entry.entry_v1;
if (first) {
_LOG(log, logtype::LOGS, "--------- %slog %s\n",
tail ? "tail end of " : "", filename);
first = false;
}
// Msg format is: <priority:1><tag:N>\0<message:N>\0
//
// We want to display it in the same format as "logcat -v threadtime"
// (although in this case the pid is redundant).
static const char* kPrioChars = "!.VDIWEFS";
unsigned hdr_size = log_entry.entry.hdr_size;
if (!hdr_size) {
hdr_size = sizeof(log_entry.entry_v1);
}
char* msg = reinterpret_cast<char*>(log_entry.buf) + hdr_size;
char timeBuf[32];
time_t sec = static_cast<time_t>(entry->sec);
struct tm tmBuf;
struct tm* ptm;
ptm = localtime_r(&sec, &tmBuf);
strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
if (log_entry.id() == LOG_ID_EVENTS) {
if (!g_eventTagMap) {
g_eventTagMap = android_openEventTagMap(EVENT_TAG_MAP_FILE);
}
AndroidLogEntry e;
char buf[512];
android_log_processBinaryLogBuffer(entry, &e, g_eventTagMap, buf, sizeof(buf));
_LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
'I', e.tag, e.message);
continue;
}
unsigned char prio = msg[0];
char* tag = msg + 1;
msg = tag + strlen(tag) + 1;
// consume any trailing newlines
char* nl = msg + strlen(msg) - 1;
while (nl >= msg && *nl == '\n') {
*nl-- = '\0';
}
char prioChar = (prio < strlen(kPrioChars) ? kPrioChars[prio] : '?');
// Look for line breaks ('\n') and display each text line
// on a separate line, prefixed with the header, like logcat does.
do {
nl = strchr(msg, '\n');
if (nl) {
*nl = '\0';
++nl;
}
_LOG(log, logtype::LOGS, "%s.%03d %5d %5d %c %-8s: %s\n",
timeBuf, entry->nsec / 1000000, entry->pid, entry->tid,
prioChar, tag, msg);
} while ((msg = nl));
}
android_logger_list_free(logger_list);
}
// Dumps the logs generated by the specified pid to the tombstone, from both
// "system" and "main" log devices. Ideally we'd interleave the output.
static void dump_logs(log_t* log, pid_t pid, unsigned int tail) {
dump_log_file(log, pid, "system", tail);
dump_log_file(log, pid, "main", tail);
}
// Dumps all information about the specified pid to the tombstone.
static void dump_crash(log_t* log, BacktraceMap* map, pid_t pid, pid_t tid,
const std::set<pid_t>& siblings, int signal, int si_code,
uintptr_t abort_msg_address) {
// don't copy log messages to tombstone unless this is a dev device
char value[PROPERTY_VALUE_MAX];
property_get("ro.debuggable", value, "0");
bool want_logs = (value[0] == '1');
_LOG(log, logtype::HEADER,
"*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n");
dump_header_info(log);
dump_thread(log, pid, tid, map, signal, si_code, abort_msg_address, true);
if (want_logs) {
dump_logs(log, pid, 5);
}
if (!siblings.empty()) {
for (pid_t sibling : siblings) {
dump_thread(log, pid, sibling, map, 0, 0, 0, false);
}
}
if (want_logs) {
dump_logs(log, pid, 0);
}
}
// open_tombstone - find an available tombstone slot, if any, of the
// form tombstone_XX where XX is 00 to MAX_TOMBSTONES-1, inclusive. If no
// file is available, we reuse the least-recently-modified file.
int open_tombstone(std::string* out_path) {
// In a single pass, find an available slot and, in case none
// exist, find and record the least-recently-modified file.
char path[128];
int fd = -1;
int oldest = -1;
struct stat oldest_sb;
for (int i = 0; i < MAX_TOMBSTONES; i++) {
snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, i);
struct stat sb;
if (stat(path, &sb) == 0) {
if (oldest < 0 || sb.st_mtime < oldest_sb.st_mtime) {
oldest = i;
oldest_sb.st_mtime = sb.st_mtime;
}
continue;
}
if (errno != ENOENT) continue;
fd = open(path, O_CREAT | O_EXCL | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
if (fd < 0) continue; // raced ?
if (out_path) {
*out_path = path;
}
fchown(fd, AID_SYSTEM, AID_SYSTEM);
return fd;
}
if (oldest < 0) {
ALOGE("debuggerd: failed to find a valid tombstone, default to using tombstone 0.\n");
oldest = 0;
}
// we didn't find an available file, so we clobber the oldest one
snprintf(path, sizeof(path), TOMBSTONE_TEMPLATE, oldest);
fd = open(path, O_CREAT | O_TRUNC | O_WRONLY | O_NOFOLLOW | O_CLOEXEC, 0600);
if (fd < 0) {
ALOGE("debuggerd: failed to open tombstone file '%s': %s\n", path, strerror(errno));
return -1;
}
if (out_path) {
*out_path = path;
}
fchown(fd, AID_SYSTEM, AID_SYSTEM);
return fd;
}
void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
const std::set<pid_t>& siblings, int signal, int original_si_code,
uintptr_t abort_msg_address, std::string* amfd_data) {
log_t log;
log.current_tid = tid;
log.crashed_tid = tid;
if (tombstone_fd < 0) {
ALOGE("debuggerd: skipping tombstone write, nothing to do.\n");
return;
}
log.tfd = tombstone_fd;
log.amfd_data = amfd_data;
dump_crash(&log, map, pid, tid, siblings, signal, original_si_code, abort_msg_address);
}

View File

@@ -1,39 +0,0 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _DEBUGGERD_TOMBSTONE_H
#define _DEBUGGERD_TOMBSTONE_H
#include <stdbool.h>
#include <stddef.h>
#include <sys/types.h>
#include <set>
#include <string>
class BacktraceMap;
/* Create and open a tombstone file for writing.
* Returns a writable file descriptor, or -1 with errno set appropriately.
* If out_path is non-null, *out_path is set to the path of the tombstone file.
*/
int open_tombstone(std::string* path);
/* Creates a tombstone file and writes the crash dump to it. */
void engrave_tombstone(int tombstone_fd, BacktraceMap* map, pid_t pid, pid_t tid,
const std::set<pid_t>& siblings, int signal, int original_si_code,
uintptr_t abort_msg_address, std::string* amfd_data);
#endif // _DEBUGGERD_TOMBSTONE_H

View File

@@ -1,210 +0,0 @@
/*
* Copyright 2008, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "DEBUG"
#include "utility.h"
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <string>
#include <android-base/stringprintf.h>
#include <backtrace/Backtrace.h>
#include <log/log.h>
constexpr int SLEEP_TIME_USEC = 50000; // 0.05 seconds
constexpr int MAX_TOTAL_SLEEP_USEC = 10000000; // 10 seconds
// Whitelist output desired in the logcat output.
bool is_allowed_in_logcat(enum logtype ltype) {
if ((ltype == HEADER)
|| (ltype == REGISTERS)
|| (ltype == BACKTRACE)) {
return true;
}
return false;
}
void _LOG(log_t* log, enum logtype ltype, const char* fmt, ...) {
bool write_to_tombstone = (log->tfd != -1);
bool write_to_logcat = is_allowed_in_logcat(ltype)
&& log->crashed_tid != -1
&& log->current_tid != -1
&& (log->crashed_tid == log->current_tid);
char buf[512];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
size_t len = strlen(buf);
if (len <= 0) {
return;
}
if (write_to_tombstone) {
TEMP_FAILURE_RETRY(write(log->tfd, buf, len));
}
if (write_to_logcat) {
__android_log_buf_write(LOG_ID_CRASH, ANDROID_LOG_FATAL, LOG_TAG, buf);
if (log->amfd_data != nullptr) {
*log->amfd_data += buf;
}
}
}
int wait_for_signal(pid_t tid, int* total_sleep_time_usec) {
while (true) {
int status;
pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL | WNOHANG));
if (n == -1) {
ALOGE("waitpid failed: tid %d, %s", tid, strerror(errno));
return -1;
} else if (n == tid) {
if (WIFSTOPPED(status)) {
return WSTOPSIG(status);
} else {
ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status);
// This is the only circumstance under which we can allow a detach
// to fail with ESRCH, which indicates the tid has exited.
return -1;
}
}
if (*total_sleep_time_usec > MAX_TOTAL_SLEEP_USEC) {
ALOGE("timed out waiting for stop signal: tid=%d", tid);
return -1;
}
usleep(SLEEP_TIME_USEC);
*total_sleep_time_usec += SLEEP_TIME_USEC;
}
}
#define MEMORY_BYTES_TO_DUMP 256
#define MEMORY_BYTES_PER_LINE 16
void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...) {
std::string log_msg;
va_list ap;
va_start(ap, fmt);
android::base::StringAppendV(&log_msg, fmt, ap);
va_end(ap);
// Align the address to sizeof(long) and start 32 bytes before the address.
addr &= ~(sizeof(long) - 1);
if (addr >= 4128) {
addr -= 32;
}
// Don't bother if the address looks too low, or looks too high.
if (addr < 4096 ||
#if defined(__LP64__)
addr > 0x4000000000000000UL - MEMORY_BYTES_TO_DUMP) {
#else
addr > 0xffff0000 - MEMORY_BYTES_TO_DUMP) {
#endif
return;
}
_LOG(log, logtype::MEMORY, "\n%s\n", log_msg.c_str());
// Dump 256 bytes
uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)];
memset(data, 0, MEMORY_BYTES_TO_DUMP);
size_t bytes = backtrace->Read(addr, reinterpret_cast<uint8_t*>(data), sizeof(data));
if (bytes % sizeof(uintptr_t) != 0) {
// This should never happen, but just in case.
ALOGE("Bytes read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
bytes &= ~(sizeof(uintptr_t) - 1);
}
uintptr_t start = 0;
bool skip_2nd_read = false;
if (bytes == 0) {
// In this case, we might want to try another read at the beginning of
// the next page only if it's within the amount of memory we would have
// read.
size_t page_size = sysconf(_SC_PAGE_SIZE);
start = ((addr + (page_size - 1)) & ~(page_size - 1)) - addr;
if (start == 0 || start >= MEMORY_BYTES_TO_DUMP) {
skip_2nd_read = true;
}
}
if (bytes < MEMORY_BYTES_TO_DUMP && !skip_2nd_read) {
// Try to do one more read. This could happen if a read crosses a map,
// but the maps do not have any break between them. Or it could happen
// if reading from an unreadable map, but the read would cross back
// into a readable map. Only requires one extra read because a map has
// to contain at least one page, and the total number of bytes to dump
// is smaller than a page.
size_t bytes2 = backtrace->Read(addr + start + bytes, reinterpret_cast<uint8_t*>(data) + bytes,
sizeof(data) - bytes - start);
bytes += bytes2;
if (bytes2 > 0 && bytes % sizeof(uintptr_t) != 0) {
// This should never happen, but we'll try and continue any way.
ALOGE("Bytes after second read %zu, is not a multiple of %zu", bytes, sizeof(uintptr_t));
bytes &= ~(sizeof(uintptr_t) - 1);
}
}
// Dump the code around memory as:
// addr contents ascii
// 0000000000008d34 ef000000e8bd0090 e1b00000512fff1e ............../Q
// 0000000000008d44 ea00b1f9e92d0090 e3a070fcef000000 ......-..p......
// On 32-bit machines, there are still 16 bytes per line but addresses and
// words are of course presented differently.
uintptr_t* data_ptr = data;
size_t current = 0;
size_t total_bytes = start + bytes;
for (size_t line = 0; line < MEMORY_BYTES_TO_DUMP / MEMORY_BYTES_PER_LINE; line++) {
std::string logline;
android::base::StringAppendF(&logline, " %" PRIPTR, addr);
addr += MEMORY_BYTES_PER_LINE;
std::string ascii;
for (size_t i = 0; i < MEMORY_BYTES_PER_LINE / sizeof(uintptr_t); i++) {
if (current >= start && current + sizeof(uintptr_t) <= total_bytes) {
android::base::StringAppendF(&logline, " %" PRIPTR, *data_ptr);
// Fill out the ascii string from the data.
uint8_t* ptr = reinterpret_cast<uint8_t*>(data_ptr);
for (size_t val = 0; val < sizeof(uintptr_t); val++, ptr++) {
if (*ptr >= 0x20 && *ptr < 0x7f) {
ascii += *ptr;
} else {
ascii += '.';
}
}
data_ptr++;
} else {
logline += ' ' + std::string(sizeof(uintptr_t) * 2, '-');
ascii += std::string(sizeof(uintptr_t), '.');
}
current += sizeof(uintptr_t);
}
_LOG(log, logtype::MEMORY, "%s %s\n", logline.c_str(), ascii.c_str());
}
}

View File

@@ -1,84 +0,0 @@
/* system/debuggerd/utility.h
**
** Copyright 2008, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef _DEBUGGERD_UTILITY_H
#define _DEBUGGERD_UTILITY_H
#include <stdbool.h>
#include <sys/types.h>
#include <string>
#include <backtrace/Backtrace.h>
// Figure out the abi based on defined macros.
#if defined(__arm__)
#define ABI_STRING "arm"
#elif defined(__aarch64__)
#define ABI_STRING "arm64"
#elif defined(__mips__) && !defined(__LP64__)
#define ABI_STRING "mips"
#elif defined(__mips__) && defined(__LP64__)
#define ABI_STRING "mips64"
#elif defined(__i386__)
#define ABI_STRING "x86"
#elif defined(__x86_64__)
#define ABI_STRING "x86_64"
#else
#error "Unsupported ABI"
#endif
struct log_t{
// Tombstone file descriptor.
int tfd;
// Data to be sent to the Activity Manager.
std::string* amfd_data;
// The tid of the thread that crashed.
pid_t crashed_tid;
// The tid of the thread we are currently working with.
pid_t current_tid;
// logd daemon crash, can block asking for logcat data, allow suppression.
bool should_retrieve_logcat;
log_t()
: tfd(-1), amfd_data(nullptr), crashed_tid(-1), current_tid(-1),
should_retrieve_logcat(true) {}
};
// List of types of logs to simplify the logging decision in _LOG
enum logtype {
HEADER,
THREAD,
REGISTERS,
FP_REGISTERS,
BACKTRACE,
MAPS,
MEMORY,
STACK,
LOGS
};
// Log information onto the tombstone.
void _LOG(log_t* log, logtype ltype, const char *fmt, ...)
__attribute__ ((format(printf, 3, 4)));
int wait_for_signal(pid_t tid, int* total_sleep_time_usec);
void dump_memory(log_t* log, Backtrace* backtrace, uintptr_t addr, const char* fmt, ...);
#endif // _DEBUGGERD_UTILITY_H

View File

@@ -1,15 +0,0 @@
.globl crash1
.globl crashnostack
crash1:
movl $0xa5a50000, %eax
movl $0xa5a50001, %ebx
movl $0xa5a50002, %ecx
movl $0, %edx
jmp *%edx
crashnostack:
movl $0, %ebp
jmp *%ebp

View File

@@ -1,62 +0,0 @@
/*
* Copyright 2006, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "DEBUG"
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <sys/ptrace.h>
#include <backtrace/Backtrace.h>
#include <log/log.h>
#include "machine.h"
#include "utility.h"
void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
struct pt_regs r;
if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r) == -1) {
ALOGE("cannot get registers: %s\n", strerror(errno));
return;
}
dump_memory(log, backtrace, static_cast<uintptr_t>(r.eax), "memory near eax:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.ebx), "memory near ebx:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.ecx), "memory near ecx:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.edx), "memory near edx:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.esi), "memory near esi:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.edi), "memory near edi:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.eip), "code around eip:");
}
void dump_registers(log_t* log, pid_t tid) {
struct pt_regs r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
ALOGE("cannot get registers: %s\n", strerror(errno));
return;
}
_LOG(log, logtype::REGISTERS, " eax %08lx ebx %08lx ecx %08lx edx %08lx\n",
r.eax, r.ebx, r.ecx, r.edx);
_LOG(log, logtype::REGISTERS, " esi %08lx edi %08lx\n",
r.esi, r.edi);
_LOG(log, logtype::REGISTERS, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n",
r.xcs, r.xds, r.xes, r.xfs, r.xss);
_LOG(log, logtype::REGISTERS, " eip %08lx ebp %08lx esp %08lx flags %08lx\n",
r.eip, r.ebp, r.esp, r.eflags);
}

View File

@@ -1,15 +0,0 @@
.globl crash1
.globl crashnostack
crash1:
movl $0xa5a50000, %eax
movl $0xa5a50001, %ebx
movl $0xa5a50002, %ecx
movl $0, %edx
jmp *%rdx
crashnostack:
movl $0, %ebp
jmp *%rbp

View File

@@ -1,67 +0,0 @@
/*
** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#define LOG_TAG "DEBUG"
#include <errno.h>
#include <stdint.h>
#include <sys/ptrace.h>
#include <string.h>
#include <sys/user.h>
#include <backtrace/Backtrace.h>
#include <log/log.h>
#include "machine.h"
#include "utility.h"
void dump_memory_and_code(log_t* log, Backtrace* backtrace) {
struct user_regs_struct r;
if (ptrace(PTRACE_GETREGS, backtrace->Tid(), 0, &r) == -1) {
ALOGE("cannot get registers: %s\n", strerror(errno));
return;
}
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rax), "memory near rax:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rbx), "memory near rbx:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rcx), "memory near rcx:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rdx), "memory near rdx:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rsi), "memory near rsi:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rdi), "memory near rdi:");
dump_memory(log, backtrace, static_cast<uintptr_t>(r.rip), "code around rip:");
}
void dump_registers(log_t* log, pid_t tid) {
struct user_regs_struct r;
if (ptrace(PTRACE_GETREGS, tid, 0, &r) == -1) {
ALOGE("cannot get registers: %s\n", strerror(errno));
return;
}
_LOG(log, logtype::REGISTERS, " rax %016lx rbx %016lx rcx %016lx rdx %016lx\n",
r.rax, r.rbx, r.rcx, r.rdx);
_LOG(log, logtype::REGISTERS, " rsi %016lx rdi %016lx\n",
r.rsi, r.rdi);
_LOG(log, logtype::REGISTERS, " r8 %016lx r9 %016lx r10 %016lx r11 %016lx\n",
r.r8, r.r9, r.r10, r.r11);
_LOG(log, logtype::REGISTERS, " r12 %016lx r13 %016lx r14 %016lx r15 %016lx\n",
r.r12, r.r13, r.r14, r.r15);
_LOG(log, logtype::REGISTERS, " cs %016lx ss %016lx\n",
r.cs, r.ss);
_LOG(log, logtype::REGISTERS, " rip %016lx rbp %016lx rsp %016lx eflags %016lx\n",
r.rip, r.rbp, r.rsp, r.eflags);
}

View File

@@ -1,95 +0,0 @@
#
# Copyright (C) 2014 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
include $(CLEAR_VARS)
LOCAL_MODULE := $(module)
LOCAL_MODULE_TAGS := $(module_tag)
LOCAL_MULTILIB := $($(module)_multilib)
ifeq ($(LOCAL_MULTILIB),both)
ifneq ($(build_target),$(filter $(build_target),SHARED_LIBRARY STATIC_LIBRARY))
LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
endif
endif
# ifeq ($(build_type),target)
# include $(LLVM_DEVICE_BUILD_MK)
# else
# include $(LLVM_HOST_BUILD_MK)
# endif
LOCAL_ADDITIONAL_DEPENDENCIES += \
$(LOCAL_PATH)/Android.mk \
$(LOCAL_PATH)/Android.build.mk \
LOCAL_CFLAGS += \
$(libbacktrace_common_cflags) \
$($(module)_cflags) \
$($(module)_cflags_$(build_type)) \
LOCAL_CLANG_CFLAGS += \
$(libbacktrace_common_clang_cflags) \
LOCAL_CONLYFLAGS += \
$(libbacktrace_common_conlyflags) \
$($(module)_conlyflags) \
$($(module)_conlyflags_$(build_type)) \
LOCAL_CPPFLAGS += \
$(libbacktrace_common_cppflags) \
$($(module)_cppflags) \
$($(module)_cppflags_$(build_type)) \
LOCAL_C_INCLUDES += \
$(libbacktrace_common_c_includes) \
$($(module)_c_includes) \
$($(module)_c_includes_$(build_type)) \
LOCAL_SRC_FILES := \
$($(module)_src_files) \
$($(module)_src_files_$(build_type)) \
LOCAL_STATIC_LIBRARIES += \
$($(module)_static_libraries) \
$($(module)_static_libraries_$(build_type)) \
LOCAL_SHARED_LIBRARIES += \
$($(module)_shared_libraries) \
$($(module)_shared_libraries_$(build_type)) \
LOCAL_LDLIBS += \
$($(module)_ldlibs) \
$($(module)_ldlibs_$(build_type)) \
LOCAL_STRIP_MODULE := $($(module)_strip_module)
ifeq ($(build_type),target)
include $(BUILD_$(build_target))
endif
ifeq ($(build_type),host)
# Only build if host builds are supported.
ifeq ($(build_host),true)
# -fno-omit-frame-pointer should be set for host build. Because currently
# libunwind can't recognize .debug_frame using dwarf version 4, and it relies
# on stack frame pointer to do unwinding on x86.
# $(LLVM_HOST_BUILD_MK) overwrites -fno-omit-frame-pointer. so the below line
# must be after the include.
LOCAL_CFLAGS += -Wno-extern-c-compat -fno-omit-frame-pointer
include $(BUILD_HOST_$(build_target))
endif
endif

View File

@@ -1,124 +0,0 @@
#
# Copyright (C) 2014 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH:= $(call my-dir)
libbacktrace_common_cflags := \
-Wall \
-Werror
libbacktrace_common_conlyflags := \
-std=gnu99 \
libbacktrace_common_cppflags := \
-std=gnu++11 \
-I$(HERE_PATH)/crash_dump/libbase/include \
-I$(HERE_PATH)/crash_dump/libunwind/include/tdep
# The latest clang (r230699) does not allow SP/PC to be declared in inline asm lists.
libbacktrace_common_clang_cflags += \
-Wno-inline-asm
build_host := false
ifeq ($(HOST_OS),linux)
ifeq ($(HOST_ARCH),$(filter $(HOST_ARCH),x86 x86_64))
build_host := true
endif
endif
# LLVM_ROOT_PATH := external/llvm
# include $(LLVM_ROOT_PATH)/llvm.mk
#-------------------------------------------------------------------------
# The libbacktrace library.
#-------------------------------------------------------------------------
libbacktrace_src_files := \
Backtrace.cpp \
BacktraceCurrent.cpp \
BacktraceMap.cpp \
BacktracePtrace.cpp \
thread_utils.c \
ThreadEntry.cpp \
UnwindCurrent.cpp \
UnwindMap.cpp \
UnwindPtrace.cpp \
libbacktrace_shared_ldlibs := -llog
libbacktrace_shared_libraries := libunwind libcrashdumpbase
module := libbacktrace
module_tag := optional
build_type := target
build_target := SHARED_LIBRARY
include $(LOCAL_PATH)/Android.build.mk
build_type := host
libbacktrace_multilib := both
include $(LOCAL_PATH)/Android.build.mk
libbacktrace_static_ldlibs := -llog -lunwind
# -lbase
# libbacktrace_static_libraries := libunwind
build_target := STATIC_LIBRARY
include $(LOCAL_PATH)/Android.build.mk
libbacktrace_static_libraries :=
#-------------------------------------------------------------------------
# The libbacktrace_offline shared library.
#-------------------------------------------------------------------------
libbacktrace_offline_src_files := \
BacktraceOffline.cpp \
# Use shared llvm library on device to save space.
libbacktrace_offline_shared_libraries_target := \
libbacktrace \
libbase \
liblog \
libunwind \
libutils \
libLLVM \
libbacktrace_offline_static_libraries_target := \
libziparchive \
libz \
# Use static llvm libraries on host to remove dependency on 32-bit llvm shared library
# which is not included in the prebuilt.
libbacktrace_offline_static_libraries_host := \
libbacktrace \
libunwind \
libziparchive-host \
libz \
libbase \
liblog \
libutils \
libLLVMObject \
libLLVMBitReader \
libLLVMMC \
libLLVMMCParser \
libLLVMCore \
libLLVMSupport \
module := libbacktrace_offline
build_type := target
build_target := STATIC_LIBRARY
libbacktrace_offline_multilib := both
# i don't know if this lib is required or not
# include $(LOCAL_PATH)/Android.build.mk
build_type := host
# include $(LOCAL_PATH)/Android.build.mk

View File

@@ -1,155 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <ucontext.h>
#include <string>
#include <android-base/stringprintf.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include "BacktraceLog.h"
#include "thread_utils.h"
#include "UnwindCurrent.h"
#include "UnwindPtrace.h"
using android::base::StringPrintf;
//-------------------------------------------------------------------------
// Backtrace functions.
//-------------------------------------------------------------------------
Backtrace::Backtrace(pid_t pid, pid_t tid, BacktraceMap* map)
: pid_(pid), tid_(tid), map_(map), map_shared_(true) {
if (map_ == nullptr) {
map_ = BacktraceMap::Create(pid);
map_shared_ = false;
}
}
Backtrace::~Backtrace() {
if (map_ && !map_shared_) {
delete map_;
map_ = nullptr;
}
}
std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
std::string func_name = GetFunctionNameRaw(pc, offset);
return func_name;
}
bool Backtrace::VerifyReadWordArgs(uintptr_t ptr, word_t* out_value) {
if (ptr & (sizeof(word_t)-1)) {
BACK_LOGW("invalid pointer %p", reinterpret_cast<void*>(ptr));
*out_value = static_cast<word_t>(-1);
return false;
}
return true;
}
std::string Backtrace::FormatFrameData(size_t frame_num) {
if (frame_num >= frames_.size()) {
return "";
}
return FormatFrameData(&frames_[frame_num]);
}
std::string Backtrace::FormatFrameData(const backtrace_frame_data_t* frame) {
uintptr_t relative_pc;
std::string map_name;
if (BacktraceMap::IsValid(frame->map)) {
relative_pc = BacktraceMap::GetRelativePc(frame->map, frame->pc);
if (!frame->map.name.empty()) {
map_name = frame->map.name.c_str();
if (map_name[0] == '[' && map_name[map_name.size() - 1] == ']') {
map_name.resize(map_name.size() - 1);
map_name += StringPrintf(":%" PRIPTR "]", frame->map.start);
}
} else {
map_name = StringPrintf("<anonymous:%" PRIPTR ">", frame->map.start);
}
} else {
map_name = "<unknown>";
relative_pc = frame->pc;
}
std::string line(StringPrintf("#%02zu pc %" PRIPTR " ", frame->num, relative_pc));
line += map_name;
// Special handling for non-zero offset maps, we need to print that
// information.
if (frame->map.offset != 0) {
line += " (offset " + StringPrintf("0x%" PRIxPTR, frame->map.offset) + ")";
}
if (!frame->func_name.empty()) {
line += " (" + frame->func_name;
if (frame->func_offset) {
line += StringPrintf("+%" PRIuPTR, frame->func_offset);
}
line += ')';
}
return line;
}
void Backtrace::FillInMap(uintptr_t pc, backtrace_map_t* map) {
if (map_ != nullptr) {
map_->FillIn(pc, map);
}
}
Backtrace* Backtrace::Create(pid_t pid, pid_t tid, BacktraceMap* map) {
if (pid == BACKTRACE_CURRENT_PROCESS) {
pid = getpid();
if (tid == BACKTRACE_CURRENT_THREAD) {
tid = gettid();
}
} else if (tid == BACKTRACE_CURRENT_THREAD) {
tid = pid;
}
if (pid == getpid()) {
return new UnwindCurrent(pid, tid, map);
} else {
return new UnwindPtrace(pid, tid, map);
}
}
std::string Backtrace::GetErrorString(BacktraceUnwindError error) {
switch (error) {
case BACKTRACE_UNWIND_NO_ERROR:
return "No error";
case BACKTRACE_UNWIND_ERROR_SETUP_FAILED:
return "Setup failed";
case BACKTRACE_UNWIND_ERROR_MAP_MISSING:
return "No map found";
case BACKTRACE_UNWIND_ERROR_INTERNAL:
return "Internal libbacktrace error, please submit a bugreport";
case BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST:
return "Thread doesn't exist";
case BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT:
return "Thread has not repsonded to signal in time";
case BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION:
return "Attempt to use an unsupported feature";
case BACKTRACE_UNWIND_ERROR_NO_CONTEXT:
return "Attempt to do an offline unwind without a context";
}
}

View File

@@ -1,210 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define _GNU_SOURCE 1
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <ucontext.h>
#include <unistd.h>
#include <stdlib.h>
#include <string>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include "BacktraceCurrent.h"
#include "BacktraceLog.h"
#include "ThreadEntry.h"
#include "thread_utils.h"
bool BacktraceCurrent::ReadWord(uintptr_t ptr, word_t* out_value) {
if (!VerifyReadWordArgs(ptr, out_value)) {
return false;
}
backtrace_map_t map;
FillInMap(ptr, &map);
if (BacktraceMap::IsValid(map) && map.flags & PROT_READ) {
*out_value = *reinterpret_cast<word_t*>(ptr);
return true;
} else {
BACK_LOGW("pointer %p not in a readable map", reinterpret_cast<void*>(ptr));
*out_value = static_cast<word_t>(-1);
return false;
}
}
size_t BacktraceCurrent::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
backtrace_map_t map;
FillInMap(addr, &map);
if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
return 0;
}
bytes = MIN(map.end - addr, bytes);
memcpy(buffer, reinterpret_cast<uint8_t*>(addr), bytes);
return bytes;
}
bool BacktraceCurrent::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
if (GetMap() == nullptr) {
// Without a map object, we can't do anything.
error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
return false;
}
error_ = BACKTRACE_UNWIND_NO_ERROR;
if (ucontext) {
return UnwindFromContext(num_ignore_frames, ucontext);
}
if (Tid() != gettid()) {
return UnwindThread(num_ignore_frames);
}
return UnwindFromContext(num_ignore_frames, nullptr);
}
bool BacktraceCurrent::DiscardFrame(const backtrace_frame_data_t& frame) {
if (BacktraceMap::IsValid(frame.map)) {
const std::string library = basename(frame.map.name.c_str());
if (library == "libunwind.so" || library == "libbacktrace.so") {
return true;
}
}
return false;
}
static pthread_mutex_t g_sigaction_mutex = PTHREAD_MUTEX_INITIALIZER;
static void SignalLogOnly(int, siginfo_t*, void*) {
BACK_LOGE("pid %d, tid %d: Received a spurious signal %d\n", getpid(), gettid(), THREAD_SIGNAL);
}
static void SignalHandler(int, siginfo_t*, void* sigcontext) {
ThreadEntry* entry = ThreadEntry::Get(getpid(), gettid(), false);
if (!entry) {
BACK_LOGE("pid %d, tid %d entry not found", getpid(), gettid());
return;
}
entry->CopyUcontextFromSigcontext(sigcontext);
// Indicate the ucontext is now valid.
entry->Wake();
// Pause the thread until the unwind is complete. This avoids having
// the thread run ahead causing problems.
// The number indicates that we are waiting for the second Wake() call
// overall which is made by the thread requesting an unwind.
if (entry->Wait(2)) {
// Do not remove the entry here because that can result in a deadlock
// if the code cannot properly send a signal to the thread under test.
entry->Wake();
} else {
// At this point, it is possible that entry has been freed, so just exit.
BACK_LOGE("Timed out waiting for unwind thread to indicate it completed.");
}
}
bool BacktraceCurrent::UnwindThread(size_t num_ignore_frames) {
// Prevent multiple threads trying to set the trigger action on different
// threads at the same time.
pthread_mutex_lock(&g_sigaction_mutex);
ThreadEntry* entry = ThreadEntry::Get(Pid(), Tid());
entry->Lock();
struct sigaction act, oldact;
memset(&act, 0, sizeof(act));
act.sa_sigaction = SignalHandler;
act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
sigemptyset(&act.sa_mask);
if (sigaction(THREAD_SIGNAL, &act, &oldact) != 0) {
BACK_LOGE("sigaction failed: %s", strerror(errno));
ThreadEntry::Remove(entry);
pthread_mutex_unlock(&g_sigaction_mutex);
error_ = BACKTRACE_UNWIND_ERROR_INTERNAL;
return false;
}
if (tgkill(Pid(), Tid(), THREAD_SIGNAL) != 0) {
// Do not emit an error message, this might be expected. Set the
// error and let the caller decide.
if (errno == ESRCH) {
error_ = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST;
} else {
error_ = BACKTRACE_UNWIND_ERROR_INTERNAL;
}
sigaction(THREAD_SIGNAL, &oldact, nullptr);
ThreadEntry::Remove(entry);
pthread_mutex_unlock(&g_sigaction_mutex);
return false;
}
// Wait for the thread to get the ucontext. The number indicates
// that we are waiting for the first Wake() call made by the thread.
bool wait_completed = entry->Wait(1);
if (!wait_completed && oldact.sa_sigaction == nullptr) {
// If the wait failed, it could be that the signal could not be delivered
// within the timeout. Add a signal handler that's simply going to log
// something so that we don't crash if the signal eventually gets
// delivered. Only do this if there isn't already an action set up.
memset(&act, 0, sizeof(act));
act.sa_sigaction = SignalLogOnly;
act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
sigemptyset(&act.sa_mask);
sigaction(THREAD_SIGNAL, &act, nullptr);
} else {
sigaction(THREAD_SIGNAL, &oldact, nullptr);
}
// After the thread has received the signal, allow other unwinders to
// continue.
pthread_mutex_unlock(&g_sigaction_mutex);
bool unwind_done = false;
if (wait_completed) {
unwind_done = UnwindFromContext(num_ignore_frames, entry->GetUcontext());
// Tell the signal handler to exit and release the entry.
entry->Wake();
// Wait for the thread to indicate it is done with the ThreadEntry.
if (!entry->Wait(3)) {
// Send a warning, but do not mark as a failure to unwind.
BACK_LOGW("Timed out waiting for signal handler to indicate it finished.");
}
} else {
// Check to see if the thread has disappeared.
if (tgkill(Pid(), Tid(), 0) == -1 && errno == ESRCH) {
error_ = BACKTRACE_UNWIND_ERROR_THREAD_DOESNT_EXIST;
} else {
error_ = BACKTRACE_UNWIND_ERROR_THREAD_TIMEOUT;
BACK_LOGE("Timed out waiting for signal handler to get ucontext data.");
}
}
ThreadEntry::Remove(entry);
return unwind_done;
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBBACKTRACE_BACKTRACE_CURRENT_H
#define _LIBBACKTRACE_BACKTRACE_CURRENT_H
#include <stdint.h>
#include <sys/types.h>
#include <ucontext.h>
#include <backtrace/Backtrace.h>
// The signal used to cause a thread to dump the stack.
#if defined(__GLIBC__)
// In order to run the backtrace_tests on the host, we can't use
// the internal real time signals used by GLIBC. To avoid this,
// use SIGRTMIN for the signal to dump the stack.
#define THREAD_SIGNAL SIGRTMIN
#else
#define THREAD_SIGNAL (__SIGRTMIN+1)
#endif
class BacktraceMap;
class BacktraceCurrent : public Backtrace {
public:
BacktraceCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
virtual ~BacktraceCurrent() {}
size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
bool ReadWord(uintptr_t ptr, word_t* out_value) override;
bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
protected:
bool DiscardFrame(const backtrace_frame_data_t& frame);
private:
bool UnwindThread(size_t num_ignore_frames);
virtual bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) = 0;
};
#endif // _LIBBACKTRACE_BACKTRACE_CURRENT_H

View File

@@ -1,31 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBBACKTRACE_BACKTRACE_LOG_H
#define _LIBBACKTRACE_BACKTRACE_LOG_H
#define LOG_TAG "libbacktrace"
#include <log/log.h>
// Macro to log the function name along with the warning message.
#define BACK_LOGW(format, ...) \
ALOGW("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
#define BACK_LOGE(format, ...) \
ALOGE("%s: " format, __PRETTY_FUNCTION__, ##__VA_ARGS__)
#endif // _LIBBACKTRACE_BACKTRACE_LOG_H

View File

@@ -1,153 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <ctype.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>
#include <backtrace/backtrace_constants.h>
#include <backtrace/BacktraceMap.h>
#include <log/log.h>
#include "thread_utils.h"
BacktraceMap::BacktraceMap(pid_t pid) : pid_(pid) {
if (pid_ < 0) {
pid_ = getpid();
}
}
BacktraceMap::~BacktraceMap() {
}
void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
for (BacktraceMap::const_iterator it = begin();
it != end(); ++it) {
if (addr >= it->start && addr < it->end) {
*map = *it;
return;
}
}
*map = {};
}
bool BacktraceMap::ParseLine(const char* line, backtrace_map_t* map) {
unsigned long int start;
unsigned long int end;
char permissions[5];
int name_pos;
#if defined(__APPLE__)
// Mac OS vmmap(1) output:
// __TEXT 0009f000-000a1000 [ 8K 8K] r-x/rwx SM=COW /Volumes/android/dalvik-dev/out/host/darwin-x86/bin/libcorkscrew_test\n
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
if (sscanf(line, "%*21c %lx-%lx [%*13c] %3c/%*3c SM=%*3c %n",
&start, &end, permissions, &name_pos) != 3) {
#else
// Linux /proc/<pid>/maps lines:
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so\n
// 012345678901234567890123456789012345678901234567890123456789
// 0 1 2 3 4 5
if (sscanf(line, "%lx-%lx %4s %*x %*x:%*x %*d %n",
&start, &end, permissions, &name_pos) != 3) {
#endif
return false;
}
map->start = start;
map->end = end;
map->flags = PROT_NONE;
if (permissions[0] == 'r') {
map->flags |= PROT_READ;
}
if (permissions[1] == 'w') {
map->flags |= PROT_WRITE;
}
if (permissions[2] == 'x') {
map->flags |= PROT_EXEC;
}
map->name = line+name_pos;
if (!map->name.empty() && map->name[map->name.length()-1] == '\n') {
map->name.erase(map->name.length()-1);
}
ALOGV("Parsed map: start=%p, end=%p, flags=%x, name=%s",
reinterpret_cast<void*>(map->start), reinterpret_cast<void*>(map->end),
map->flags, map->name.c_str());
return true;
}
bool BacktraceMap::Build() {
#if defined(__APPLE__)
char cmd[sizeof(pid_t)*3 + sizeof("vmmap -w -resident -submap -allSplitLibs -interleaved ") + 1];
#else
char path[sizeof(pid_t)*3 + sizeof("/proc//maps") + 1];
#endif
char line[1024];
#if defined(__APPLE__)
// cmd is guaranteed to always be big enough to hold this string.
snprintf(cmd, sizeof(cmd), "vmmap -w -resident -submap -allSplitLibs -interleaved %d", pid_);
FILE* fp = popen(cmd, "r");
#else
// path is guaranteed to always be big enough to hold this string.
snprintf(path, sizeof(path), "/proc/%d/maps", pid_);
FILE* fp = fopen(path, "r");
#endif
if (fp == nullptr) {
return false;
}
while(fgets(line, sizeof(line), fp)) {
backtrace_map_t map;
if (ParseLine(line, &map)) {
maps_.push_back(map);
}
}
#if defined(__APPLE__)
pclose(fp);
#else
fclose(fp);
#endif
return true;
}
#if defined(__APPLE__)
// Corkscrew and libunwind don't compile on the mac, so create a generic
// map object.
BacktraceMap* BacktraceMap::Create(pid_t pid, bool /*uncached*/) {
BacktraceMap* map = new BacktraceMap(pid);
if (!map->Build()) {
delete map;
return nullptr;
}
return map;
}
#endif
BacktraceMap* BacktraceMap::Create(pid_t pid, const std::vector<backtrace_map_t>& maps) {
BacktraceMap* backtrace_map = new BacktraceMap(pid);
backtrace_map->maps_.insert(backtrace_map->maps_.begin(), maps.begin(), maps.end());
std::sort(backtrace_map->maps_.begin(), backtrace_map->maps_.end(),
[](const backtrace_map_t& map1, const backtrace_map_t& map2) {
return map1.start < map2.start;
});
return backtrace_map;
}

View File

@@ -1,760 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "BacktraceOffline.h"
extern "C" {
#define UNW_REMOTE_ONLY
#include <dwarf.h>
}
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <ucontext.h>
#include <unistd.h>
#include <memory>
#include <string>
#include <vector>
#include <android-base/file.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include <ziparchive/zip_archive.h>
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#include <llvm/ADT/StringRef.h>
#include <llvm/Object/Binary.h>
#include <llvm/Object/ELFObjectFile.h>
#include <llvm/Object/ObjectFile.h>
#pragma clang diagnostic pop
#include "BacktraceLog.h"
void Space::Clear() {
start = 0;
end = 0;
data = nullptr;
}
size_t Space::Read(uint64_t addr, uint8_t* buffer, size_t size) {
if (addr >= start && addr < end) {
size_t read_size = std::min(size, static_cast<size_t>(end - addr));
memcpy(buffer, data + (addr - start), read_size);
return read_size;
}
return 0;
}
static int FindProcInfo(unw_addr_space_t addr_space, unw_word_t ip, unw_proc_info* proc_info,
int need_unwind_info, void* arg) {
BacktraceOffline* backtrace = reinterpret_cast<BacktraceOffline*>(arg);
bool result = backtrace->FindProcInfo(addr_space, ip, proc_info, need_unwind_info);
return result ? 0 : -UNW_EINVAL;
}
static void PutUnwindInfo(unw_addr_space_t, unw_proc_info_t*, void*) {
}
static int GetDynInfoListAddr(unw_addr_space_t, unw_word_t*, void*) {
return -UNW_ENOINFO;
}
static int AccessMem(unw_addr_space_t, unw_word_t addr, unw_word_t* value, int write, void* arg) {
if (write == 1) {
return -UNW_EINVAL;
}
BacktraceOffline* backtrace = reinterpret_cast<BacktraceOffline*>(arg);
*value = 0;
size_t read_size = backtrace->Read(addr, reinterpret_cast<uint8_t*>(value), sizeof(unw_word_t));
// Strictly we should check if read_size matches sizeof(unw_word_t), but it is possible in
// .eh_frame_hdr that the section can end at a position not aligned in sizeof(unw_word_t), and
// we should permit the read at the end of the section.
return (read_size > 0u ? 0 : -UNW_EINVAL);
}
static int AccessReg(unw_addr_space_t, unw_regnum_t unwind_reg, unw_word_t* value, int write,
void* arg) {
if (write == 1) {
return -UNW_EINVAL;
}
BacktraceOffline* backtrace = reinterpret_cast<BacktraceOffline*>(arg);
uint64_t reg_value;
bool result = backtrace->ReadReg(unwind_reg, &reg_value);
if (result) {
*value = static_cast<unw_word_t>(reg_value);
}
return result ? 0 : -UNW_EINVAL;
}
static int AccessFpReg(unw_addr_space_t, unw_regnum_t, unw_fpreg_t*, int, void*) {
return -UNW_EINVAL;
}
static int Resume(unw_addr_space_t, unw_cursor_t*, void*) {
return -UNW_EINVAL;
}
static int GetProcName(unw_addr_space_t, unw_word_t, char*, size_t, unw_word_t*, void*) {
return -UNW_EINVAL;
}
static unw_accessors_t accessors = {
.find_proc_info = FindProcInfo,
.put_unwind_info = PutUnwindInfo,
.get_dyn_info_list_addr = GetDynInfoListAddr,
.access_mem = AccessMem,
.access_reg = AccessReg,
.access_fpreg = AccessFpReg,
.resume = Resume,
.get_proc_name = GetProcName,
};
bool BacktraceOffline::Unwind(size_t num_ignore_frames, ucontext_t* context) {
if (context == nullptr) {
BACK_LOGW("The context is needed for offline backtracing.");
error_ = BACKTRACE_UNWIND_ERROR_NO_CONTEXT;
return false;
}
context_ = context;
error_ = BACKTRACE_UNWIND_NO_ERROR;
unw_addr_space_t addr_space = unw_create_addr_space(&accessors, 0);
unw_cursor_t cursor;
int ret = unw_init_remote(&cursor, addr_space, this);
if (ret != 0) {
BACK_LOGW("unw_init_remote failed %d", ret);
unw_destroy_addr_space(addr_space);
error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
return false;
}
size_t num_frames = 0;
do {
unw_word_t pc;
ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
if (ret < 0) {
BACK_LOGW("Failed to read IP %d", ret);
break;
}
unw_word_t sp;
ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
if (ret < 0) {
BACK_LOGW("Failed to read SP %d", ret);
break;
}
if (num_ignore_frames == 0) {
frames_.resize(num_frames + 1);
backtrace_frame_data_t* frame = &frames_[num_frames];
frame->num = num_frames;
frame->pc = static_cast<uintptr_t>(pc);
frame->sp = static_cast<uintptr_t>(sp);
frame->stack_size = 0;
if (num_frames > 0) {
backtrace_frame_data_t* prev = &frames_[num_frames - 1];
prev->stack_size = frame->sp - prev->sp;
}
frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
FillInMap(frame->pc, &frame->map);
num_frames++;
} else {
num_ignore_frames--;
}
ret = unw_step(&cursor);
} while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
unw_destroy_addr_space(addr_space);
context_ = nullptr;
return true;
}
bool BacktraceOffline::ReadWord(uintptr_t ptr, word_t* out_value) {
size_t bytes_read = Read(ptr, reinterpret_cast<uint8_t*>(out_value), sizeof(word_t));
return bytes_read == sizeof(word_t);
}
size_t BacktraceOffline::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
// Normally, libunwind needs stack information and call frame information to do remote unwinding.
// If call frame information is stored in .debug_frame, libunwind can read it from file
// by itself. If call frame information is stored in .eh_frame, we need to provide data in
// .eh_frame/.eh_frame_hdr sections.
// The order of readings below doesn't matter, as the spaces don't overlap with each other.
size_t read_size = eh_frame_hdr_space_.Read(addr, buffer, bytes);
if (read_size != 0) {
return read_size;
}
read_size = eh_frame_space_.Read(addr, buffer, bytes);
if (read_size != 0) {
return read_size;
}
read_size = stack_space_.Read(addr, buffer, bytes);
return read_size;
}
static bool FileOffsetToVaddr(
const std::vector<DebugFrameInfo::EhFrame::ProgramHeader>& program_headers,
uint64_t file_offset, uint64_t* vaddr) {
for (auto& header : program_headers) {
if (file_offset >= header.file_offset && file_offset < header.file_offset + header.file_size) {
// TODO: Consider load_bias?
*vaddr = file_offset - header.file_offset + header.vaddr;
return true;
}
}
return false;
}
bool BacktraceOffline::FindProcInfo(unw_addr_space_t addr_space, uint64_t ip,
unw_proc_info_t* proc_info, int need_unwind_info) {
backtrace_map_t map;
FillInMap(ip, &map);
if (!BacktraceMap::IsValid(map)) {
return false;
}
const std::string& filename = map.name;
DebugFrameInfo* debug_frame = GetDebugFrameInFile(filename);
if (debug_frame == nullptr) {
return false;
}
if (debug_frame->is_eh_frame) {
uint64_t ip_offset = ip - map.start + map.offset;
uint64_t ip_vaddr; // vaddr in the elf file.
bool result = FileOffsetToVaddr(debug_frame->eh_frame.program_headers, ip_offset, &ip_vaddr);
if (!result) {
return false;
}
// Calculate the addresses where .eh_frame_hdr and .eh_frame stay when the process was running.
eh_frame_hdr_space_.start = (ip - ip_vaddr) + debug_frame->eh_frame.eh_frame_hdr_vaddr;
eh_frame_hdr_space_.end =
eh_frame_hdr_space_.start + debug_frame->eh_frame.eh_frame_hdr_data.size();
eh_frame_hdr_space_.data = debug_frame->eh_frame.eh_frame_hdr_data.data();
eh_frame_space_.start = (ip - ip_vaddr) + debug_frame->eh_frame.eh_frame_vaddr;
eh_frame_space_.end = eh_frame_space_.start + debug_frame->eh_frame.eh_frame_data.size();
eh_frame_space_.data = debug_frame->eh_frame.eh_frame_data.data();
unw_dyn_info di;
memset(&di, '\0', sizeof(di));
di.start_ip = map.start;
di.end_ip = map.end;
di.format = UNW_INFO_FORMAT_REMOTE_TABLE;
di.u.rti.name_ptr = 0;
di.u.rti.segbase = eh_frame_hdr_space_.start;
di.u.rti.table_data =
eh_frame_hdr_space_.start + debug_frame->eh_frame.fde_table_offset_in_eh_frame_hdr;
di.u.rti.table_len = (eh_frame_hdr_space_.end - di.u.rti.table_data) / sizeof(unw_word_t);
int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this);
return ret == 0;
}
eh_frame_hdr_space_.Clear();
eh_frame_space_.Clear();
unw_dyn_info_t di;
unw_word_t segbase = map.start - map.offset;
int found = dwarf_find_debug_frame(0, &di, ip, segbase, filename.c_str(), map.start, map.end);
if (found == 1) {
int ret = dwarf_search_unwind_table(addr_space, ip, &di, proc_info, need_unwind_info, this);
return ret == 0;
}
return false;
}
bool BacktraceOffline::ReadReg(size_t reg, uint64_t* value) {
bool result = true;
#if defined(__arm__)
switch (reg) {
case UNW_ARM_R0:
*value = context_->uc_mcontext.arm_r0;
break;
case UNW_ARM_R1:
*value = context_->uc_mcontext.arm_r1;
break;
case UNW_ARM_R2:
*value = context_->uc_mcontext.arm_r2;
break;
case UNW_ARM_R3:
*value = context_->uc_mcontext.arm_r3;
break;
case UNW_ARM_R4:
*value = context_->uc_mcontext.arm_r4;
break;
case UNW_ARM_R5:
*value = context_->uc_mcontext.arm_r5;
break;
case UNW_ARM_R6:
*value = context_->uc_mcontext.arm_r6;
break;
case UNW_ARM_R7:
*value = context_->uc_mcontext.arm_r7;
break;
case UNW_ARM_R8:
*value = context_->uc_mcontext.arm_r8;
break;
case UNW_ARM_R9:
*value = context_->uc_mcontext.arm_r9;
break;
case UNW_ARM_R10:
*value = context_->uc_mcontext.arm_r10;
break;
case UNW_ARM_R11:
*value = context_->uc_mcontext.arm_fp;
break;
case UNW_ARM_R12:
*value = context_->uc_mcontext.arm_ip;
break;
case UNW_ARM_R13:
*value = context_->uc_mcontext.arm_sp;
break;
case UNW_ARM_R14:
*value = context_->uc_mcontext.arm_lr;
break;
case UNW_ARM_R15:
*value = context_->uc_mcontext.arm_pc;
break;
default:
result = false;
}
#elif defined(__aarch64__)
if (reg <= UNW_AARCH64_PC) {
*value = context_->uc_mcontext.regs[reg];
} else {
result = false;
}
#elif defined(__x86_64__)
switch (reg) {
case UNW_X86_64_R8:
*value = context_->uc_mcontext.gregs[REG_R8];
break;
case UNW_X86_64_R9:
*value = context_->uc_mcontext.gregs[REG_R9];
break;
case UNW_X86_64_R10:
*value = context_->uc_mcontext.gregs[REG_R10];
break;
case UNW_X86_64_R11:
*value = context_->uc_mcontext.gregs[REG_R11];
break;
case UNW_X86_64_R12:
*value = context_->uc_mcontext.gregs[REG_R12];
break;
case UNW_X86_64_R13:
*value = context_->uc_mcontext.gregs[REG_R13];
break;
case UNW_X86_64_R14:
*value = context_->uc_mcontext.gregs[REG_R14];
break;
case UNW_X86_64_R15:
*value = context_->uc_mcontext.gregs[REG_R15];
break;
case UNW_X86_64_RDI:
*value = context_->uc_mcontext.gregs[REG_RDI];
break;
case UNW_X86_64_RSI:
*value = context_->uc_mcontext.gregs[REG_RSI];
break;
case UNW_X86_64_RBP:
*value = context_->uc_mcontext.gregs[REG_RBP];
break;
case UNW_X86_64_RBX:
*value = context_->uc_mcontext.gregs[REG_RBX];
break;
case UNW_X86_64_RDX:
*value = context_->uc_mcontext.gregs[REG_RDX];
break;
case UNW_X86_64_RAX:
*value = context_->uc_mcontext.gregs[REG_RAX];
break;
case UNW_X86_64_RCX:
*value = context_->uc_mcontext.gregs[REG_RCX];
break;
case UNW_X86_64_RSP:
*value = context_->uc_mcontext.gregs[REG_RSP];
break;
case UNW_X86_64_RIP:
*value = context_->uc_mcontext.gregs[REG_RIP];
break;
default:
result = false;
}
#elif defined(__i386__)
switch (reg) {
case UNW_X86_GS:
*value = context_->uc_mcontext.gregs[REG_GS];
break;
case UNW_X86_FS:
*value = context_->uc_mcontext.gregs[REG_FS];
break;
case UNW_X86_ES:
*value = context_->uc_mcontext.gregs[REG_ES];
break;
case UNW_X86_DS:
*value = context_->uc_mcontext.gregs[REG_DS];
break;
case UNW_X86_EAX:
*value = context_->uc_mcontext.gregs[REG_EAX];
break;
case UNW_X86_EBX:
*value = context_->uc_mcontext.gregs[REG_EBX];
break;
case UNW_X86_ECX:
*value = context_->uc_mcontext.gregs[REG_ECX];
break;
case UNW_X86_EDX:
*value = context_->uc_mcontext.gregs[REG_EDX];
break;
case UNW_X86_ESI:
*value = context_->uc_mcontext.gregs[REG_ESI];
break;
case UNW_X86_EDI:
*value = context_->uc_mcontext.gregs[REG_EDI];
break;
case UNW_X86_EBP:
*value = context_->uc_mcontext.gregs[REG_EBP];
break;
case UNW_X86_EIP:
*value = context_->uc_mcontext.gregs[REG_EIP];
break;
case UNW_X86_ESP:
*value = context_->uc_mcontext.gregs[REG_ESP];
break;
case UNW_X86_TRAPNO:
*value = context_->uc_mcontext.gregs[REG_TRAPNO];
break;
case UNW_X86_CS:
*value = context_->uc_mcontext.gregs[REG_CS];
break;
case UNW_X86_EFLAGS:
*value = context_->uc_mcontext.gregs[REG_EFL];
break;
case UNW_X86_SS:
*value = context_->uc_mcontext.gregs[REG_SS];
break;
default:
result = false;
}
#endif
return result;
}
std::string BacktraceOffline::GetFunctionNameRaw(uintptr_t, uintptr_t* offset) {
// We don't have enough information to support this. And it is expensive.
*offset = 0;
return "";
}
std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>> BacktraceOffline::debug_frames_;
std::unordered_set<std::string> BacktraceOffline::debug_frame_missing_files_;
static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename);
DebugFrameInfo* BacktraceOffline::GetDebugFrameInFile(const std::string& filename) {
if (cache_file_) {
auto it = debug_frames_.find(filename);
if (it != debug_frames_.end()) {
return it->second.get();
}
if (debug_frame_missing_files_.find(filename) != debug_frame_missing_files_.end()) {
return nullptr;
}
}
DebugFrameInfo* debug_frame = ReadDebugFrameFromFile(filename);
if (cache_file_) {
if (debug_frame != nullptr) {
debug_frames_.emplace(filename, std::unique_ptr<DebugFrameInfo>(debug_frame));
} else {
debug_frame_missing_files_.insert(filename);
}
} else {
if (last_debug_frame_ != nullptr) {
delete last_debug_frame_;
}
last_debug_frame_ = debug_frame;
}
return debug_frame;
}
static bool OmitEncodedValue(uint8_t encode, const uint8_t*& p) {
if (encode == DW_EH_PE_omit) {
return 0;
}
uint8_t format = encode & 0x0f;
switch (format) {
case DW_EH_PE_ptr:
p += sizeof(unw_word_t);
break;
case DW_EH_PE_uleb128:
case DW_EH_PE_sleb128:
while ((*p & 0x80) != 0) {
++p;
}
++p;
break;
case DW_EH_PE_udata2:
case DW_EH_PE_sdata2:
p += 2;
break;
case DW_EH_PE_udata4:
case DW_EH_PE_sdata4:
p += 4;
break;
case DW_EH_PE_udata8:
case DW_EH_PE_sdata8:
p += 8;
break;
default:
return false;
}
return true;
}
static bool GetFdeTableOffsetInEhFrameHdr(const std::vector<uint8_t>& data,
uint64_t* table_offset_in_eh_frame_hdr) {
const uint8_t* p = data.data();
const uint8_t* end = p + data.size();
if (p + 4 > end) {
return false;
}
uint8_t version = *p++;
if (version != 1) {
return false;
}
uint8_t eh_frame_ptr_encode = *p++;
uint8_t fde_count_encode = *p++;
uint8_t fde_table_encode = *p++;
if (fde_table_encode != (DW_EH_PE_datarel | DW_EH_PE_sdata4)) {
return false;
}
if (!OmitEncodedValue(eh_frame_ptr_encode, p) || !OmitEncodedValue(fde_count_encode, p)) {
return false;
}
if (p >= end) {
return false;
}
*table_offset_in_eh_frame_hdr = p - data.data();
return true;
}
using ProgramHeader = DebugFrameInfo::EhFrame::ProgramHeader;
template <class ELFT>
DebugFrameInfo* ReadDebugFrameFromELFFile(const llvm::object::ELFFile<ELFT>* elf) {
bool has_eh_frame_hdr = false;
uint64_t eh_frame_hdr_vaddr = 0;
std::vector<uint8_t> eh_frame_hdr_data;
bool has_eh_frame = false;
uint64_t eh_frame_vaddr = 0;
std::vector<uint8_t> eh_frame_data;
for (auto it = elf->section_begin(); it != elf->section_end(); ++it) {
llvm::ErrorOr<llvm::StringRef> name = elf->getSectionName(&*it);
if (name) {
if (name.get() == ".debug_frame") {
DebugFrameInfo* debug_frame = new DebugFrameInfo;
debug_frame->is_eh_frame = false;
return debug_frame;
}
if (name.get() == ".eh_frame_hdr") {
has_eh_frame_hdr = true;
eh_frame_hdr_vaddr = it->sh_addr;
llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
if (data) {
eh_frame_hdr_data.insert(eh_frame_hdr_data.begin(), data->data(),
data->data() + data->size());
} else {
return nullptr;
}
} else if (name.get() == ".eh_frame") {
has_eh_frame = true;
eh_frame_vaddr = it->sh_addr;
llvm::ErrorOr<llvm::ArrayRef<uint8_t>> data = elf->getSectionContents(&*it);
if (data) {
eh_frame_data.insert(eh_frame_data.begin(), data->data(), data->data() + data->size());
} else {
return nullptr;
}
}
}
}
if (!(has_eh_frame_hdr && has_eh_frame)) {
return nullptr;
}
uint64_t fde_table_offset;
if (!GetFdeTableOffsetInEhFrameHdr(eh_frame_hdr_data, &fde_table_offset)) {
return nullptr;
}
std::vector<ProgramHeader> program_headers;
for (auto it = elf->program_header_begin(); it != elf->program_header_end(); ++it) {
ProgramHeader header;
header.vaddr = it->p_vaddr;
header.file_offset = it->p_offset;
header.file_size = it->p_filesz;
program_headers.push_back(header);
}
DebugFrameInfo* debug_frame = new DebugFrameInfo;
debug_frame->is_eh_frame = true;
debug_frame->eh_frame.eh_frame_hdr_vaddr = eh_frame_hdr_vaddr;
debug_frame->eh_frame.eh_frame_vaddr = eh_frame_vaddr;
debug_frame->eh_frame.fde_table_offset_in_eh_frame_hdr = fde_table_offset;
debug_frame->eh_frame.eh_frame_hdr_data = std::move(eh_frame_hdr_data);
debug_frame->eh_frame.eh_frame_data = std::move(eh_frame_data);
debug_frame->eh_frame.program_headers = program_headers;
return debug_frame;
}
static bool IsValidElfPath(const std::string& filename) {
static const char elf_magic[] = {0x7f, 'E', 'L', 'F'};
struct stat st;
if (stat(filename.c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
return false;
}
FILE* fp = fopen(filename.c_str(), "reb");
if (fp == nullptr) {
return false;
}
char buf[4];
if (fread(buf, 4, 1, fp) != 1) {
fclose(fp);
return false;
}
fclose(fp);
return memcmp(buf, elf_magic, 4) == 0;
}
static bool IsValidApkPath(const std::string& apk_path) {
static const char zip_preamble[] = {0x50, 0x4b, 0x03, 0x04};
struct stat st;
if (stat(apk_path.c_str(), &st) != 0 || !S_ISREG(st.st_mode)) {
return false;
}
FILE* fp = fopen(apk_path.c_str(), "reb");
if (fp == nullptr) {
return false;
}
char buf[4];
if (fread(buf, 4, 1, fp) != 1) {
fclose(fp);
return false;
}
fclose(fp);
return memcmp(buf, zip_preamble, 4) == 0;
}
class ScopedZiparchiveHandle {
public:
ScopedZiparchiveHandle(ZipArchiveHandle handle) : handle_(handle) {
}
~ScopedZiparchiveHandle() {
CloseArchive(handle_);
}
private:
ZipArchiveHandle handle_;
};
llvm::object::OwningBinary<llvm::object::Binary> OpenEmbeddedElfFile(const std::string& filename) {
llvm::object::OwningBinary<llvm::object::Binary> nothing;
size_t pos = filename.find("!/");
if (pos == std::string::npos) {
return nothing;
}
std::string apk_file = filename.substr(0, pos);
std::string elf_file = filename.substr(pos + 2);
if (!IsValidApkPath(apk_file)) {
BACK_LOGW("%s is not a valid apk file", apk_file.c_str());
return nothing;
}
ZipArchiveHandle handle;
int32_t ret_code = OpenArchive(apk_file.c_str(), &handle);
if (ret_code != 0) {
CloseArchive(handle);
BACK_LOGW("failed to open archive %s: %s", apk_file.c_str(), ErrorCodeString(ret_code));
return nothing;
}
ScopedZiparchiveHandle scoped_handle(handle);
ZipEntry zentry;
ret_code = FindEntry(handle, ZipString(elf_file.c_str()), &zentry);
if (ret_code != 0) {
BACK_LOGW("failed to find %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
ErrorCodeString(ret_code));
return nothing;
}
if (zentry.method != kCompressStored || zentry.compressed_length != zentry.uncompressed_length) {
BACK_LOGW("%s is compressed in %s, which doesn't support running directly", elf_file.c_str(),
apk_file.c_str());
return nothing;
}
auto buffer_or_err = llvm::MemoryBuffer::getOpenFileSlice(GetFileDescriptor(handle), apk_file,
zentry.uncompressed_length,
zentry.offset);
if (!buffer_or_err) {
BACK_LOGW("failed to read %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
buffer_or_err.getError().message().c_str());
return nothing;
}
auto binary_or_err = llvm::object::createBinary(buffer_or_err.get()->getMemBufferRef());
if (!binary_or_err) {
BACK_LOGW("failed to create binary for %s in %s: %s", elf_file.c_str(), apk_file.c_str(),
binary_or_err.getError().message().c_str());
return nothing;
}
return llvm::object::OwningBinary<llvm::object::Binary>(std::move(binary_or_err.get()),
std::move(buffer_or_err.get()));
}
static DebugFrameInfo* ReadDebugFrameFromFile(const std::string& filename) {
llvm::object::OwningBinary<llvm::object::Binary> owning_binary;
if (filename.find("!/") != std::string::npos) {
owning_binary = OpenEmbeddedElfFile(filename);
} else {
if (!IsValidElfPath(filename)) {
return nullptr;
}
auto binary_or_err = llvm::object::createBinary(llvm::StringRef(filename));
if (!binary_or_err) {
return nullptr;
}
owning_binary = std::move(binary_or_err.get());
}
llvm::object::Binary* binary = owning_binary.getBinary();
auto obj = llvm::dyn_cast<llvm::object::ObjectFile>(binary);
if (obj == nullptr) {
return nullptr;
}
if (auto elf = llvm::dyn_cast<llvm::object::ELF32LEObjectFile>(obj)) {
return ReadDebugFrameFromELFFile(elf->getELFFile());
}
if (auto elf = llvm::dyn_cast<llvm::object::ELF64LEObjectFile>(obj)) {
return ReadDebugFrameFromELFFile(elf->getELFFile());
}
return nullptr;
}
Backtrace* Backtrace::CreateOffline(pid_t pid, pid_t tid, BacktraceMap* map,
const backtrace_stackinfo_t& stack, bool cache_file) {
return new BacktraceOffline(pid, tid, map, stack, cache_file);
}

View File

@@ -1,105 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBBACKTRACE_UNWIND_OFFLINE_H
#define _LIBBACKTRACE_UNWIND_OFFLINE_H
#include <libunwind.h>
#include <stdint.h>
#include <sys/types.h>
#include <ucontext.h>
#include <unordered_map>
#include <unordered_set>
#include <backtrace/Backtrace.h>
struct Space {
uint64_t start;
uint64_t end;
const uint8_t* data;
Space() {
Clear();
}
void Clear();
size_t Read(uint64_t addr, uint8_t* buffer, size_t size);
};
struct DebugFrameInfo {
bool is_eh_frame;
struct EhFrame {
uint64_t eh_frame_hdr_vaddr;
uint64_t eh_frame_vaddr;
uint64_t fde_table_offset_in_eh_frame_hdr;
std::vector<uint8_t> eh_frame_hdr_data;
std::vector<uint8_t> eh_frame_data;
struct ProgramHeader {
uint64_t vaddr;
uint64_t file_offset;
uint64_t file_size;
};
std::vector<ProgramHeader> program_headers;
} eh_frame;
};
class BacktraceOffline : public Backtrace {
public:
BacktraceOffline(pid_t pid, pid_t tid, BacktraceMap* map, const backtrace_stackinfo_t& stack,
bool cache_file)
: Backtrace(pid, tid, map),
cache_file_(cache_file),
context_(nullptr),
last_debug_frame_(nullptr) {
stack_space_.start = stack.start;
stack_space_.end = stack.end;
stack_space_.data = stack.data;
}
virtual ~BacktraceOffline() {
if (last_debug_frame_ != nullptr) {
delete last_debug_frame_;
}
}
bool Unwind(size_t num_ignore_frames, ucontext_t* context) override;
bool ReadWord(uintptr_t ptr, word_t* out_value) override;
size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes) override;
bool FindProcInfo(unw_addr_space_t addr_space, uint64_t ip, unw_proc_info_t* proc_info,
int need_unwind_info);
bool ReadReg(size_t reg_index, uint64_t* value);
protected:
std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
DebugFrameInfo* GetDebugFrameInFile(const std::string& filename);
static std::unordered_map<std::string, std::unique_ptr<DebugFrameInfo>> debug_frames_;
static std::unordered_set<std::string> debug_frame_missing_files_;
bool cache_file_;
ucontext_t* context_;
Space eh_frame_hdr_space_;
Space eh_frame_space_;
Space stack_space_;
DebugFrameInfo* last_debug_frame_;
};
#endif // _LIBBACKTRACE_BACKTRACE_OFFLINE_H

View File

@@ -1,113 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <sys/param.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <ucontext.h>
#include <unistd.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include "BacktraceLog.h"
#include "BacktracePtrace.h"
#include "thread_utils.h"
#if !defined(__APPLE__)
static bool PtraceRead(pid_t tid, uintptr_t addr, word_t* out_value) {
// ptrace() returns -1 and sets errno when the operation fails.
// To disambiguate -1 from a valid result, we clear errno beforehand.
errno = 0;
*out_value = ptrace(PTRACE_PEEKTEXT, tid, reinterpret_cast<void*>(addr), nullptr);
if (*out_value == static_cast<word_t>(-1) && errno) {
return false;
}
return true;
}
#endif
bool BacktracePtrace::ReadWord(uintptr_t ptr, word_t* out_value) {
#if defined(__APPLE__)
BACK_LOGW("MacOS does not support reading from another pid.");
return false;
#else
if (!VerifyReadWordArgs(ptr, out_value)) {
return false;
}
backtrace_map_t map;
FillInMap(ptr, &map);
if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
return false;
}
return PtraceRead(Tid(), ptr, out_value);
#endif
}
size_t BacktracePtrace::Read(uintptr_t addr, uint8_t* buffer, size_t bytes) {
#if defined(__APPLE__)
BACK_LOGW("MacOS does not support reading from another pid.");
return 0;
#else
backtrace_map_t map;
FillInMap(addr, &map);
if (!BacktraceMap::IsValid(map) || !(map.flags & PROT_READ)) {
return 0;
}
bytes = MIN(map.end - addr, bytes);
size_t bytes_read = 0;
word_t data_word;
size_t align_bytes = addr & (sizeof(word_t) - 1);
if (align_bytes != 0) {
if (!PtraceRead(Tid(), addr & ~(sizeof(word_t) - 1), &data_word)) {
return 0;
}
size_t copy_bytes = MIN(sizeof(word_t) - align_bytes, bytes);
memcpy(buffer, reinterpret_cast<uint8_t*>(&data_word) + align_bytes, copy_bytes);
addr += copy_bytes;
buffer += copy_bytes;
bytes -= copy_bytes;
bytes_read += copy_bytes;
}
size_t num_words = bytes / sizeof(word_t);
for (size_t i = 0; i < num_words; i++) {
if (!PtraceRead(Tid(), addr, &data_word)) {
return bytes_read;
}
memcpy(buffer, &data_word, sizeof(word_t));
buffer += sizeof(word_t);
addr += sizeof(word_t);
bytes_read += sizeof(word_t);
}
size_t left_over = bytes & (sizeof(word_t) - 1);
if (left_over) {
if (!PtraceRead(Tid(), addr, &data_word)) {
return bytes_read;
}
memcpy(buffer, &data_word, left_over);
bytes_read += left_over;
}
return bytes_read;
#endif
}

View File

@@ -1,37 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBBACKTRACE_BACKTRACE_PTRACE_H
#define _LIBBACKTRACE_BACKTRACE_PTRACE_H
#include <stdint.h>
#include <sys/types.h>
#include <backtrace/Backtrace.h>
class BacktraceMap;
class BacktracePtrace : public Backtrace {
public:
BacktracePtrace(pid_t pid, pid_t tid, BacktraceMap* map) : Backtrace(pid, tid, map) {}
virtual ~BacktracePtrace() {}
size_t Read(uintptr_t addr, uint8_t* buffer, size_t bytes);
bool ReadWord(uintptr_t ptr, word_t* out_value);
};
#endif // _LIBBACKTRACE_BACKTRACE_PTRACE_H

View File

@@ -1,93 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
// This is an extremely simplified version of libpagemap.
#define _BITS(x, offset, bits) (((x) >> offset) & ((1LL << (bits)) - 1))
#define PAGEMAP_PRESENT(x) (_BITS(x, 63, 1))
#define PAGEMAP_SWAPPED(x) (_BITS(x, 62, 1))
#define PAGEMAP_SHIFT(x) (_BITS(x, 55, 6))
#define PAGEMAP_PFN(x) (_BITS(x, 0, 55))
#define PAGEMAP_SWAP_OFFSET(x) (_BITS(x, 5, 50))
#define PAGEMAP_SWAP_TYPE(x) (_BITS(x, 0, 5))
static bool ReadData(int fd, unsigned long place, uint64_t *data) {
if (lseek(fd, place * sizeof(uint64_t), SEEK_SET) < 0) {
return false;
}
if (read(fd, (void*)data, sizeof(uint64_t)) != (ssize_t)sizeof(uint64_t)) {
return false;
}
return true;
}
size_t GetPssBytes() {
FILE* maps = fopen("/proc/self/maps", "r");
if (maps == nullptr) {
return 0;
}
int pagecount_fd = open("/proc/kpagecount", O_RDONLY);
if (pagecount_fd == -1) {
fclose(maps);
return 0;
}
int pagemap_fd = open("/proc/self/pagemap", O_RDONLY);
if (pagemap_fd == -1) {
fclose(maps);
close(pagecount_fd);
return 0;
}
char line[4096];
size_t total_pss = 0;
int pagesize = getpagesize();
while (fgets(line, sizeof(line), maps)) {
uintptr_t start, end;
if (sscanf(line, "%" SCNxPTR "-%" SCNxPTR " ", &start, &end) != 2) {
total_pss = 0;
break;
}
for (size_t page = start/pagesize; page < end/pagesize; page++) {
uint64_t data;
if (ReadData(pagemap_fd, page, &data)) {
if (PAGEMAP_PRESENT(data) && !PAGEMAP_SWAPPED(data)) {
uint64_t count;
if (ReadData(pagecount_fd, PAGEMAP_PFN(data), &count)) {
total_pss += (count >= 1) ? pagesize / count : 0;
}
}
}
}
}
fclose(maps);
close(pagecount_fd);
close(pagemap_fd);
return total_pss;
}

View File

@@ -1,22 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBBACKTRACE_GET_PSS_H
#define _LIBBACKTRACE_GET_PSS_H
size_t GetPssBytes();
#endif // _LIBBACKTRACE_GET_PSS_H

View File

@@ -1,131 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <pthread.h>
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <ucontext.h>
#include "BacktraceLog.h"
#include "ThreadEntry.h"
// Initialize static member variables.
ThreadEntry* ThreadEntry::list_ = nullptr;
pthread_mutex_t ThreadEntry::list_mutex_ = PTHREAD_MUTEX_INITIALIZER;
// Assumes that ThreadEntry::list_mutex_ has already been locked before
// creating a ThreadEntry object.
ThreadEntry::ThreadEntry(pid_t pid, pid_t tid)
: pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER),
wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0),
next_(ThreadEntry::list_), prev_(nullptr) {
pthread_condattr_t attr;
pthread_condattr_init(&attr);
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
pthread_cond_init(&wait_cond_, &attr);
// Add ourselves to the list.
if (ThreadEntry::list_) {
ThreadEntry::list_->prev_ = this;
}
ThreadEntry::list_ = this;
}
ThreadEntry* ThreadEntry::Get(pid_t pid, pid_t tid, bool create) {
pthread_mutex_lock(&ThreadEntry::list_mutex_);
ThreadEntry* entry = list_;
while (entry != nullptr) {
if (entry->Match(pid, tid)) {
break;
}
entry = entry->next_;
}
if (!entry) {
if (create) {
entry = new ThreadEntry(pid, tid);
}
} else {
entry->ref_count_++;
}
pthread_mutex_unlock(&ThreadEntry::list_mutex_);
return entry;
}
void ThreadEntry::Remove(ThreadEntry* entry) {
entry->Unlock();
pthread_mutex_lock(&ThreadEntry::list_mutex_);
if (--entry->ref_count_ == 0) {
delete entry;
}
pthread_mutex_unlock(&ThreadEntry::list_mutex_);
}
// Assumes that ThreadEntry::list_mutex_ has already been locked before
// deleting a ThreadEntry object.
ThreadEntry::~ThreadEntry() {
if (list_ == this) {
list_ = next_;
} else {
if (next_) {
next_->prev_ = prev_;
}
prev_->next_ = next_;
}
next_ = nullptr;
prev_ = nullptr;
pthread_cond_destroy(&wait_cond_);
}
bool ThreadEntry::Wait(int value) {
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
ts.tv_sec += 5;
bool wait_completed = true;
pthread_mutex_lock(&wait_mutex_);
while (wait_value_ != value) {
int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts);
if (ret != 0) {
BACK_LOGW("pthread_cond_timedwait for value %d failed: %s", value, strerror(ret));
wait_completed = false;
break;
}
}
pthread_mutex_unlock(&wait_mutex_);
return wait_completed;
}
void ThreadEntry::Wake() {
pthread_mutex_lock(&wait_mutex_);
wait_value_++;
pthread_mutex_unlock(&wait_mutex_);
pthread_cond_signal(&wait_cond_);
}
void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) {
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(sigcontext);
// The only thing the unwinder cares about is the mcontext data.
memcpy(&ucontext_.uc_mcontext, &ucontext->uc_mcontext, sizeof(ucontext->uc_mcontext));
}

View File

@@ -1,71 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBBACKTRACE_THREAD_ENTRY_H
#define _LIBBACKTRACE_THREAD_ENTRY_H
#include <pthread.h>
#include <sys/types.h>
#include <ucontext.h>
class ThreadEntry {
public:
static ThreadEntry* Get(pid_t pid, pid_t tid, bool create = true);
static void Remove(ThreadEntry* entry);
void Wake();
bool Wait(int);
void CopyUcontextFromSigcontext(void*);
inline void Lock() {
pthread_mutex_lock(&mutex_);
// Always reset the wait value since this could be the first or nth
// time this entry is locked.
wait_value_ = 0;
}
inline void Unlock() {
pthread_mutex_unlock(&mutex_);
}
inline ucontext_t* GetUcontext() { return &ucontext_; }
private:
ThreadEntry(pid_t pid, pid_t tid);
~ThreadEntry();
bool Match(pid_t chk_pid, pid_t chk_tid) { return (chk_pid == pid_ && chk_tid == tid_); }
pid_t pid_;
pid_t tid_;
int ref_count_;
pthread_mutex_t mutex_;
pthread_mutex_t wait_mutex_;
pthread_cond_t wait_cond_;
int wait_value_;
ThreadEntry* next_;
ThreadEntry* prev_;
ucontext_t ucontext_;
static ThreadEntry* list_;
static pthread_mutex_t list_mutex_;
};
#endif // _LIBBACKTRACE_THREAD_ENTRY_H

View File

@@ -1,133 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <ucontext.h>
#include <memory>
#include <string>
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <backtrace/Backtrace.h>
#include "BacktraceLog.h"
#include "UnwindCurrent.h"
std::string UnwindCurrent::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
*offset = 0;
char buf[512];
unw_word_t value;
if (unw_get_proc_name_by_ip(unw_local_addr_space, pc, buf, sizeof(buf),
&value, &context_) >= 0 && buf[0] != '\0') {
*offset = static_cast<uintptr_t>(value);
return buf;
}
return "";
}
void UnwindCurrent::GetUnwContextFromUcontext(const ucontext_t* ucontext) {
unw_tdep_context_t* unw_context = reinterpret_cast<unw_tdep_context_t*>(&context_);
#if defined(__arm__)
unw_context->regs[0] = ucontext->uc_mcontext.arm_r0;
unw_context->regs[1] = ucontext->uc_mcontext.arm_r1;
unw_context->regs[2] = ucontext->uc_mcontext.arm_r2;
unw_context->regs[3] = ucontext->uc_mcontext.arm_r3;
unw_context->regs[4] = ucontext->uc_mcontext.arm_r4;
unw_context->regs[5] = ucontext->uc_mcontext.arm_r5;
unw_context->regs[6] = ucontext->uc_mcontext.arm_r6;
unw_context->regs[7] = ucontext->uc_mcontext.arm_r7;
unw_context->regs[8] = ucontext->uc_mcontext.arm_r8;
unw_context->regs[9] = ucontext->uc_mcontext.arm_r9;
unw_context->regs[10] = ucontext->uc_mcontext.arm_r10;
unw_context->regs[11] = ucontext->uc_mcontext.arm_fp;
unw_context->regs[12] = ucontext->uc_mcontext.arm_ip;
unw_context->regs[13] = ucontext->uc_mcontext.arm_sp;
unw_context->regs[14] = ucontext->uc_mcontext.arm_lr;
unw_context->regs[15] = ucontext->uc_mcontext.arm_pc;
#else
unw_context->uc_mcontext = ucontext->uc_mcontext;
#endif
}
bool UnwindCurrent::UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) {
if (ucontext == nullptr) {
int ret = unw_getcontext(&context_);
if (ret < 0) {
BACK_LOGW("unw_getcontext failed %d", ret);
error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
return false;
}
} else {
GetUnwContextFromUcontext(ucontext);
}
// The cursor structure is pretty large, do not put it on the stack.
std::unique_ptr<unw_cursor_t> cursor(new unw_cursor_t);
int ret = unw_init_local(cursor.get(), &context_);
if (ret < 0) {
BACK_LOGW("unw_init_local failed %d", ret);
error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
return false;
}
size_t num_frames = 0;
do {
unw_word_t pc;
ret = unw_get_reg(cursor.get(), UNW_REG_IP, &pc);
if (ret < 0) {
BACK_LOGW("Failed to read IP %d", ret);
break;
}
unw_word_t sp;
ret = unw_get_reg(cursor.get(), UNW_REG_SP, &sp);
if (ret < 0) {
BACK_LOGW("Failed to read SP %d", ret);
break;
}
frames_.resize(num_frames+1);
backtrace_frame_data_t* frame = &frames_.at(num_frames);
frame->num = num_frames;
frame->pc = static_cast<uintptr_t>(pc);
frame->sp = static_cast<uintptr_t>(sp);
frame->stack_size = 0;
FillInMap(frame->pc, &frame->map);
// Check to see if we should skip this frame because it's coming
// from within the library, and we are doing a local unwind.
if (ucontext != nullptr || num_frames != 0 || !DiscardFrame(*frame)) {
if (num_ignore_frames == 0) {
// GetFunctionName is an expensive call, only do it if we are
// keeping the frame.
frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
if (num_frames > 0) {
// Set the stack size for the previous frame.
backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
prev->stack_size = frame->sp - prev->sp;
}
num_frames++;
} else {
num_ignore_frames--;
}
}
ret = unw_step (cursor.get());
} while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
return true;
}

View File

@@ -1,49 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBBACKTRACE_UNWIND_CURRENT_H
#define _LIBBACKTRACE_UNWIND_CURRENT_H
#include <stdint.h>
#include <sys/types.h>
#include <ucontext.h>
#include <string>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include "BacktraceCurrent.h"
#define UNW_LOCAL_ONLY
#include <libunwind.h>
class UnwindCurrent : public BacktraceCurrent {
public:
UnwindCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : BacktraceCurrent(pid, tid, map) {}
virtual ~UnwindCurrent() {}
std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
private:
void GetUnwContextFromUcontext(const ucontext_t* ucontext);
bool UnwindFromContext(size_t num_ignore_frames, ucontext_t* ucontext) override;
unw_context_t context_;
};
#endif // _LIBBACKTRACE_UNWIND_CURRENT_H

View File

@@ -1,157 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <backtrace/BacktraceMap.h>
#include <libunwind.h>
#include "BacktraceLog.h"
#include "UnwindMap.h"
//-------------------------------------------------------------------------
// libunwind has a single shared address space for the current process
// aka local. If multiple maps are created for the current pid, then
// only update the local address space once, and keep a reference count
// of maps using the same map cursor.
//-------------------------------------------------------------------------
UnwindMap::UnwindMap(pid_t pid) : BacktraceMap(pid) {
unw_map_cursor_clear(&map_cursor_);
}
UnwindMapRemote::UnwindMapRemote(pid_t pid) : UnwindMap(pid) {
}
UnwindMapRemote::~UnwindMapRemote() {
unw_map_cursor_destroy(&map_cursor_);
unw_map_cursor_clear(&map_cursor_);
}
bool UnwindMapRemote::GenerateMap() {
// Use the map_cursor information to construct the BacktraceMap data
// rather than reparsing /proc/self/maps.
unw_map_cursor_reset(&map_cursor_);
unw_map_t unw_map;
while (unw_map_cursor_get_next(&map_cursor_, &unw_map)) {
backtrace_map_t map;
map.start = unw_map.start;
map.end = unw_map.end;
map.offset = unw_map.offset;
map.load_base = unw_map.load_base;
map.flags = unw_map.flags;
map.name = unw_map.path;
// The maps are in descending order, but we want them in ascending order.
maps_.push_front(map);
}
return true;
}
bool UnwindMapRemote::Build() {
return (unw_map_cursor_create(&map_cursor_, pid_) == 0) && GenerateMap();
}
UnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) {
}
UnwindMapLocal::~UnwindMapLocal() {
if (map_created_) {
unw_map_local_destroy();
unw_map_cursor_clear(&map_cursor_);
}
}
bool UnwindMapLocal::GenerateMap() {
// It's possible for the map to be regenerated while this loop is occurring.
// If that happens, get the map again, but only try at most three times
// before giving up.
for (int i = 0; i < 3; i++) {
maps_.clear();
// Save the map data retrieved so we can tell if it changes.
unw_map_local_cursor_get(&map_cursor_);
unw_map_t unw_map;
int ret;
while ((ret = unw_map_local_cursor_get_next(&map_cursor_, &unw_map)) > 0) {
backtrace_map_t map;
map.start = unw_map.start;
map.end = unw_map.end;
map.offset = unw_map.offset;
map.load_base = unw_map.load_base;
map.flags = unw_map.flags;
map.name = unw_map.path;
free(unw_map.path);
// The maps are in descending order, but we want them in ascending order.
maps_.push_front(map);
}
// Check to see if the map changed while getting the data.
if (ret != -UNW_EINVAL) {
return true;
}
}
BACK_LOGW("Unable to generate the map.");
return false;
}
bool UnwindMapLocal::Build() {
return (map_created_ = (unw_map_local_create() == 0)) && GenerateMap();;
}
void UnwindMapLocal::FillIn(uintptr_t addr, backtrace_map_t* map) {
BacktraceMap::FillIn(addr, map);
if (!IsValid(*map)) {
// Check to see if the underlying map changed and regenerate the map
// if it did.
if (unw_map_local_cursor_valid(&map_cursor_) < 0) {
if (GenerateMap()) {
BacktraceMap::FillIn(addr, map);
}
}
}
}
//-------------------------------------------------------------------------
// BacktraceMap create function.
//-------------------------------------------------------------------------
BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
BacktraceMap* map;
if (uncached) {
// Force use of the base class to parse the maps when this call is made.
map = new BacktraceMap(pid);
} else if (pid == getpid()) {
map = new UnwindMapLocal();
} else {
map = new UnwindMapRemote(pid);
}
if (!map->Build()) {
delete map;
return nullptr;
}
return map;
}

View File

@@ -1,65 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBBACKTRACE_UNWIND_MAP_H
#define _LIBBACKTRACE_UNWIND_MAP_H
#include <stdint.h>
#include <sys/types.h>
#include <backtrace/BacktraceMap.h>
// The unw_map_cursor_t structure is different depending on whether it is
// the local or remote version. In order to get the correct version, include
// libunwind.h first then this header.
class UnwindMap : public BacktraceMap {
public:
UnwindMap(pid_t pid);
unw_map_cursor_t* GetMapCursor() { return &map_cursor_; }
protected:
unw_map_cursor_t map_cursor_;
};
class UnwindMapRemote : public UnwindMap {
public:
UnwindMapRemote(pid_t pid);
virtual ~UnwindMapRemote();
bool Build() override;
private:
bool GenerateMap();
};
class UnwindMapLocal : public UnwindMap {
public:
UnwindMapLocal();
virtual ~UnwindMapLocal();
bool Build() override;
void FillIn(uintptr_t addr, backtrace_map_t* map) override;
private:
bool GenerateMap();
bool map_created_;
};
#endif // _LIBBACKTRACE_UNWIND_MAP_H

View File

@@ -1,142 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdint.h>
#include <sys/types.h>
#include <ucontext.h>
#include <libunwind.h>
#include <libunwind-ptrace.h>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include "BacktraceLog.h"
#include "UnwindMap.h"
#include "UnwindPtrace.h"
UnwindPtrace::UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map)
: BacktracePtrace(pid, tid, map), addr_space_(nullptr), upt_info_(nullptr) {
}
UnwindPtrace::~UnwindPtrace() {
if (upt_info_) {
_UPT_destroy(upt_info_);
upt_info_ = nullptr;
}
if (addr_space_) {
// Remove the map from the address space before destroying it.
// It will be freed in the UnwindMap destructor.
unw_map_set(addr_space_, nullptr);
unw_destroy_addr_space(addr_space_);
addr_space_ = nullptr;
}
}
bool UnwindPtrace::Unwind(size_t num_ignore_frames, ucontext_t* ucontext) {
if (GetMap() == nullptr) {
// Without a map object, we can't do anything.
error_ = BACKTRACE_UNWIND_ERROR_MAP_MISSING;
return false;
}
error_ = BACKTRACE_UNWIND_NO_ERROR;
if (ucontext) {
BACK_LOGW("Unwinding from a specified context not supported yet.");
error_ = BACKTRACE_UNWIND_ERROR_UNSUPPORTED_OPERATION;
return false;
}
addr_space_ = unw_create_addr_space(&_UPT_accessors, 0);
if (!addr_space_) {
BACK_LOGW("unw_create_addr_space failed.");
error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
return false;
}
UnwindMap* map = static_cast<UnwindMap*>(GetMap());
unw_map_set(addr_space_, map->GetMapCursor());
upt_info_ = reinterpret_cast<struct UPT_info*>(_UPT_create(Tid()));
if (!upt_info_) {
BACK_LOGW("Failed to create upt info.");
error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
return false;
}
unw_cursor_t cursor;
int ret = unw_init_remote(&cursor, addr_space_, upt_info_);
if (ret < 0) {
BACK_LOGW("unw_init_remote failed %d", ret);
error_ = BACKTRACE_UNWIND_ERROR_SETUP_FAILED;
return false;
}
size_t num_frames = 0;
do {
unw_word_t pc;
ret = unw_get_reg(&cursor, UNW_REG_IP, &pc);
if (ret < 0) {
BACK_LOGW("Failed to read IP %d", ret);
break;
}
unw_word_t sp;
ret = unw_get_reg(&cursor, UNW_REG_SP, &sp);
if (ret < 0) {
BACK_LOGW("Failed to read SP %d", ret);
break;
}
if (num_ignore_frames == 0) {
frames_.resize(num_frames+1);
backtrace_frame_data_t* frame = &frames_.at(num_frames);
frame->num = num_frames;
frame->pc = static_cast<uintptr_t>(pc);
frame->sp = static_cast<uintptr_t>(sp);
frame->stack_size = 0;
if (num_frames > 0) {
backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
prev->stack_size = frame->sp - prev->sp;
}
frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
FillInMap(frame->pc, &frame->map);
num_frames++;
} else {
num_ignore_frames--;
}
ret = unw_step (&cursor);
} while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
return true;
}
std::string UnwindPtrace::GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) {
*offset = 0;
char buf[512];
unw_word_t value;
if (unw_get_proc_name_by_ip(addr_space_, pc, buf, sizeof(buf), &value,
upt_info_) >= 0 && buf[0] != '\0') {
*offset = static_cast<uintptr_t>(value);
return buf;
}
return "";
}

View File

@@ -1,46 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBBACKTRACE_UNWIND_PTRACE_H
#define _LIBBACKTRACE_UNWIND_PTRACE_H
#include <stdint.h>
#include <sys/types.h>
#include <string>
#ifdef UNW_LOCAL_ONLY
#undef UNW_LOCAL_ONLY
#endif
#include <libunwind.h>
#include "BacktracePtrace.h"
class UnwindPtrace : public BacktracePtrace {
public:
UnwindPtrace(pid_t pid, pid_t tid, BacktraceMap* map);
virtual ~UnwindPtrace();
bool Unwind(size_t num_ignore_frames, ucontext_t* ucontext) override;
std::string GetFunctionNameRaw(uintptr_t pc, uintptr_t* offset) override;
private:
unw_addr_space_t addr_space_;
struct UPT_info* upt_info_;
};
#endif // _LIBBACKTRACE_UNWIND_PTRACE_H

View File

@@ -1,189 +0,0 @@
#include <libunwind.h>
#include <pthread.h>
#include <stdint.h>
#include <string.h>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
#include <cutils/threads.h>
#include <gtest/gtest.h>
extern "C" {
// Prototypes for functions in the test library.
int test_level_one(int, int, int, int, void (*)(void*), void*);
int test_level_two(int, int, int, int, void (*)(void*), void*);
int test_level_three(int, int, int, int, void (*)(void*), void*);
int test_level_four(int, int, int, int, void (*)(void*), void*);
int test_recursive_call(int, void (*)(void*), void*);
}
static volatile bool g_exit_flag = false;
static void GetContextAndExit(void* arg) {
unw_context_t* unw_context = reinterpret_cast<unw_context_t*>(arg);
unw_getcontext(unw_context);
// Don't touch the stack anymore.
while (!g_exit_flag) {
}
}
struct OfflineThreadArg {
unw_context_t unw_context;
pid_t tid;
std::function<int(void (*)(void*), void*)> function;
};
static void* OfflineThreadFunc(void* arg) {
OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(arg);
fn_arg->tid = gettid();
fn_arg->function(GetContextAndExit, &fn_arg->unw_context);
return nullptr;
}
static ucontext_t GetUContextFromUnwContext(const unw_context_t& unw_context) {
ucontext_t ucontext;
memset(&ucontext, 0, sizeof(ucontext));
#if defined(__arm__)
ucontext.uc_mcontext.arm_r0 = unw_context.regs[0];
ucontext.uc_mcontext.arm_r1 = unw_context.regs[1];
ucontext.uc_mcontext.arm_r2 = unw_context.regs[2];
ucontext.uc_mcontext.arm_r3 = unw_context.regs[3];
ucontext.uc_mcontext.arm_r4 = unw_context.regs[4];
ucontext.uc_mcontext.arm_r5 = unw_context.regs[5];
ucontext.uc_mcontext.arm_r6 = unw_context.regs[6];
ucontext.uc_mcontext.arm_r7 = unw_context.regs[7];
ucontext.uc_mcontext.arm_r8 = unw_context.regs[8];
ucontext.uc_mcontext.arm_r9 = unw_context.regs[9];
ucontext.uc_mcontext.arm_r10 = unw_context.regs[10];
ucontext.uc_mcontext.arm_fp = unw_context.regs[11];
ucontext.uc_mcontext.arm_ip = unw_context.regs[12];
ucontext.uc_mcontext.arm_sp = unw_context.regs[13];
ucontext.uc_mcontext.arm_lr = unw_context.regs[14];
ucontext.uc_mcontext.arm_pc = unw_context.regs[15];
#else
ucontext.uc_mcontext = unw_context.uc_mcontext;
#endif
return ucontext;
}
static void OfflineBacktraceFunctionCall(std::function<int(void (*)(void*), void*)> function,
std::vector<uintptr_t>* pc_values) {
// Create a thread to generate the needed stack and registers information.
g_exit_flag = false;
const size_t stack_size = 1024 * 1024;
void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
ASSERT_NE(MAP_FAILED, stack);
uintptr_t stack_addr = reinterpret_cast<uintptr_t>(stack);
pthread_attr_t attr;
ASSERT_EQ(0, pthread_attr_init(&attr));
ASSERT_EQ(0, pthread_attr_setstack(&attr, reinterpret_cast<void*>(stack), stack_size));
pthread_t thread;
OfflineThreadArg arg;
arg.function = function;
ASSERT_EQ(0, pthread_create(&thread, &attr, OfflineThreadFunc, &arg));
// Wait for the offline thread to generate the stack and unw_context information.
sleep(1);
// Copy the stack information.
std::vector<uint8_t> stack_data(reinterpret_cast<uint8_t*>(stack),
reinterpret_cast<uint8_t*>(stack) + stack_size);
g_exit_flag = true;
ASSERT_EQ(0, pthread_join(thread, nullptr));
ASSERT_EQ(0, munmap(stack, stack_size));
// Do offline backtrace.
std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(getpid()));
ASSERT_TRUE(map != nullptr);
backtrace_stackinfo_t stack_info;
stack_info.start = stack_addr;
stack_info.end = stack_addr + stack_size;
stack_info.data = stack_data.data();
std::unique_ptr<Backtrace> backtrace(
Backtrace::CreateOffline(getpid(), arg.tid, map.get(), stack_info));
ASSERT_TRUE(backtrace != nullptr);
ucontext_t ucontext = GetUContextFromUnwContext(arg.unw_context);
ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
// Collect pc values of the call stack frames.
for (size_t i = 0; i < backtrace->NumFrames(); ++i) {
pc_values->push_back(backtrace->GetFrame(i)->pc);
}
}
// Return the name of the function which matches the address. Although we don't know the
// exact end of each function, it is accurate enough for the tests.
static std::string FunctionNameForAddress(uintptr_t addr) {
struct FunctionSymbol {
std::string name;
uintptr_t start;
uintptr_t end;
};
static std::vector<FunctionSymbol> symbols;
if (symbols.empty()) {
symbols = std::vector<FunctionSymbol>{
{"unknown_start", 0, 0},
{"test_level_one", reinterpret_cast<uintptr_t>(&test_level_one), 0},
{"test_level_two", reinterpret_cast<uintptr_t>(&test_level_two), 0},
{"test_level_three", reinterpret_cast<uintptr_t>(&test_level_three), 0},
{"test_level_four", reinterpret_cast<uintptr_t>(&test_level_four), 0},
{"test_recursive_call", reinterpret_cast<uintptr_t>(&test_recursive_call), 0},
{"GetContextAndExit", reinterpret_cast<uintptr_t>(&GetContextAndExit), 0},
{"unknown_end", static_cast<uintptr_t>(-1), static_cast<uintptr_t>(-1)},
};
std::sort(
symbols.begin(), symbols.end(),
[](const FunctionSymbol& s1, const FunctionSymbol& s2) { return s1.start < s2.start; });
for (size_t i = 0; i + 1 < symbols.size(); ++i) {
symbols[i].end = symbols[i + 1].start;
}
}
for (auto& symbol : symbols) {
if (addr >= symbol.start && addr < symbol.end) {
return symbol.name;
}
}
return "";
}
TEST(libbacktrace, offline) {
std::function<int(void (*)(void*), void*)> function =
std::bind(test_level_one, 1, 2, 3, 4, std::placeholders::_1, std::placeholders::_2);
std::vector<uintptr_t> pc_values;
OfflineBacktraceFunctionCall(function, &pc_values);
ASSERT_FALSE(pc_values.empty());
ASSERT_LE(pc_values.size(), static_cast<size_t>(MAX_BACKTRACE_FRAMES));
size_t test_one_index = 0;
for (size_t i = 0; i < pc_values.size(); ++i) {
if (FunctionNameForAddress(pc_values[i]) == "test_level_one") {
test_one_index = i;
break;
}
}
ASSERT_GE(test_one_index, 3u);
ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index]));
ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1]));
ASSERT_EQ("test_level_three", FunctionNameForAddress(pc_values[test_one_index - 2]));
ASSERT_EQ("test_level_four", FunctionNameForAddress(pc_values[test_one_index - 3]));
}
TEST(libbacktrace, offline_max_trace) {
std::function<int(void (*)(void*), void*)> function = std::bind(
test_recursive_call, MAX_BACKTRACE_FRAMES + 10, std::placeholders::_1, std::placeholders::_2);
std::vector<uintptr_t> pc_values;
OfflineBacktraceFunctionCall(function, &pc_values);
ASSERT_FALSE(pc_values.empty());
ASSERT_EQ(static_cast<size_t>(MAX_BACKTRACE_FRAMES), pc_values.size());
ASSERT_EQ("test_recursive_call", FunctionNameForAddress(pc_values.back()));
}

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,55 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
int test_level_four(int one, int two, int three, int four,
void (*callback_func)(void*), void* data) {
if (callback_func != NULL) {
callback_func(data);
} else {
while (1) {
}
}
return one + two + three + four;
}
int test_level_three(int one, int two, int three, int four,
void (*callback_func)(void*), void* data) {
return test_level_four(one+3, two+6, three+9, four+12, callback_func, data) + 3;
}
int test_level_two(int one, int two, int three, int four,
void (*callback_func)(void*), void* data) {
return test_level_three(one+2, two+4, three+6, four+8, callback_func, data) + 2;
}
int test_level_one(int one, int two, int three, int four,
void (*callback_func)(void*), void* data) {
return test_level_two(one+1, two+2, three+3, four+4, callback_func, data) + 1;
}
int test_recursive_call(int level, void (*callback_func)(void*), void* data) {
if (level > 0) {
return test_recursive_call(level - 1, callback_func, data) + level;
} else if (callback_func != NULL) {
callback_func(data);
} else {
while (1) {
}
}
return 0;
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "thread_utils.h"
#if !defined(__BIONIC__)
// glibc doesn't implement or export tgkill.
#include <unistd.h>
#include <sys/syscall.h>
int tgkill(int tgid, int tid, int sig) {
return syscall(__NR_tgkill, tgid, tid, sig);
}
#endif

View File

@@ -1,32 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef _LIBBACKTRACE_THREAD_UTILS_H
#define _LIBBACKTRACE_THREAD_UTILS_H
#include <unistd.h>
#if !defined(__ANDROID__)
#include <cutils/threads.h>
#endif
__BEGIN_DECLS
int tgkill(int tgid, int tid, int sig);
__END_DECLS
#endif /* _LIBBACKTRACE_THREAD_UTILS_H */

View File

@@ -1,11 +0,0 @@
BasedOnStyle: Google
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
IndentWidth: 2
PointerAlignment: Left
TabWidth: 2
UseTab: Never
PenaltyExcessCharacter: 32

View File

@@ -1,59 +0,0 @@
#
# Copyright (C) 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
LOCAL_PATH := $(call my-dir)
libbase_src_files := \
file.cpp \
logging.cpp \
parsenetaddress.cpp \
stringprintf.cpp \
strings.cpp \
test_utils.cpp \
libbase_cppflags := \
-Wall \
-Wextra \
-Werror \
libbase_linux_cppflags := \
-Wexit-time-destructors \
libbase_darwin_cppflags := \
-Wexit-time-destructors \
# Device
# ------------------------------------------------------------------------------
include $(CLEAR_VARS)
LOCAL_MODULE := libcrashdumpbase_static
LOCAL_CLANG := true
LOCAL_SRC_FILES := $(libbase_src_files) $(libbase_linux_src_files)
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_CPPFLAGS := $(libbase_cppflags) $(libbase_linux_cppflags)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_LDLIBS := -llog
LOCAL_MULTILIB := both
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libcrashdumpbase
LOCAL_CLANG := true
LOCAL_WHOLE_STATIC_LIBRARIES := libcrashdumpbase_static
LOCAL_LDLIBS := -llog
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_MULTILIB := both
include $(BUILD_SHARED_LIBRARY)

View File

@@ -1,2 +0,0 @@
set noparent
filter=-build/header_guard,-build/include,-build/c++11,-whitespace/operators

View File

@@ -1,34 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/errors.h"
#include <gtest/gtest.h>
namespace android {
namespace base {
// Error strings aren't consistent enough across systems to test the output,
// just make sure we can compile correctly and nothing crashes even if we send
// it possibly bogus error codes.
TEST(ErrorsTest, TestSystemErrorString) {
SystemErrorCodeToString(-1);
SystemErrorCodeToString(0);
SystemErrorCodeToString(1);
}
} // namespace base
} // namespace android

View File

@@ -1,29 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/errors.h"
#include <errno.h>
namespace android {
namespace base {
std::string SystemErrorCodeToString(int error_code) {
return strerror(error_code);
}
} // namespace base
} // namespace android

View File

@@ -1,68 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/errors.h"
#include <windows.h>
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
#include "android-base/utf8.h"
// A Windows error code is a DWORD. It's simpler to use an int error code for
// both Unix and Windows if possible, but if this fails we'll need a different
// function signature for each.
static_assert(sizeof(int) >= sizeof(DWORD),
"Windows system error codes are too large to fit in an int.");
namespace android {
namespace base {
static constexpr DWORD kErrorMessageBufferSize = 256;
std::string SystemErrorCodeToString(int int_error_code) {
WCHAR msgbuf[kErrorMessageBufferSize];
DWORD error_code = int_error_code;
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
DWORD len = FormatMessageW(flags, nullptr, error_code, 0, msgbuf,
kErrorMessageBufferSize, nullptr);
if (len == 0) {
return android::base::StringPrintf(
"Error %lu while retrieving message for error %lu", GetLastError(),
error_code);
}
// Convert UTF-16 to UTF-8.
std::string msg;
if (!android::base::WideToUTF8(msgbuf, &msg)) {
return android::base::StringPrintf(
"Error %lu while converting message for error %lu from UTF-16 to UTF-8",
GetLastError(), error_code);
}
// Messages returned by the system end with line breaks.
msg = android::base::Trim(msg);
// There are many Windows error messages compared to POSIX, so include the
// numeric error code for easier, quicker, accurate identification. Use
// decimal instead of hex because there are decimal ranges like 10000-11999
// for Winsock.
android::base::StringAppendF(&msg, " (%lu)", error_code);
return msg;
}
} // namespace base
} // namespace android

View File

@@ -1,176 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/file.h"
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string>
#include "android-base/macros.h" // For TEMP_FAILURE_RETRY on Darwin.
#include "android-base/utf8.h"
#define LOG_TAG "base.file"
#include "cutils/log.h"
#include "utils/Compat.h"
namespace android {
namespace base {
// Versions of standard library APIs that support UTF-8 strings.
using namespace android::base::utf8;
bool ReadFdToString(int fd, std::string* content) {
content->clear();
char buf[BUFSIZ];
ssize_t n;
while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) {
content->append(buf, n);
}
return (n == 0) ? true : false;
}
bool ReadFileToString(const std::string& path, std::string* content) {
content->clear();
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_BINARY));
if (fd == -1) {
return false;
}
bool result = ReadFdToString(fd, content);
close(fd);
return result;
}
bool WriteStringToFd(const std::string& content, int fd) {
const char* p = content.data();
size_t left = content.size();
while (left > 0) {
ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, left));
if (n == -1) {
return false;
}
p += n;
left -= n;
}
return true;
}
static bool CleanUpAfterFailedWrite(const std::string& path) {
// Something went wrong. Let's not leave a corrupt file lying around.
int saved_errno = errno;
unlink(path.c_str());
errno = saved_errno;
return false;
}
#if !defined(_WIN32)
bool WriteStringToFile(const std::string& content, const std::string& path,
mode_t mode, uid_t owner, gid_t group) {
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, mode));
if (fd == -1) {
ALOGE("android::WriteStringToFile open failed: %s", strerror(errno));
return false;
}
// We do an explicit fchmod here because we assume that the caller really
// meant what they said and doesn't want the umask-influenced mode.
if (fchmod(fd, mode) == -1) {
ALOGE("android::WriteStringToFile fchmod failed: %s", strerror(errno));
return CleanUpAfterFailedWrite(path);
}
if (fchown(fd, owner, group) == -1) {
ALOGE("android::WriteStringToFile fchown failed: %s", strerror(errno));
return CleanUpAfterFailedWrite(path);
}
if (!WriteStringToFd(content, fd)) {
ALOGE("android::WriteStringToFile write failed: %s", strerror(errno));
return CleanUpAfterFailedWrite(path);
}
close(fd);
return true;
}
#endif
bool WriteStringToFile(const std::string& content, const std::string& path) {
int flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_BINARY;
int fd = TEMP_FAILURE_RETRY(open(path.c_str(), flags, DEFFILEMODE));
if (fd == -1) {
return false;
}
bool result = WriteStringToFd(content, fd);
close(fd);
return result || CleanUpAfterFailedWrite(path);
}
bool ReadFully(int fd, void* data, size_t byte_count) {
uint8_t* p = reinterpret_cast<uint8_t*>(data);
size_t remaining = byte_count;
while (remaining > 0) {
ssize_t n = TEMP_FAILURE_RETRY(read(fd, p, remaining));
if (n <= 0) return false;
p += n;
remaining -= n;
}
return true;
}
bool WriteFully(int fd, const void* data, size_t byte_count) {
const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
size_t remaining = byte_count;
while (remaining > 0) {
ssize_t n = TEMP_FAILURE_RETRY(write(fd, p, remaining));
if (n == -1) return false;
p += n;
remaining -= n;
}
return true;
}
bool RemoveFileIfExists(const std::string& path, std::string* err) {
struct stat st;
#if defined(_WIN32)
//TODO: Windows version can't handle symbol link correctly.
int result = stat(path.c_str(), &st);
bool file_type_removable = (result == 0 && S_ISREG(st.st_mode));
#else
int result = lstat(path.c_str(), &st);
bool file_type_removable = (result == 0 && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)));
#endif
if (result == 0) {
if (!file_type_removable) {
if (err != nullptr) {
*err = "is not a regular or symbol link file";
}
return false;
}
if (unlink(path.c_str()) == -1) {
if (err != nullptr) {
*err = strerror(errno);
}
return false;
}
}
return true;
}
} // namespace base
} // namespace android

View File

@@ -1,112 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/file.h"
#include <gtest/gtest.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <string>
#include "android-base/test_utils.h"
TEST(file, ReadFileToString_ENOENT) {
std::string s("hello");
errno = 0;
ASSERT_FALSE(android::base::ReadFileToString("/proc/does-not-exist", &s));
EXPECT_EQ(ENOENT, errno);
EXPECT_EQ("", s); // s was cleared.
}
TEST(file, ReadFileToString_WriteStringToFile) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path))
<< strerror(errno);
std::string s;
ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
<< strerror(errno);
EXPECT_EQ("abc", s);
}
// WriteStringToFile2 is explicitly for setting Unix permissions, which make no
// sense on Windows.
#if !defined(_WIN32)
TEST(file, WriteStringToFile2) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteStringToFile("abc", tf.path, 0660,
getuid(), getgid()))
<< strerror(errno);
struct stat sb;
ASSERT_EQ(0, stat(tf.path, &sb));
ASSERT_EQ(0660U, static_cast<unsigned int>(sb.st_mode & ~S_IFMT));
ASSERT_EQ(getuid(), sb.st_uid);
ASSERT_EQ(getgid(), sb.st_gid);
std::string s;
ASSERT_TRUE(android::base::ReadFileToString(tf.path, &s))
<< strerror(errno);
EXPECT_EQ("abc", s);
}
#endif
TEST(file, WriteStringToFd) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteStringToFd("abc", tf.fd));
ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
std::string s;
ASSERT_TRUE(android::base::ReadFdToString(tf.fd, &s)) << strerror(errno);
EXPECT_EQ("abc", s);
}
TEST(file, WriteFully) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
ASSERT_TRUE(android::base::WriteFully(tf.fd, "abc", 3));
ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
std::string s;
s.resize(3);
ASSERT_TRUE(android::base::ReadFully(tf.fd, &s[0], s.size()))
<< strerror(errno);
EXPECT_EQ("abc", s);
ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)) << strerror(errno);
s.resize(1024);
ASSERT_FALSE(android::base::ReadFully(tf.fd, &s[0], s.size()));
}
TEST(file, RemoveFileIfExist) {
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
close(tf.fd);
tf.fd = -1;
std::string err;
ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path, &err)) << err;
ASSERT_TRUE(android::base::RemoveFileIfExists(tf.path));
TemporaryDir td;
ASSERT_FALSE(android::base::RemoveFileIfExists(td.path));
ASSERT_FALSE(android::base::RemoveFileIfExists(td.path, &err));
ASSERT_EQ("is not a regular or symbol link file", err);
}

View File

@@ -1,46 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Portable error handling functions. This is only necessary for host-side
// code that needs to be cross-platform; code that is only run on Unix should
// just use errno and strerror() for simplicity.
//
// There is some complexity since Windows has (at least) three different error
// numbers, not all of which share the same type:
// * errno: for C runtime errors.
// * GetLastError(): Windows non-socket errors.
// * WSAGetLastError(): Windows socket errors.
// errno can be passed to strerror() on all platforms, but the other two require
// special handling to get the error string. Refer to Microsoft documentation
// to determine which error code to check for each function.
#ifndef ANDROID_BASE_ERRORS_H
#define ANDROID_BASE_ERRORS_H
#include <string>
namespace android {
namespace base {
// Returns a string describing the given system error code. |error_code| must
// be errno on Unix or GetLastError()/WSAGetLastError() on Windows. Passing
// errno on Windows has undefined behavior.
std::string SystemErrorCodeToString(int error_code);
} // namespace base
} // namespace android
#endif // ANDROID_BASE_ERRORS_H

View File

@@ -1,49 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_BASE_FILE_H
#define ANDROID_BASE_FILE_H
#include <sys/stat.h>
#include <string>
#if !defined(_WIN32) && !defined(O_BINARY)
#define O_BINARY 0
#endif
namespace android {
namespace base {
bool ReadFdToString(int fd, std::string* content);
bool ReadFileToString(const std::string& path, std::string* content);
bool WriteStringToFile(const std::string& content, const std::string& path);
bool WriteStringToFd(const std::string& content, int fd);
#if !defined(_WIN32)
bool WriteStringToFile(const std::string& content, const std::string& path,
mode_t mode, uid_t owner, gid_t group);
#endif
bool ReadFully(int fd, void* data, size_t byte_count);
bool WriteFully(int fd, const void* data, size_t byte_count);
bool RemoveFileIfExists(const std::string& path, std::string* err = nullptr);
} // namespace base
} // namespace android
#endif // ANDROID_BASE_FILE_H

View File

@@ -1,338 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_BASE_LOGGING_H
#define ANDROID_BASE_LOGGING_H
// NOTE: For Windows, you must include logging.h after windows.h to allow the
// following code to suppress the evil ERROR macro:
#ifdef _WIN32
// windows.h includes wingdi.h which defines an evil macro ERROR.
#ifdef ERROR
#undef ERROR
#endif
#endif
#include <functional>
#include <memory>
#include <ostream>
#include "android-base/macros.h"
namespace android {
namespace base {
enum LogSeverity {
VERBOSE,
DEBUG,
INFO,
WARNING,
ERROR,
FATAL,
};
enum LogId {
DEFAULT,
MAIN,
SYSTEM,
};
typedef std::function<void(LogId, LogSeverity, const char*, const char*,
unsigned int, const char*)> LogFunction;
extern void StderrLogger(LogId, LogSeverity, const char*, const char*,
unsigned int, const char*);
#ifdef __ANDROID__
// We expose this even though it is the default because a user that wants to
// override the default log buffer will have to construct this themselves.
class LogdLogger {
public:
explicit LogdLogger(LogId default_log_id = android::base::MAIN);
void operator()(LogId, LogSeverity, const char* tag, const char* file,
unsigned int line, const char* message);
private:
LogId default_log_id_;
};
#endif
// Configure logging based on ANDROID_LOG_TAGS environment variable.
// We need to parse a string that looks like
//
// *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i
//
// The tag (or '*' for the global level) comes first, followed by a colon and a
// letter indicating the minimum priority level we're expected to log. This can
// be used to reveal or conceal logs with specific tags.
extern void InitLogging(char* argv[], LogFunction&& logger);
// Configures logging using the default logger (logd for the device, stderr for
// the host).
extern void InitLogging(char* argv[]);
// Replace the current logger.
extern void SetLogger(LogFunction&& logger);
// Get the minimum severity level for logging.
extern LogSeverity GetMinimumLogSeverity();
class ErrnoRestorer {
public:
ErrnoRestorer()
: saved_errno_(errno) {
}
~ErrnoRestorer() {
errno = saved_errno_;
}
// Allow this object to be used as part of && operation.
operator bool() const {
return true;
}
private:
const int saved_errno_;
DISALLOW_COPY_AND_ASSIGN(ErrnoRestorer);
};
// Logs a message to logcat on Android otherwise to stderr. If the severity is
// FATAL it also causes an abort. For example:
//
// LOG(FATAL) << "We didn't expect to reach here";
#define LOG(severity) LOG_TO(DEFAULT, severity)
// Logs a message to logcat with the specified log ID on Android otherwise to
// stderr. If the severity is FATAL it also causes an abort.
// Use an if-else statement instead of just an if statement here. So if there is a
// else statement after LOG() macro, it won't bind to the if statement in the macro.
// do-while(0) statement doesn't work here. Because we need to support << operator
// following the macro, like "LOG(DEBUG) << xxx;".
#define LOG_TO(dest, severity) \
UNLIKELY(::android::base::severity >= ::android::base::GetMinimumLogSeverity()) && \
::android::base::ErrnoRestorer() && \
::android::base::LogMessage(__FILE__, __LINE__, \
::android::base::dest, \
::android::base::severity, -1).stream()
// A variant of LOG that also logs the current errno value. To be used when
// library calls fail.
#define PLOG(severity) PLOG_TO(DEFAULT, severity)
// Behaves like PLOG, but logs to the specified log ID.
#define PLOG_TO(dest, severity) \
UNLIKELY(::android::base::severity >= ::android::base::GetMinimumLogSeverity()) && \
::android::base::ErrnoRestorer() && \
::android::base::LogMessage(__FILE__, __LINE__, \
::android::base::dest, \
::android::base::severity, errno).stream()
// Marker that code is yet to be implemented.
#define UNIMPLEMENTED(level) \
LOG(level) << __PRETTY_FUNCTION__ << " unimplemented "
// Check whether condition x holds and LOG(FATAL) if not. The value of the
// expression x is only evaluated once. Extra logging can be appended using <<
// after. For example:
//
// CHECK(false == true) results in a log message of
// "Check failed: false == true".
#define CHECK(x) \
LIKELY((x)) || \
::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
::android::base::FATAL, -1).stream() \
<< "Check failed: " #x << " "
// Helper for CHECK_xx(x,y) macros.
#define CHECK_OP(LHS, RHS, OP) \
for (auto _values = ::android::base::MakeEagerEvaluator(LHS, RHS); \
UNLIKELY(!(_values.lhs OP _values.rhs)); \
/* empty */) \
::android::base::LogMessage(__FILE__, __LINE__, ::android::base::DEFAULT, \
::android::base::FATAL, -1).stream() \
<< "Check failed: " << #LHS << " " << #OP << " " << #RHS \
<< " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") "
// Check whether a condition holds between x and y, LOG(FATAL) if not. The value
// of the expressions x and y is evaluated once. Extra logging can be appended
// using << after. For example:
//
// CHECK_NE(0 == 1, false) results in
// "Check failed: false != false (0==1=false, false=false) ".
#define CHECK_EQ(x, y) CHECK_OP(x, y, == )
#define CHECK_NE(x, y) CHECK_OP(x, y, != )
#define CHECK_LE(x, y) CHECK_OP(x, y, <= )
#define CHECK_LT(x, y) CHECK_OP(x, y, < )
#define CHECK_GE(x, y) CHECK_OP(x, y, >= )
#define CHECK_GT(x, y) CHECK_OP(x, y, > )
// Helper for CHECK_STRxx(s1,s2) macros.
#define CHECK_STROP(s1, s2, sense) \
if (LIKELY((strcmp(s1, s2) == 0) == sense)) \
; \
else \
LOG(FATAL) << "Check failed: " \
<< "\"" << s1 << "\"" \
<< (sense ? " == " : " != ") << "\"" << s2 << "\""
// Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not.
#define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true)
#define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false)
// Perform the pthread function call(args), LOG(FATAL) on error.
#define CHECK_PTHREAD_CALL(call, args, what) \
do { \
int rc = call args; \
if (rc != 0) { \
errno = rc; \
PLOG(FATAL) << #call << " failed for " << what; \
} \
} while (false)
// CHECK that can be used in a constexpr function. For example:
//
// constexpr int half(int n) {
// return
// DCHECK_CONSTEXPR(n >= 0, , 0)
// CHECK_CONSTEXPR((n & 1) == 0),
// << "Extra debugging output: n = " << n, 0)
// n / 2;
// }
#define CHECK_CONSTEXPR(x, out, dummy) \
(UNLIKELY(!(x))) \
? (LOG(FATAL) << "Check failed: " << #x out, dummy) \
:
// DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally
// CHECK should be used unless profiling identifies a CHECK as being in
// performance critical code.
#if defined(NDEBUG)
static constexpr bool kEnableDChecks = false;
#else
static constexpr bool kEnableDChecks = true;
#endif
#define DCHECK(x) \
if (::android::base::kEnableDChecks) CHECK(x)
#define DCHECK_EQ(x, y) \
if (::android::base::kEnableDChecks) CHECK_EQ(x, y)
#define DCHECK_NE(x, y) \
if (::android::base::kEnableDChecks) CHECK_NE(x, y)
#define DCHECK_LE(x, y) \
if (::android::base::kEnableDChecks) CHECK_LE(x, y)
#define DCHECK_LT(x, y) \
if (::android::base::kEnableDChecks) CHECK_LT(x, y)
#define DCHECK_GE(x, y) \
if (::android::base::kEnableDChecks) CHECK_GE(x, y)
#define DCHECK_GT(x, y) \
if (::android::base::kEnableDChecks) CHECK_GT(x, y)
#define DCHECK_STREQ(s1, s2) \
if (::android::base::kEnableDChecks) CHECK_STREQ(s1, s2)
#define DCHECK_STRNE(s1, s2) \
if (::android::base::kEnableDChecks) CHECK_STRNE(s1, s2)
#if defined(NDEBUG)
#define DCHECK_CONSTEXPR(x, out, dummy)
#else
#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy)
#endif
// Temporary class created to evaluate the LHS and RHS, used with
// MakeEagerEvaluator to infer the types of LHS and RHS.
template <typename LHS, typename RHS>
struct EagerEvaluator {
EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) {
}
LHS lhs;
RHS rhs;
};
// Helper function for CHECK_xx.
template <typename LHS, typename RHS>
static inline EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) {
return EagerEvaluator<LHS, RHS>(lhs, rhs);
}
// Explicitly instantiate EagerEvalue for pointers so that char*s aren't treated
// as strings. To compare strings use CHECK_STREQ and CHECK_STRNE. We rely on
// signed/unsigned warnings to protect you against combinations not explicitly
// listed below.
#define EAGER_PTR_EVALUATOR(T1, T2) \
template <> \
struct EagerEvaluator<T1, T2> { \
EagerEvaluator(T1 l, T2 r) \
: lhs(reinterpret_cast<const void*>(l)), \
rhs(reinterpret_cast<const void*>(r)) { \
} \
const void* lhs; \
const void* rhs; \
}
EAGER_PTR_EVALUATOR(const char*, const char*);
EAGER_PTR_EVALUATOR(const char*, char*);
EAGER_PTR_EVALUATOR(char*, const char*);
EAGER_PTR_EVALUATOR(char*, char*);
EAGER_PTR_EVALUATOR(const unsigned char*, const unsigned char*);
EAGER_PTR_EVALUATOR(const unsigned char*, unsigned char*);
EAGER_PTR_EVALUATOR(unsigned char*, const unsigned char*);
EAGER_PTR_EVALUATOR(unsigned char*, unsigned char*);
EAGER_PTR_EVALUATOR(const signed char*, const signed char*);
EAGER_PTR_EVALUATOR(const signed char*, signed char*);
EAGER_PTR_EVALUATOR(signed char*, const signed char*);
EAGER_PTR_EVALUATOR(signed char*, signed char*);
// Data for the log message, not stored in LogMessage to avoid increasing the
// stack size.
class LogMessageData;
// A LogMessage is a temporarily scoped object used by LOG and the unlikely part
// of a CHECK. The destructor will abort if the severity is FATAL.
class LogMessage {
public:
LogMessage(const char* file, unsigned int line, LogId id,
LogSeverity severity, int error);
~LogMessage();
// Returns the stream associated with the message, the LogMessage performs
// output when it goes out of scope.
std::ostream& stream();
// The routine that performs the actual logging.
static void LogLine(const char* file, unsigned int line, LogId id,
LogSeverity severity, const char* msg);
private:
const std::unique_ptr<LogMessageData> data_;
DISALLOW_COPY_AND_ASSIGN(LogMessage);
};
// Allows to temporarily change the minimum severity level for logging.
class ScopedLogSeverity {
public:
explicit ScopedLogSeverity(LogSeverity level);
~ScopedLogSeverity();
private:
LogSeverity old_;
};
} // namespace base
} // namespace android
#endif // ANDROID_BASE_LOGGING_H

View File

@@ -1,188 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_BASE_MACROS_H
#define ANDROID_BASE_MACROS_H
#include <stddef.h> // for size_t
#include <unistd.h> // for TEMP_FAILURE_RETRY
// bionic and glibc both have TEMP_FAILURE_RETRY, but eg Mac OS' libc doesn't.
#ifndef TEMP_FAILURE_RETRY
#define TEMP_FAILURE_RETRY(exp) \
({ \
decltype(exp) _rc; \
do { \
_rc = (exp); \
} while (_rc == -1 && errno == EINTR); \
_rc; \
})
#endif
// A macro to disallow the copy constructor and operator= functions
// This must be placed in the private: declarations for a class.
//
// For disallowing only assign or copy, delete the relevant operator or
// constructor, for example:
// void operator=(const TypeName&) = delete;
// Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken
// semantically, one should either use disallow both or neither. Try to
// avoid these in new code.
//
// When building with C++11 toolchains, just use the language support
// for explicitly deleted methods.
#if __cplusplus >= 201103L
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
#else
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
#endif
// A macro to disallow all the implicit constructors, namely the
// default constructor, copy constructor and operator= functions.
//
// This should be used in the private: declarations for a class
// that wants to prevent anyone from instantiating it. This is
// especially useful for classes containing only static methods.
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
TypeName(); \
DISALLOW_COPY_AND_ASSIGN(TypeName)
// The arraysize(arr) macro returns the # of elements in an array arr.
// The expression is a compile-time constant, and therefore can be
// used in defining new arrays, for example. If you use arraysize on
// a pointer by mistake, you will get a compile-time error.
//
// One caveat is that arraysize() doesn't accept any array of an
// anonymous type or a type defined inside a function. In these rare
// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is
// due to a limitation in C++'s template system. The limitation might
// eventually be removed, but it hasn't happened yet.
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
// use its type.
template <typename T, size_t N>
char(&ArraySizeHelper(T(&array)[N]))[N]; // NOLINT(readability/casting)
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize,
// but can be used on anonymous types or types defined inside
// functions. It's less safe than arraysize as it accepts some
// (although not all) pointers. Therefore, you should use arraysize
// whenever possible.
//
// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type
// size_t.
//
// ARRAYSIZE_UNSAFE catches a few type errors. If you see a compiler error
//
// "warning: division by zero in ..."
//
// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer.
// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays.
//
// The following comments are on the implementation details, and can
// be ignored by the users.
//
// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in
// the array) and sizeof(*(arr)) (the # of bytes in one array
// element). If the former is divisible by the latter, perhaps arr is
// indeed an array, in which case the division result is the # of
// elements in the array. Otherwise, arr cannot possibly be an array,
// and we generate a compiler error to prevent the code from
// compiling.
//
// Since the size of bool is implementation-defined, we need to cast
// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
// result has type size_t.
//
// This macro is not perfect as it wrongfully accepts certain
// pointers, namely where the pointer size is divisible by the pointee
// size. Since all our code has to go through a 32-bit compiler,
// where a pointer is 4 bytes, this means all pointers to a type whose
// size is 3 or greater than 4 will be (righteously) rejected.
#define ARRAYSIZE_UNSAFE(a) \
((sizeof(a) / sizeof(*(a))) / \
static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
#define LIKELY(x) __builtin_expect((x), true)
#define UNLIKELY(x) __builtin_expect((x), false)
#define WARN_UNUSED __attribute__((warn_unused_result))
// A deprecated function to call to create a false use of the parameter, for
// example:
// int foo(int x) { UNUSED(x); return 10; }
// to avoid compiler warnings. Going forward we prefer ATTRIBUTE_UNUSED.
template <typename... T>
void UNUSED(const T&...) {
}
// An attribute to place on a parameter to a function, for example:
// int foo(int x ATTRIBUTE_UNUSED) { return 10; }
// to avoid compiler warnings.
#define ATTRIBUTE_UNUSED __attribute__((__unused__))
// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through
// between switch labels:
// switch (x) {
// case 40:
// case 41:
// if (truth_is_out_there) {
// ++x;
// FALLTHROUGH_INTENDED; // Use instead of/along with annotations in
// // comments.
// } else {
// return x;
// }
// case 42:
// ...
//
// As shown in the example above, the FALLTHROUGH_INTENDED macro should be
// followed by a semicolon. It is designed to mimic control-flow statements
// like 'break;', so it can be placed in most places where 'break;' can, but
// only if there are no statements on the execution path between it and the
// next switch label.
//
// When compiled with clang in C++11 mode, the FALLTHROUGH_INTENDED macro is
// expanded to [[clang::fallthrough]] attribute, which is analysed when
// performing switch labels fall-through diagnostic ('-Wimplicit-fallthrough').
// See clang documentation on language extensions for details:
// http://clang.llvm.org/docs/LanguageExtensions.html#clang__fallthrough
//
// When used with unsupported compilers, the FALLTHROUGH_INTENDED macro has no
// effect on diagnostics.
//
// In either case this macro has no effect on runtime behavior and performance
// of code.
#if defined(__clang__) && __cplusplus >= 201103L && defined(__has_warning)
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
#define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT
#endif
#endif
#ifndef FALLTHROUGH_INTENDED
#define FALLTHROUGH_INTENDED \
do { \
} while (0)
#endif
#endif // ANDROID_BASE_MACROS_H

View File

@@ -1,47 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_BASE_MEMORY_H
#define ANDROID_BASE_MEMORY_H
namespace android {
namespace base {
// Use packed structures for access to unaligned data on targets with alignment
// restrictions. The compiler will generate appropriate code to access these
// structures without generating alignment exceptions.
template <typename T>
static inline T get_unaligned(const T* address) {
struct unaligned {
T v;
} __attribute__((packed));
const unaligned* p = reinterpret_cast<const unaligned*>(address);
return p->v;
}
template <typename T>
static inline void put_unaligned(T* address, T v) {
struct unaligned {
T v;
} __attribute__((packed));
unaligned* p = reinterpret_cast<unaligned*>(address);
p->v = v;
}
} // namespace base
} // namespace android
#endif // ANDROID_BASE_MEMORY_H

View File

@@ -1,73 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_BASE_PARSEINT_H
#define ANDROID_BASE_PARSEINT_H
#include <errno.h>
#include <stdlib.h>
#include <limits>
namespace android {
namespace base {
// Parses the unsigned decimal integer in the string 's' and sets 'out' to
// that value. Optionally allows the caller to define a 'max' beyond which
// otherwise valid values will be rejected. Returns boolean success.
template <typename T>
bool ParseUint(const char* s, T* out,
T max = std::numeric_limits<T>::max()) {
int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
errno = 0;
char* end;
unsigned long long int result = strtoull(s, &end, base);
if (errno != 0 || s == end || *end != '\0') {
return false;
}
if (max < result) {
return false;
}
*out = static_cast<T>(result);
return true;
}
// Parses the signed decimal integer in the string 's' and sets 'out' to
// that value. Optionally allows the caller to define a 'min' and 'max
// beyond which otherwise valid values will be rejected. Returns boolean
// success.
template <typename T>
bool ParseInt(const char* s, T* out,
T min = std::numeric_limits<T>::min(),
T max = std::numeric_limits<T>::max()) {
int base = (s[0] == '0' && s[1] == 'x') ? 16 : 10;
errno = 0;
char* end;
long long int result = strtoll(s, &end, base);
if (errno != 0 || s == end || *end != '\0') {
return false;
}
if (result < min || max < result) {
return false;
}
*out = static_cast<T>(result);
return true;
}
} // namespace base
} // namespace android
#endif // ANDROID_BASE_PARSEINT_H

View File

@@ -1,38 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_BASE_PARSENETADDRESS_H
#define ANDROID_BASE_PARSENETADDRESS_H
#include <string>
namespace android {
namespace base {
// Parses |address| into |host| and |port|.
//
// If |address| doesn't contain a port number, the default value is taken from
// |port|. If |canonical_address| is non-null it will be set to "host:port" or
// "[host]:port" as appropriate.
//
// On failure, returns false and fills |error|.
bool ParseNetAddress(const std::string& address, std::string* host, int* port,
std::string* canonical_address, std::string* error);
} // namespace base
} // namespace android
#endif // ANDROID_BASE_PARSENETADDRESS_H

View File

@@ -1,56 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_BASE_STRINGPRINTF_H
#define ANDROID_BASE_STRINGPRINTF_H
#include <stdarg.h>
#include <string>
namespace android {
namespace base {
// These printf-like functions are implemented in terms of vsnprintf, so they
// use the same attribute for compile-time format string checking. On Windows,
// if the mingw version of vsnprintf is used, use `gnu_printf' which allows z
// in %zd and PRIu64 (and related) to be recognized by the compile-time
// checking.
#define FORMAT_ARCHETYPE __printf__
#ifdef __USE_MINGW_ANSI_STDIO
#if __USE_MINGW_ANSI_STDIO
#undef FORMAT_ARCHETYPE
#define FORMAT_ARCHETYPE gnu_printf
#endif
#endif
// Returns a string corresponding to printf-like formatting of the arguments.
std::string StringPrintf(const char* fmt, ...)
__attribute__((__format__(FORMAT_ARCHETYPE, 1, 2)));
// Appends a printf-like formatting of the arguments to 'dst'.
void StringAppendF(std::string* dst, const char* fmt, ...)
__attribute__((__format__(FORMAT_ARCHETYPE, 2, 3)));
// Appends a printf-like formatting of the arguments to 'dst'.
void StringAppendV(std::string* dst, const char* format, va_list ap)
__attribute__((__format__(FORMAT_ARCHETYPE, 2, 0)));
#undef FORMAT_ARCHETYPE
} // namespace base
} // namespace android
#endif // ANDROID_BASE_STRINGPRINTF_H

View File

@@ -1,68 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_BASE_STRINGS_H
#define ANDROID_BASE_STRINGS_H
#include <sstream>
#include <string>
#include <vector>
namespace android {
namespace base {
// Splits a string into a vector of strings.
//
// The string is split at each occurrence of a character in delimiters.
//
// The empty string is not a valid delimiter list.
std::vector<std::string> Split(const std::string& s,
const std::string& delimiters);
// Trims whitespace off both ends of the given string.
std::string Trim(const std::string& s);
// Joins a container of things into a single string, using the given separator.
template <typename ContainerT, typename SeparatorT>
std::string Join(const ContainerT& things, SeparatorT separator) {
if (things.empty()) {
return "";
}
std::ostringstream result;
result << *things.begin();
for (auto it = std::next(things.begin()); it != things.end(); ++it) {
result << separator << *it;
}
return result.str();
}
// We instantiate the common cases in strings.cpp.
extern template std::string Join(const std::vector<std::string>&, char);
extern template std::string Join(const std::vector<const char*>&, char);
extern template std::string Join(const std::vector<std::string>&, const std::string&);
extern template std::string Join(const std::vector<const char*>&, const std::string&);
// Tests whether 's' starts with 'prefix'.
bool StartsWith(const std::string& s, const char* prefix);
// Tests whether 's' ends with 'suffix'.
bool EndsWith(const std::string& s, const char* suffix);
} // namespace base
} // namespace android
#endif // ANDROID_BASE_STRINGS_H

View File

@@ -1,51 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_BASE_TEST_UTILS_H
#define ANDROID_BASE_TEST_UTILS_H
#include <string>
#include <android-base/macros.h>
class TemporaryFile {
public:
TemporaryFile();
~TemporaryFile();
int fd;
char path[1024];
private:
void init(const std::string& tmp_dir);
DISALLOW_COPY_AND_ASSIGN(TemporaryFile);
};
class TemporaryDir {
public:
TemporaryDir();
~TemporaryDir();
char path[1024];
private:
bool init(const std::string& tmp_dir);
DISALLOW_COPY_AND_ASSIGN(TemporaryDir);
};
#endif // ANDROID_BASE_TEST_UTILS_H

View File

@@ -1,83 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_BASE_THREAD_ANNOTATIONS_H
#define ANDROID_BASE_THREAD_ANNOTATIONS_H
#if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif
#define CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
#define SCOPED_CAPABILITY \
THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
#define GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#define PT_GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
#define ACQUIRED_BEFORE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
#define ACQUIRED_AFTER(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
#define REQUIRES(...) \
THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
#define REQUIRES_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
#define ACQUIRE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
#define ACQUIRE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
#define RELEASE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
#define RELEASE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
#define TRY_ACQUIRE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
#define TRY_ACQUIRE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
#define EXCLUDES(...) \
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
#define ASSERT_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
#define ASSERT_SHARED_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
#define RETURN_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
#endif // ANDROID_BASE_THREAD_ANNOTATIONS_H

View File

@@ -1,98 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_BASE_UNIQUE_FD_H
#define ANDROID_BASE_UNIQUE_FD_H
#include <unistd.h>
// DO NOT INCLUDE OTHER LIBBASE HEADERS!
// This file gets used in libbinder, and libbinder is used everywhere.
// Including other headers from libbase frequently results in inclusion of
// android-base/macros.h, which causes macro collisions.
// Container for a file descriptor that automatically closes the descriptor as
// it goes out of scope.
//
// unique_fd ufd(open("/some/path", "r"));
// if (ufd.get() == -1) return error;
//
// // Do something useful, possibly including 'return'.
//
// return 0; // Descriptor is closed for you.
//
// unique_fd is also known as ScopedFd/ScopedFD/scoped_fd; mentioned here to help
// you find this class if you're searching for one of those names.
namespace android {
namespace base {
struct DefaultCloser {
static void Close(int fd) {
// Even if close(2) fails with EINTR, the fd will have been closed.
// Using TEMP_FAILURE_RETRY will either lead to EBADF or closing someone
// else's fd.
// http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
::close(fd);
}
};
template <typename Closer>
class unique_fd_impl final {
public:
unique_fd_impl() : value_(-1) {}
explicit unique_fd_impl(int value) : value_(value) {}
~unique_fd_impl() { clear(); }
unique_fd_impl(unique_fd_impl&& other) : value_(other.release()) {}
unique_fd_impl& operator=(unique_fd_impl&& s) {
reset(s.release());
return *this;
}
void reset(int new_value) {
if (value_ != -1) {
Closer::Close(value_);
}
value_ = new_value;
}
void clear() {
reset(-1);
}
int get() const { return value_; }
operator int() const { return get(); }
int release() __attribute__((warn_unused_result)) {
int ret = value_;
value_ = -1;
return ret;
}
private:
int value_;
unique_fd_impl(const unique_fd_impl&);
void operator=(const unique_fd_impl&);
};
using unique_fd = unique_fd_impl<DefaultCloser>;
} // namespace base
} // namespace android
#endif // ANDROID_BASE_UNIQUE_FD_H

View File

@@ -1,87 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_BASE_UTF8_H
#define ANDROID_BASE_UTF8_H
#ifdef _WIN32
#include <string>
#else
// Bring in prototypes for standard APIs so that we can import them into the utf8 namespace.
#include <fcntl.h> // open
#include <unistd.h> // unlink
#endif
namespace android {
namespace base {
// Only available on Windows because this is only needed on Windows.
#ifdef _WIN32
// Convert size number of UTF-16 wchar_t's to UTF-8. Returns whether the
// conversion was done successfully.
bool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8);
// Convert a NULL-terminated string of UTF-16 characters to UTF-8. Returns
// whether the conversion was done successfully.
bool WideToUTF8(const wchar_t* utf16, std::string* utf8);
// Convert a UTF-16 std::wstring (including any embedded NULL characters) to
// UTF-8. Returns whether the conversion was done successfully.
bool WideToUTF8(const std::wstring& utf16, std::string* utf8);
// Convert size number of UTF-8 char's to UTF-16. Returns whether the conversion
// was done successfully.
bool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16);
// Convert a NULL-terminated string of UTF-8 characters to UTF-16. Returns
// whether the conversion was done successfully.
bool UTF8ToWide(const char* utf8, std::wstring* utf16);
// Convert a UTF-8 std::string (including any embedded NULL characters) to
// UTF-16. Returns whether the conversion was done successfully.
bool UTF8ToWide(const std::string& utf8, std::wstring* utf16);
#endif
// The functions in the utf8 namespace take UTF-8 strings. For Windows, these
// are wrappers, for non-Windows these just expose existing APIs. To call these
// functions, use:
//
// // anonymous namespace to avoid conflict with existing open(), unlink(), etc.
// namespace {
// // Import functions into anonymous namespace.
// using namespace android::base::utf8;
//
// void SomeFunction(const char* name) {
// int fd = open(name, ...); // Calls android::base::utf8::open().
// ...
// unlink(name); // Calls android::base::utf8::unlink().
// }
// }
namespace utf8 {
#ifdef _WIN32
int open(const char* name, int flags, ...);
int unlink(const char* name);
#else
using ::open;
using ::unlink;
#endif
} // namespace utf8
} // namespace base
} // namespace android
#endif // ANDROID_BASE_UTF8_H

View File

@@ -1,428 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef _WIN32
#include <windows.h>
#endif
#include "android-base/logging.h"
#include <libgen.h>
// For getprogname(3) or program_invocation_short_name.
#if defined(__ANDROID__) || defined(__APPLE__)
#include <stdlib.h>
#elif defined(__GLIBC__)
#include <errno.h>
#endif
#include <iostream>
#include <limits>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#ifndef _WIN32
#include <mutex>
#endif
#include "android-base/macros.h"
#include "android-base/strings.h"
#include "cutils/threads.h"
// Headers for LogMessage::LogLine.
#ifdef __ANDROID__
#include <android/set_abort_message.h>
#include "cutils/log.h"
#else
#include <sys/types.h>
#include <unistd.h>
#endif
// For gettid.
#if defined(__APPLE__)
#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED
#include <stdint.h>
#include <stdlib.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <unistd.h>
#elif defined(__linux__) && !defined(__ANDROID__)
#include <syscall.h>
#include <unistd.h>
#elif defined(_WIN32)
#include <windows.h>
#endif
#if defined(_WIN32)
typedef uint32_t thread_id;
#else
typedef pid_t thread_id;
#endif
static thread_id GetThreadId() {
#if defined(__BIONIC__)
return gettid();
#elif defined(__APPLE__)
return syscall(SYS_thread_selfid);
#elif defined(__linux__)
return syscall(__NR_gettid);
#elif defined(_WIN32)
return GetCurrentThreadId();
#endif
}
namespace {
#ifndef _WIN32
using std::mutex;
using std::lock_guard;
#if defined(__GLIBC__)
const char* getprogname() {
return program_invocation_short_name;
}
#endif
#else
const char* getprogname() {
static bool first = true;
static char progname[MAX_PATH] = {};
if (first) {
CHAR longname[MAX_PATH];
DWORD nchars = GetModuleFileNameA(nullptr, longname, arraysize(longname));
if ((nchars >= arraysize(longname)) || (nchars == 0)) {
// String truncation or some other error.
strcpy(progname, "<unknown>");
} else {
strcpy(progname, basename(longname));
}
first = false;
}
return progname;
}
class mutex {
public:
mutex() {
InitializeCriticalSection(&critical_section_);
}
~mutex() {
DeleteCriticalSection(&critical_section_);
}
void lock() {
EnterCriticalSection(&critical_section_);
}
void unlock() {
LeaveCriticalSection(&critical_section_);
}
private:
CRITICAL_SECTION critical_section_;
};
template <typename LockT>
class lock_guard {
public:
explicit lock_guard(LockT& lock) : lock_(lock) {
lock_.lock();
}
~lock_guard() {
lock_.unlock();
}
private:
LockT& lock_;
DISALLOW_COPY_AND_ASSIGN(lock_guard);
};
#endif
} // namespace
namespace android {
namespace base {
static auto& logging_lock = *new mutex();
#ifdef __ANDROID__
static auto& gLogger = *new LogFunction(LogdLogger());
#else
static auto& gLogger = *new LogFunction(StderrLogger);
#endif
static bool gInitialized = false;
static LogSeverity gMinimumLogSeverity = INFO;
static auto& gProgramInvocationName = *new std::unique_ptr<std::string>();
LogSeverity GetMinimumLogSeverity() {
return gMinimumLogSeverity;
}
static const char* ProgramInvocationName() {
if (gProgramInvocationName == nullptr) {
gProgramInvocationName.reset(new std::string(getprogname()));
}
return gProgramInvocationName->c_str();
}
void StderrLogger(LogId, LogSeverity severity, const char*, const char* file,
unsigned int line, const char* message) {
static const char log_characters[] = "VDIWEF";
static_assert(arraysize(log_characters) - 1 == FATAL + 1,
"Mismatch in size of log_characters and values in LogSeverity");
char severity_char = log_characters[severity];
fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", ProgramInvocationName(),
severity_char, getpid(), GetThreadId(), file, line, message);
}
#ifdef __ANDROID__
LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {
}
static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
ANDROID_LOG_WARN, ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
};
static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
"Mismatch in size of kLogSeverityToAndroidLogPriority and values "
"in LogSeverity");
static const log_id kLogIdToAndroidLogId[] = {
LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
};
static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
"Mismatch in size of kLogIdToAndroidLogId and values in LogId");
void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
const char* file, unsigned int line,
const char* message) {
int priority = kLogSeverityToAndroidLogPriority[severity];
if (id == DEFAULT) {
id = default_log_id_;
}
log_id lg_id = kLogIdToAndroidLogId[id];
if (priority == ANDROID_LOG_FATAL) {
__android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line,
message);
} else {
__android_log_buf_print(lg_id, priority, tag, "%s", message);
}
}
#endif
void InitLogging(char* argv[], LogFunction&& logger) {
SetLogger(std::forward<LogFunction>(logger));
InitLogging(argv);
}
void InitLogging(char* argv[]) {
if (gInitialized) {
return;
}
gInitialized = true;
// Stash the command line for later use. We can use /proc/self/cmdline on
// Linux to recover this, but we don't have that luxury on the Mac/Windows,
// and there are a couple of argv[0] variants that are commonly used.
if (argv != nullptr) {
gProgramInvocationName.reset(new std::string(basename(argv[0])));
}
const char* tags = getenv("ANDROID_LOG_TAGS");
if (tags == nullptr) {
return;
}
std::vector<std::string> specs = Split(tags, " ");
for (size_t i = 0; i < specs.size(); ++i) {
// "tag-pattern:[vdiwefs]"
std::string spec(specs[i]);
if (spec.size() == 3 && StartsWith(spec, "*:")) {
switch (spec[2]) {
case 'v':
gMinimumLogSeverity = VERBOSE;
continue;
case 'd':
gMinimumLogSeverity = DEBUG;
continue;
case 'i':
gMinimumLogSeverity = INFO;
continue;
case 'w':
gMinimumLogSeverity = WARNING;
continue;
case 'e':
gMinimumLogSeverity = ERROR;
continue;
case 'f':
gMinimumLogSeverity = FATAL;
continue;
// liblog will even suppress FATAL if you say 's' for silent, but that's
// crazy!
case 's':
gMinimumLogSeverity = FATAL;
continue;
}
}
LOG(FATAL) << "unsupported '" << spec << "' in ANDROID_LOG_TAGS (" << tags
<< ")";
}
}
void SetLogger(LogFunction&& logger) {
lock_guard<mutex> lock(logging_lock);
gLogger = std::move(logger);
}
static const char* GetFileBasename(const char* file) {
// We can't use basename(3) even on Unix because the Mac doesn't
// have a non-modifying basename.
const char* last_slash = strrchr(file, '/');
if (last_slash != nullptr) {
return last_slash + 1;
}
#if defined(_WIN32)
const char* last_backslash = strrchr(file, '\\');
if (last_backslash != nullptr) {
return last_backslash + 1;
}
#endif
return file;
}
// This indirection greatly reduces the stack impact of having lots of
// checks/logging in a function.
class LogMessageData {
public:
LogMessageData(const char* file, unsigned int line, LogId id,
LogSeverity severity, int error)
: file_(GetFileBasename(file)),
line_number_(line),
id_(id),
severity_(severity),
error_(error) {
}
const char* GetFile() const {
return file_;
}
unsigned int GetLineNumber() const {
return line_number_;
}
LogSeverity GetSeverity() const {
return severity_;
}
LogId GetId() const {
return id_;
}
int GetError() const {
return error_;
}
std::ostream& GetBuffer() {
return buffer_;
}
std::string ToString() const {
return buffer_.str();
}
private:
std::ostringstream buffer_;
const char* const file_;
const unsigned int line_number_;
const LogId id_;
const LogSeverity severity_;
const int error_;
DISALLOW_COPY_AND_ASSIGN(LogMessageData);
};
LogMessage::LogMessage(const char* file, unsigned int line, LogId id,
LogSeverity severity, int error)
: data_(new LogMessageData(file, line, id, severity, error)) {
}
LogMessage::~LogMessage() {
// Finish constructing the message.
if (data_->GetError() != -1) {
data_->GetBuffer() << ": " << strerror(data_->GetError());
}
std::string msg(data_->ToString());
{
// Do the actual logging with the lock held.
lock_guard<mutex> lock(logging_lock);
if (msg.find('\n') == std::string::npos) {
LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
data_->GetSeverity(), msg.c_str());
} else {
msg += '\n';
size_t i = 0;
while (i < msg.size()) {
size_t nl = msg.find('\n', i);
msg[nl] = '\0';
LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetId(),
data_->GetSeverity(), &msg[i]);
i = nl + 1;
}
}
}
// Abort if necessary.
if (data_->GetSeverity() == FATAL) {
#ifdef __ANDROID__
android_set_abort_message(msg.c_str());
#endif
abort();
}
}
std::ostream& LogMessage::stream() {
return data_->GetBuffer();
}
void LogMessage::LogLine(const char* file, unsigned int line, LogId id,
LogSeverity severity, const char* message) {
const char* tag = ProgramInvocationName();
gLogger(id, severity, tag, file, line, message);
}
ScopedLogSeverity::ScopedLogSeverity(LogSeverity level) {
old_ = gMinimumLogSeverity;
gMinimumLogSeverity = level;
}
ScopedLogSeverity::~ScopedLogSeverity() {
gMinimumLogSeverity = old_;
}
} // namespace base
} // namespace android

View File

@@ -1,281 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/logging.h"
#include <libgen.h>
#if defined(_WIN32)
#include <signal.h>
#endif
#include <regex>
#include <string>
#include "android-base/file.h"
#include "android-base/stringprintf.h"
#include "android-base/test_utils.h"
#include <gtest/gtest.h>
#ifdef __ANDROID__
#define HOST_TEST(suite, name) TEST(suite, DISABLED_ ## name)
#else
#define HOST_TEST(suite, name) TEST(suite, name)
#endif
class CapturedStderr {
public:
CapturedStderr() : old_stderr_(-1) {
init();
}
~CapturedStderr() {
reset();
}
int fd() const {
return temp_file_.fd;
}
private:
void init() {
#if defined(_WIN32)
// On Windows, stderr is often buffered, so make sure it is unbuffered so
// that we can immediately read back what was written to stderr.
ASSERT_EQ(0, setvbuf(stderr, NULL, _IONBF, 0));
#endif
old_stderr_ = dup(STDERR_FILENO);
ASSERT_NE(-1, old_stderr_);
ASSERT_NE(-1, dup2(fd(), STDERR_FILENO));
}
void reset() {
ASSERT_NE(-1, dup2(old_stderr_, STDERR_FILENO));
ASSERT_EQ(0, close(old_stderr_));
// Note: cannot restore prior setvbuf() setting.
}
TemporaryFile temp_file_;
int old_stderr_;
};
#if defined(_WIN32)
static void ExitSignalAbortHandler(int) {
_exit(3);
}
#endif
static void SuppressAbortUI() {
#if defined(_WIN32)
// We really just want to call _set_abort_behavior(0, _CALL_REPORTFAULT) to
// suppress the Windows Error Reporting dialog box, but that API is not
// available in the OS-supplied C Runtime, msvcrt.dll, that we currently
// use (it is available in the Visual Studio C runtime).
//
// Instead, we setup a SIGABRT handler, which is called in abort() right
// before calling Windows Error Reporting. In the handler, we exit the
// process just like abort() does.
ASSERT_NE(SIG_ERR, signal(SIGABRT, ExitSignalAbortHandler));
#endif
}
TEST(logging, CHECK) {
ASSERT_DEATH({SuppressAbortUI(); CHECK(false);}, "Check failed: false ");
CHECK(true);
ASSERT_DEATH({SuppressAbortUI(); CHECK_EQ(0, 1);}, "Check failed: 0 == 1 ");
CHECK_EQ(0, 0);
ASSERT_DEATH({SuppressAbortUI(); CHECK_STREQ("foo", "bar");},
R"(Check failed: "foo" == "bar")");
CHECK_STREQ("foo", "foo");
// Test whether CHECK() and CHECK_STREQ() have a dangling if with no else.
bool flag = false;
if (true)
CHECK(true);
else
flag = true;
EXPECT_FALSE(flag) << "CHECK macro probably has a dangling if with no else";
flag = false;
if (true)
CHECK_STREQ("foo", "foo");
else
flag = true;
EXPECT_FALSE(flag) << "CHECK_STREQ probably has a dangling if with no else";
}
std::string make_log_pattern(android::base::LogSeverity severity,
const char* message) {
static const char* log_characters = "VDIWEF";
char log_char = log_characters[severity];
std::string holder(__FILE__);
return android::base::StringPrintf(
"%c[[:space:]]+[[:digit:]]+[[:space:]]+[[:digit:]]+ %s:[[:digit:]]+] %s",
log_char, basename(&holder[0]), message);
}
TEST(logging, LOG) {
ASSERT_DEATH({SuppressAbortUI(); LOG(FATAL) << "foobar";}, "foobar");
// We can't usefully check the output of any of these on Windows because we
// don't have std::regex, but we can at least make sure we printed at least as
// many characters are in the log message.
{
CapturedStderr cap;
LOG(WARNING) << "foobar";
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
ASSERT_GT(output.length(), strlen("foobar"));
#if !defined(_WIN32)
std::regex message_regex(
make_log_pattern(android::base::WARNING, "foobar"));
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
{
CapturedStderr cap;
LOG(INFO) << "foobar";
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
ASSERT_GT(output.length(), strlen("foobar"));
#if !defined(_WIN32)
std::regex message_regex(
make_log_pattern(android::base::INFO, "foobar"));
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
{
CapturedStderr cap;
LOG(DEBUG) << "foobar";
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
ASSERT_TRUE(output.empty());
}
{
android::base::ScopedLogSeverity severity(android::base::DEBUG);
CapturedStderr cap;
LOG(DEBUG) << "foobar";
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
ASSERT_GT(output.length(), strlen("foobar"));
#if !defined(_WIN32)
std::regex message_regex(
make_log_pattern(android::base::DEBUG, "foobar"));
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
// Test whether LOG() saves and restores errno.
{
CapturedStderr cap;
errno = 12345;
LOG(INFO) << (errno = 67890);
EXPECT_EQ(12345, errno) << "errno was not restored";
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
EXPECT_NE(nullptr, strstr(output.c_str(), "67890")) << output;
#if !defined(_WIN32)
std::regex message_regex(
make_log_pattern(android::base::INFO, "67890"));
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
// Test whether LOG() has a dangling if with no else.
{
CapturedStderr cap;
// Do the test two ways: once where we hypothesize that LOG()'s if
// will evaluate to true (when severity is high enough) and once when we
// expect it to evaluate to false (when severity is not high enough).
bool flag = false;
if (true)
LOG(INFO) << "foobar";
else
flag = true;
EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else";
flag = false;
if (true)
LOG(VERBOSE) << "foobar";
else
flag = true;
EXPECT_FALSE(flag) << "LOG macro probably has a dangling if with no else";
}
}
TEST(logging, PLOG) {
{
CapturedStderr cap;
errno = ENOENT;
PLOG(INFO) << "foobar";
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
ASSERT_GT(output.length(), strlen("foobar"));
#if !defined(_WIN32)
std::regex message_regex(make_log_pattern(
android::base::INFO, "foobar: No such file or directory"));
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
}
TEST(logging, UNIMPLEMENTED) {
{
CapturedStderr cap;
errno = ENOENT;
UNIMPLEMENTED(ERROR);
ASSERT_EQ(0, lseek(cap.fd(), 0, SEEK_SET));
std::string output;
android::base::ReadFdToString(cap.fd(), &output);
ASSERT_GT(output.length(), strlen("unimplemented"));
#if !defined(_WIN32)
std::string expected_message =
android::base::StringPrintf("%s unimplemented ", __PRETTY_FUNCTION__);
std::regex message_regex(
make_log_pattern(android::base::ERROR, expected_message.c_str()));
ASSERT_TRUE(std::regex_search(output, message_regex)) << output;
#endif
}
}

View File

@@ -1,78 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/parseint.h"
#include <gtest/gtest.h>
TEST(parseint, signed_smoke) {
int i;
ASSERT_FALSE(android::base::ParseInt("x", &i));
ASSERT_FALSE(android::base::ParseInt("123x", &i));
ASSERT_TRUE(android::base::ParseInt("123", &i));
ASSERT_EQ(123, i);
ASSERT_TRUE(android::base::ParseInt("-123", &i));
ASSERT_EQ(-123, i);
short s;
ASSERT_TRUE(android::base::ParseInt("1234", &s));
ASSERT_EQ(1234, s);
ASSERT_TRUE(android::base::ParseInt("12", &i, 0, 15));
ASSERT_EQ(12, i);
ASSERT_FALSE(android::base::ParseInt("-12", &i, 0, 15));
ASSERT_FALSE(android::base::ParseInt("16", &i, 0, 15));
}
TEST(parseint, unsigned_smoke) {
unsigned int i;
ASSERT_FALSE(android::base::ParseUint("x", &i));
ASSERT_FALSE(android::base::ParseUint("123x", &i));
ASSERT_TRUE(android::base::ParseUint("123", &i));
ASSERT_EQ(123u, i);
ASSERT_FALSE(android::base::ParseUint("-123", &i));
unsigned short s;
ASSERT_TRUE(android::base::ParseUint("1234", &s));
ASSERT_EQ(1234u, s);
ASSERT_TRUE(android::base::ParseUint("12", &i, 15u));
ASSERT_EQ(12u, i);
ASSERT_FALSE(android::base::ParseUint("-12", &i, 15u));
ASSERT_FALSE(android::base::ParseUint("16", &i, 15u));
}
TEST(parseint, no_implicit_octal) {
int i;
ASSERT_TRUE(android::base::ParseInt("0123", &i));
ASSERT_EQ(123, i);
unsigned int u;
ASSERT_TRUE(android::base::ParseUint("0123", &u));
ASSERT_EQ(123u, u);
}
TEST(parseint, explicit_hex) {
int i;
ASSERT_TRUE(android::base::ParseInt("0x123", &i));
ASSERT_EQ(0x123, i);
unsigned int u;
ASSERT_TRUE(android::base::ParseUint("0x123", &u));
ASSERT_EQ(0x123u, u);
}

View File

@@ -1,82 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/parsenetaddress.h"
#include <algorithm>
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
namespace android {
namespace base {
bool ParseNetAddress(const std::string& address, std::string* host, int* port,
std::string* canonical_address, std::string* error) {
host->clear();
bool ipv6 = true;
bool saw_port = false;
size_t colons = std::count(address.begin(), address.end(), ':');
size_t dots = std::count(address.begin(), address.end(), '.');
std::string port_str;
if (address[0] == '[') {
// [::1]:123
if (address.rfind("]:") == std::string::npos) {
*error = StringPrintf("bad IPv6 address '%s'", address.c_str());
return false;
}
*host = address.substr(1, (address.find("]:") - 1));
port_str = address.substr(address.rfind("]:") + 2);
saw_port = true;
} else if (dots == 0 && colons >= 2 && colons <= 7) {
// ::1
*host = address;
} else if (colons <= 1) {
// 1.2.3.4 or some.accidental.domain.com
ipv6 = false;
std::vector<std::string> pieces = Split(address, ":");
*host = pieces[0];
if (pieces.size() > 1) {
port_str = pieces[1];
saw_port = true;
}
}
if (host->empty()) {
*error = StringPrintf("no host in '%s'", address.c_str());
return false;
}
if (saw_port) {
if (sscanf(port_str.c_str(), "%d", port) != 1 || *port <= 0 ||
*port > 65535) {
*error = StringPrintf("bad port number '%s' in '%s'", port_str.c_str(),
address.c_str());
return false;
}
}
if (canonical_address != nullptr) {
*canonical_address =
StringPrintf(ipv6 ? "[%s]:%d" : "%s:%d", host->c_str(), *port);
}
return true;
}
} // namespace base
} // namespace android

View File

@@ -1,127 +0,0 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/parsenetaddress.h"
#include <gtest/gtest.h>
using android::base::ParseNetAddress;
TEST(ParseNetAddressTest, TestUrl) {
std::string canonical, host, error;
int port = 123;
EXPECT_TRUE(
ParseNetAddress("www.google.com", &host, &port, &canonical, &error));
EXPECT_EQ("www.google.com:123", canonical);
EXPECT_EQ("www.google.com", host);
EXPECT_EQ(123, port);
EXPECT_TRUE(
ParseNetAddress("www.google.com:666", &host, &port, &canonical, &error));
EXPECT_EQ("www.google.com:666", canonical);
EXPECT_EQ("www.google.com", host);
EXPECT_EQ(666, port);
}
TEST(ParseNetAddressTest, TestIpv4) {
std::string canonical, host, error;
int port = 123;
EXPECT_TRUE(ParseNetAddress("1.2.3.4", &host, &port, &canonical, &error));
EXPECT_EQ("1.2.3.4:123", canonical);
EXPECT_EQ("1.2.3.4", host);
EXPECT_EQ(123, port);
EXPECT_TRUE(ParseNetAddress("1.2.3.4:666", &host, &port, &canonical, &error));
EXPECT_EQ("1.2.3.4:666", canonical);
EXPECT_EQ("1.2.3.4", host);
EXPECT_EQ(666, port);
}
TEST(ParseNetAddressTest, TestIpv6) {
std::string canonical, host, error;
int port = 123;
EXPECT_TRUE(ParseNetAddress("::1", &host, &port, &canonical, &error));
EXPECT_EQ("[::1]:123", canonical);
EXPECT_EQ("::1", host);
EXPECT_EQ(123, port);
EXPECT_TRUE(ParseNetAddress("fe80::200:5aee:feaa:20a2", &host, &port,
&canonical, &error));
EXPECT_EQ("[fe80::200:5aee:feaa:20a2]:123", canonical);
EXPECT_EQ("fe80::200:5aee:feaa:20a2", host);
EXPECT_EQ(123, port);
EXPECT_TRUE(ParseNetAddress("[::1]:666", &host, &port, &canonical, &error));
EXPECT_EQ("[::1]:666", canonical);
EXPECT_EQ("::1", host);
EXPECT_EQ(666, port);
EXPECT_TRUE(ParseNetAddress("[fe80::200:5aee:feaa:20a2]:666", &host, &port,
&canonical, &error));
EXPECT_EQ("[fe80::200:5aee:feaa:20a2]:666", canonical);
EXPECT_EQ("fe80::200:5aee:feaa:20a2", host);
EXPECT_EQ(666, port);
}
TEST(ParseNetAddressTest, TestInvalidAddress) {
std::string canonical, host;
int port;
std::string failure_cases[] = {
// Invalid IPv4.
"1.2.3.4:",
"1.2.3.4::",
":123",
// Invalid IPv6.
":1",
"::::::::1",
"[::1",
"[::1]",
"[::1]:",
"[::1]::",
// Invalid port.
"1.2.3.4:-1",
"1.2.3.4:0",
"1.2.3.4:65536"
"1.2.3.4:hello",
"[::1]:-1",
"[::1]:0",
"[::1]:65536",
"[::1]:hello",
};
for (const auto& address : failure_cases) {
// Failure should give some non-empty error string.
std::string error;
EXPECT_FALSE(ParseNetAddress(address, &host, &port, &canonical, &error));
EXPECT_NE("", error);
}
}
// Null canonical address argument.
TEST(ParseNetAddressTest, TestNullCanonicalAddress) {
std::string host, error;
int port = 42;
EXPECT_TRUE(ParseNetAddress("www.google.com", &host, &port, nullptr, &error));
EXPECT_TRUE(ParseNetAddress("1.2.3.4", &host, &port, nullptr, &error));
EXPECT_TRUE(ParseNetAddress("::1", &host, &port, nullptr, &error));
}

View File

@@ -1,85 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/stringprintf.h"
#include <stdio.h>
#include <string>
namespace android {
namespace base {
void StringAppendV(std::string* dst, const char* format, va_list ap) {
// First try with a small fixed size buffer
char space[1024];
// It's possible for methods that use a va_list to invalidate
// the data in it upon use. The fix is to make a copy
// of the structure before using it and use that copy instead.
va_list backup_ap;
va_copy(backup_ap, ap);
int result = vsnprintf(space, sizeof(space), format, backup_ap);
va_end(backup_ap);
if (result < static_cast<int>(sizeof(space))) {
if (result >= 0) {
// Normal case -- everything fit.
dst->append(space, result);
return;
}
if (result < 0) {
// Just an error.
return;
}
}
// Increase the buffer size to the size requested by vsnprintf,
// plus one for the closing \0.
int length = result + 1;
char* buf = new char[length];
// Restore the va_list before we use it again
va_copy(backup_ap, ap);
result = vsnprintf(buf, length, format, backup_ap);
va_end(backup_ap);
if (result >= 0 && result < length) {
// It fit
dst->append(buf, result);
}
delete[] buf;
}
std::string StringPrintf(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
std::string result;
StringAppendV(&result, fmt, ap);
va_end(ap);
return result;
}
void StringAppendF(std::string* dst, const char* format, ...) {
va_list ap;
va_start(ap, format);
StringAppendV(dst, format, ap);
va_end(ap);
}
} // namespace base
} // namespace android

View File

@@ -1,60 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/stringprintf.h"
#include <gtest/gtest.h>
#include <string>
TEST(StringPrintfTest, HexSizeT) {
size_t size = 0x00107e59;
EXPECT_EQ("00107e59", android::base::StringPrintf("%08zx", size));
EXPECT_EQ("0x00107e59", android::base::StringPrintf("0x%08zx", size));
}
TEST(StringPrintfTest, StringAppendF) {
std::string s("a");
android::base::StringAppendF(&s, "b");
EXPECT_EQ("ab", s);
}
TEST(StringPrintfTest, Errno) {
errno = 123;
android::base::StringPrintf("hello %s", "world");
EXPECT_EQ(123, errno);
}
void TestN(size_t n) {
char* buf = new char[n + 1];
memset(buf, 'x', n);
buf[n] = '\0';
std::string s(android::base::StringPrintf("%s", buf));
EXPECT_EQ(buf, s);
delete[] buf;
}
TEST(StringPrintfTest, At1023) {
TestN(1023);
}
TEST(StringPrintfTest, At1024) {
TestN(1024);
}
TEST(StringPrintfTest, At1025) {
TestN(1025);
}

View File

@@ -1,104 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/strings.h"
#include <stdlib.h>
#include <string.h>
#include <string>
#include <vector>
namespace android {
namespace base {
#define CHECK_NE(a, b) \
if ((a) == (b)) abort();
std::vector<std::string> Split(const std::string& s,
const std::string& delimiters) {
CHECK_NE(delimiters.size(), 0U);
std::vector<std::string> result;
size_t base = 0;
size_t found;
do {
found = s.find_first_of(delimiters, base);
result.push_back(s.substr(base, found - base));
base = found + 1;
} while (found != s.npos);
return result;
}
std::string Trim(const std::string& s) {
std::string result;
if (s.size() == 0) {
return result;
}
size_t start_index = 0;
size_t end_index = s.size() - 1;
// Skip initial whitespace.
while (start_index < s.size()) {
if (!isspace(s[start_index])) {
break;
}
start_index++;
}
// Skip terminating whitespace.
while (end_index >= start_index) {
if (!isspace(s[end_index])) {
break;
}
end_index--;
}
// All spaces, no beef.
if (end_index < start_index) {
return "";
}
// Start_index is the first non-space, end_index is the last one.
return s.substr(start_index, end_index - start_index + 1);
}
// These cases are probably the norm, so we mark them extern in the header to
// aid compile time and binary size.
template std::string Join(const std::vector<std::string>&, char);
template std::string Join(const std::vector<const char*>&, char);
template std::string Join(const std::vector<std::string>&, const std::string&);
template std::string Join(const std::vector<const char*>&, const std::string&);
bool StartsWith(const std::string& s, const char* prefix) {
return s.compare(0, strlen(prefix), prefix) == 0;
}
bool EndsWith(const std::string& s, const char* suffix) {
size_t suffix_length = strlen(suffix);
size_t string_length = s.size();
if (suffix_length > string_length) {
return false;
}
size_t offset = string_length - suffix_length;
return s.compare(offset, suffix_length, suffix) == 0;
}
} // namespace base
} // namespace android

View File

@@ -1,177 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/strings.h"
#include <gtest/gtest.h>
#include <string>
#include <vector>
#include <set>
#include <unordered_set>
TEST(strings, split_empty) {
std::vector<std::string> parts = android::base::Split("", ",");
ASSERT_EQ(1U, parts.size());
ASSERT_EQ("", parts[0]);
}
TEST(strings, split_single) {
std::vector<std::string> parts = android::base::Split("foo", ",");
ASSERT_EQ(1U, parts.size());
ASSERT_EQ("foo", parts[0]);
}
TEST(strings, split_simple) {
std::vector<std::string> parts = android::base::Split("foo,bar,baz", ",");
ASSERT_EQ(3U, parts.size());
ASSERT_EQ("foo", parts[0]);
ASSERT_EQ("bar", parts[1]);
ASSERT_EQ("baz", parts[2]);
}
TEST(strings, split_with_empty_part) {
std::vector<std::string> parts = android::base::Split("foo,,bar", ",");
ASSERT_EQ(3U, parts.size());
ASSERT_EQ("foo", parts[0]);
ASSERT_EQ("", parts[1]);
ASSERT_EQ("bar", parts[2]);
}
TEST(strings, split_null_char) {
std::vector<std::string> parts =
android::base::Split(std::string("foo\0bar", 7), std::string("\0", 1));
ASSERT_EQ(2U, parts.size());
ASSERT_EQ("foo", parts[0]);
ASSERT_EQ("bar", parts[1]);
}
TEST(strings, split_any) {
std::vector<std::string> parts = android::base::Split("foo:bar,baz", ",:");
ASSERT_EQ(3U, parts.size());
ASSERT_EQ("foo", parts[0]);
ASSERT_EQ("bar", parts[1]);
ASSERT_EQ("baz", parts[2]);
}
TEST(strings, split_any_with_empty_part) {
std::vector<std::string> parts = android::base::Split("foo:,bar", ",:");
ASSERT_EQ(3U, parts.size());
ASSERT_EQ("foo", parts[0]);
ASSERT_EQ("", parts[1]);
ASSERT_EQ("bar", parts[2]);
}
TEST(strings, trim_empty) {
ASSERT_EQ("", android::base::Trim(""));
}
TEST(strings, trim_already_trimmed) {
ASSERT_EQ("foo", android::base::Trim("foo"));
}
TEST(strings, trim_left) {
ASSERT_EQ("foo", android::base::Trim(" foo"));
}
TEST(strings, trim_right) {
ASSERT_EQ("foo", android::base::Trim("foo "));
}
TEST(strings, trim_both) {
ASSERT_EQ("foo", android::base::Trim(" foo "));
}
TEST(strings, trim_no_trim_middle) {
ASSERT_EQ("foo bar", android::base::Trim("foo bar"));
}
TEST(strings, trim_other_whitespace) {
ASSERT_EQ("foo", android::base::Trim("\v\tfoo\n\f"));
}
TEST(strings, join_nothing) {
std::vector<std::string> list = {};
ASSERT_EQ("", android::base::Join(list, ','));
}
TEST(strings, join_single) {
std::vector<std::string> list = {"foo"};
ASSERT_EQ("foo", android::base::Join(list, ','));
}
TEST(strings, join_simple) {
std::vector<std::string> list = {"foo", "bar", "baz"};
ASSERT_EQ("foo,bar,baz", android::base::Join(list, ','));
}
TEST(strings, join_separator_in_vector) {
std::vector<std::string> list = {",", ","};
ASSERT_EQ(",,,", android::base::Join(list, ','));
}
TEST(strings, join_simple_ints) {
std::set<int> list = {1, 2, 3};
ASSERT_EQ("1,2,3", android::base::Join(list, ','));
}
TEST(strings, join_unordered_set) {
std::unordered_set<int> list = {1, 2};
ASSERT_TRUE("1,2" == android::base::Join(list, ',') ||
"2,1" == android::base::Join(list, ','));
}
TEST(strings, startswith_empty) {
ASSERT_FALSE(android::base::StartsWith("", "foo"));
ASSERT_TRUE(android::base::StartsWith("", ""));
}
TEST(strings, startswith_simple) {
ASSERT_TRUE(android::base::StartsWith("foo", ""));
ASSERT_TRUE(android::base::StartsWith("foo", "f"));
ASSERT_TRUE(android::base::StartsWith("foo", "fo"));
ASSERT_TRUE(android::base::StartsWith("foo", "foo"));
}
TEST(strings, startswith_prefix_too_long) {
ASSERT_FALSE(android::base::StartsWith("foo", "foobar"));
}
TEST(strings, startswith_contains_prefix) {
ASSERT_FALSE(android::base::StartsWith("foobar", "oba"));
ASSERT_FALSE(android::base::StartsWith("foobar", "bar"));
}
TEST(strings, endswith_empty) {
ASSERT_FALSE(android::base::EndsWith("", "foo"));
ASSERT_TRUE(android::base::EndsWith("", ""));
}
TEST(strings, endswith_simple) {
ASSERT_TRUE(android::base::EndsWith("foo", ""));
ASSERT_TRUE(android::base::EndsWith("foo", "o"));
ASSERT_TRUE(android::base::EndsWith("foo", "oo"));
ASSERT_TRUE(android::base::EndsWith("foo", "foo"));
}
TEST(strings, endswith_prefix_too_long) {
ASSERT_FALSE(android::base::EndsWith("foo", "foobar"));
}
TEST(strings, endswith_contains_prefix) {
ASSERT_FALSE(android::base::EndsWith("foobar", "oba"));
ASSERT_FALSE(android::base::EndsWith("foobar", "foo"));
}

View File

@@ -1,25 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <gtest/gtest.h>
#include "android-base/logging.h"
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
android::base::InitLogging(argv, android::base::StderrLogger);
return RUN_ALL_TESTS();
}

View File

@@ -1,102 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/logging.h"
#include "android-base/test_utils.h"
#include "utils/Compat.h" // For OS_PATH_SEPARATOR.
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>
#if defined(_WIN32)
#include <windows.h>
#include <direct.h>
#endif
#include <string>
#ifdef _WIN32
int mkstemp(char* template_name) {
if (_mktemp(template_name) == nullptr) {
return -1;
}
// Use open() to match the close() that TemporaryFile's destructor does.
// Use O_BINARY to match base file APIs.
return open(template_name, O_CREAT | O_EXCL | O_RDWR | O_BINARY,
S_IRUSR | S_IWUSR);
}
char* mkdtemp(char* template_name) {
if (_mktemp(template_name) == nullptr) {
return nullptr;
}
if (_mkdir(template_name) == -1) {
return nullptr;
}
return template_name;
}
#endif
static std::string GetSystemTempDir() {
#if defined(__ANDROID__)
return "/data/local/tmp";
#elif defined(_WIN32)
char tmp_dir[MAX_PATH];
DWORD result = GetTempPathA(sizeof(tmp_dir), tmp_dir);
CHECK_NE(result, 0ul) << "GetTempPathA failed, error: " << GetLastError();
CHECK_LT(result, sizeof(tmp_dir)) << "path truncated to: " << result;
// GetTempPath() returns a path with a trailing slash, but init()
// does not expect that, so remove it.
CHECK_EQ(tmp_dir[result - 1], '\\');
tmp_dir[result - 1] = '\0';
return tmp_dir;
#else
return "/tmp";
#endif
}
TemporaryFile::TemporaryFile() {
init(GetSystemTempDir());
}
TemporaryFile::~TemporaryFile() {
close(fd);
unlink(path);
}
void TemporaryFile::init(const std::string& tmp_dir) {
snprintf(path, sizeof(path), "%s%cTemporaryFile-XXXXXX", tmp_dir.c_str(),
OS_PATH_SEPARATOR);
fd = mkstemp(path);
}
TemporaryDir::TemporaryDir() {
init(GetSystemTempDir());
}
TemporaryDir::~TemporaryDir() {
rmdir(path);
}
bool TemporaryDir::init(const std::string& tmp_dir) {
snprintf(path, sizeof(path), "%s%cTemporaryDir-XXXXXX", tmp_dir.c_str(),
OS_PATH_SEPARATOR);
return (mkdtemp(path) != nullptr);
}

View File

@@ -1,187 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <windows.h>
#include "android-base/utf8.h"
#include <fcntl.h>
#include <string>
#include "android-base/logging.h"
namespace android {
namespace base {
// Helper to set errno based on GetLastError() after WideCharToMultiByte()/MultiByteToWideChar().
static void SetErrnoFromLastError() {
switch (GetLastError()) {
case ERROR_NO_UNICODE_TRANSLATION:
errno = EILSEQ;
break;
default:
errno = EINVAL;
break;
}
}
bool WideToUTF8(const wchar_t* utf16, const size_t size, std::string* utf8) {
utf8->clear();
if (size == 0) {
return true;
}
// TODO: Consider using std::wstring_convert once libcxx is supported on
// Windows.
// Only Vista or later has this flag that causes WideCharToMultiByte() to
// return an error on invalid characters.
const DWORD flags =
#if (WINVER >= 0x0600)
WC_ERR_INVALID_CHARS;
#else
0;
#endif
const int chars_required = WideCharToMultiByte(CP_UTF8, flags, utf16, size,
NULL, 0, NULL, NULL);
if (chars_required <= 0) {
SetErrnoFromLastError();
return false;
}
// This could potentially throw a std::bad_alloc exception.
utf8->resize(chars_required);
const int result = WideCharToMultiByte(CP_UTF8, flags, utf16, size,
&(*utf8)[0], chars_required, NULL,
NULL);
if (result != chars_required) {
SetErrnoFromLastError();
CHECK_LE(result, chars_required) << "WideCharToMultiByte wrote " << result
<< " chars to buffer of " << chars_required << " chars";
utf8->clear();
return false;
}
return true;
}
bool WideToUTF8(const wchar_t* utf16, std::string* utf8) {
// Compute string length of NULL-terminated string with wcslen().
return WideToUTF8(utf16, wcslen(utf16), utf8);
}
bool WideToUTF8(const std::wstring& utf16, std::string* utf8) {
// Use the stored length of the string which allows embedded NULL characters
// to be converted.
return WideToUTF8(utf16.c_str(), utf16.length(), utf8);
}
// Internal helper function that takes MultiByteToWideChar() flags.
static bool UTF8ToWideWithFlags(const char* utf8, const size_t size, std::wstring* utf16,
const DWORD flags) {
utf16->clear();
if (size == 0) {
return true;
}
// TODO: Consider using std::wstring_convert once libcxx is supported on
// Windows.
const int chars_required = MultiByteToWideChar(CP_UTF8, flags, utf8, size,
NULL, 0);
if (chars_required <= 0) {
SetErrnoFromLastError();
return false;
}
// This could potentially throw a std::bad_alloc exception.
utf16->resize(chars_required);
const int result = MultiByteToWideChar(CP_UTF8, flags, utf8, size,
&(*utf16)[0], chars_required);
if (result != chars_required) {
SetErrnoFromLastError();
CHECK_LE(result, chars_required) << "MultiByteToWideChar wrote " << result
<< " chars to buffer of " << chars_required << " chars";
utf16->clear();
return false;
}
return true;
}
bool UTF8ToWide(const char* utf8, const size_t size, std::wstring* utf16) {
// If strictly interpreting as UTF-8 succeeds, return success.
if (UTF8ToWideWithFlags(utf8, size, utf16, MB_ERR_INVALID_CHARS)) {
return true;
}
const int saved_errno = errno;
// Fallback to non-strict interpretation, allowing invalid characters and
// converting as best as possible, and return false to signify a problem.
(void)UTF8ToWideWithFlags(utf8, size, utf16, 0);
errno = saved_errno;
return false;
}
bool UTF8ToWide(const char* utf8, std::wstring* utf16) {
// Compute string length of NULL-terminated string with strlen().
return UTF8ToWide(utf8, strlen(utf8), utf16);
}
bool UTF8ToWide(const std::string& utf8, std::wstring* utf16) {
// Use the stored length of the string which allows embedded NULL characters
// to be converted.
return UTF8ToWide(utf8.c_str(), utf8.length(), utf16);
}
// Versions of standard library APIs that support UTF-8 strings.
namespace utf8 {
int open(const char* name, int flags, ...) {
std::wstring name_utf16;
if (!UTF8ToWide(name, &name_utf16)) {
return -1;
}
int mode = 0;
if ((flags & O_CREAT) != 0) {
va_list args;
va_start(args, flags);
mode = va_arg(args, int);
va_end(args);
}
return _wopen(name_utf16.c_str(), flags, mode);
}
int unlink(const char* name) {
std::wstring name_utf16;
if (!UTF8ToWide(name, &name_utf16)) {
return -1;
}
return _wunlink(name_utf16.c_str());
}
} // namespace utf8
} // namespace base
} // namespace android

View File

@@ -1,412 +0,0 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "android-base/utf8.h"
#include <gtest/gtest.h>
#include "android-base/macros.h"
namespace android {
namespace base {
TEST(UTFStringConversionsTest, ConvertInvalidUTF8) {
std::wstring wide;
errno = 0;
// Standalone \xa2 is an invalid UTF-8 sequence, so this should return an
// error. Concatenate two C/C++ literal string constants to prevent the
// compiler from giving an error about "\xa2af" containing a "hex escape
// sequence out of range".
EXPECT_FALSE(android::base::UTF8ToWide("before\xa2" "after", &wide));
EXPECT_EQ(EILSEQ, errno);
// Even if an invalid character is encountered, UTF8ToWide() should still do
// its best to convert the rest of the string. sysdeps_win32.cpp:
// _console_write_utf8() depends on this behavior.
//
// Thus, we verify that the valid characters are converted, but we ignore the
// specific replacement character that UTF8ToWide() may replace the invalid
// UTF-8 characters with because we want to allow that to change if the
// implementation changes.
EXPECT_EQ(0U, wide.find(L"before"));
const wchar_t after_wide[] = L"after";
EXPECT_EQ(wide.length() - (arraysize(after_wide) - 1), wide.find(after_wide));
}
// Below is adapted from https://chromium.googlesource.com/chromium/src/+/master/base/strings/utf_string_conversions_unittest.cc
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// The tests below from utf_string_conversions_unittest.cc check for this
// preprocessor symbol, so define it, as it is appropriate for Windows.
#define WCHAR_T_IS_UTF16
static_assert(sizeof(wchar_t) == 2, "wchar_t is not 2 bytes");
// The tests below from utf_string_conversions_unittest.cc call versions of
// UTF8ToWide() and WideToUTF8() that don't return success/failure, so these are
// stub implementations with that signature. These are just for testing and
// should not be moved to base because they assert/expect no errors which is
// probably not a good idea (or at least it is something that should be left
// up to the caller, not a base library).
static std::wstring UTF8ToWide(const std::string& utf8) {
std::wstring utf16;
EXPECT_TRUE(UTF8ToWide(utf8, &utf16));
return utf16;
}
static std::string WideToUTF8(const std::wstring& utf16) {
std::string utf8;
EXPECT_TRUE(WideToUTF8(utf16, &utf8));
return utf8;
}
namespace {
const wchar_t* const kConvertRoundtripCases[] = {
L"Google Video",
// "网页 图片 资讯更多 »"
L"\x7f51\x9875\x0020\x56fe\x7247\x0020\x8d44\x8baf\x66f4\x591a\x0020\x00bb",
// "Παγκόσμιος Ιστός"
L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2",
// "Поиск страниц на русском"
L"\x041f\x043e\x0438\x0441\x043a\x0020\x0441\x0442"
L"\x0440\x0430\x043d\x0438\x0446\x0020\x043d\x0430"
L"\x0020\x0440\x0443\x0441\x0441\x043a\x043e\x043c",
// "전체서비스"
L"\xc804\xccb4\xc11c\xbe44\xc2a4",
// Test characters that take more than 16 bits. This will depend on whether
// wchar_t is 16 or 32 bits.
#if defined(WCHAR_T_IS_UTF16)
L"\xd800\xdf00",
// ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
L"\xd807\xdd40\xd807\xdd41\xd807\xdd42\xd807\xdd43\xd807\xdd44",
#elif defined(WCHAR_T_IS_UTF32)
L"\x10300",
// ????? (Mathematical Alphanumeric Symbols (U+011d40 - U+011d44 : A,B,C,D,E)
L"\x11d40\x11d41\x11d42\x11d43\x11d44",
#endif
};
} // namespace
TEST(UTFStringConversionsTest, ConvertUTF8AndWide) {
// we round-trip all the wide strings through UTF-8 to make sure everything
// agrees on the conversion. This uses the stream operators to test them
// simultaneously.
for (size_t i = 0; i < arraysize(kConvertRoundtripCases); ++i) {
std::ostringstream utf8;
utf8 << WideToUTF8(kConvertRoundtripCases[i]);
std::wostringstream wide;
wide << UTF8ToWide(utf8.str());
EXPECT_EQ(kConvertRoundtripCases[i], wide.str());
}
}
TEST(UTFStringConversionsTest, ConvertUTF8AndWideEmptyString) {
// An empty std::wstring should be converted to an empty std::string,
// and vice versa.
std::wstring wempty;
std::string empty;
EXPECT_EQ(empty, WideToUTF8(wempty));
EXPECT_EQ(wempty, UTF8ToWide(empty));
}
TEST(UTFStringConversionsTest, ConvertUTF8ToWide) {
struct UTF8ToWideCase {
const char* utf8;
const wchar_t* wide;
bool success;
} convert_cases[] = {
// Regular UTF-8 input.
{"\xe4\xbd\xa0\xe5\xa5\xbd", L"\x4f60\x597d", true},
// Non-character is passed through.
{"\xef\xbf\xbfHello", L"\xffffHello", true},
// Truncated UTF-8 sequence.
{"\xe4\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
// Truncated off the end.
{"\xe5\xa5\xbd\xe4\xa0", L"\x597d\xfffd", false},
// Non-shortest-form UTF-8.
{"\xf0\x84\xbd\xa0\xe5\xa5\xbd", L"\xfffd\x597d", false},
// This UTF-8 character decodes to a UTF-16 surrogate, which is illegal.
// Note that for whatever reason, this test fails on Windows XP.
{"\xed\xb0\x80", L"\xfffd", false},
// Non-BMP characters. The second is a non-character regarded as valid.
// The result will either be in UTF-16 or UTF-32.
#if defined(WCHAR_T_IS_UTF16)
{"A\xF0\x90\x8C\x80z", L"A\xd800\xdf00z", true},
{"A\xF4\x8F\xBF\xBEz", L"A\xdbff\xdffez", true},
#elif defined(WCHAR_T_IS_UTF32)
{"A\xF0\x90\x8C\x80z", L"A\x10300z", true},
{"A\xF4\x8F\xBF\xBEz", L"A\x10fffez", true},
#endif
};
for (size_t i = 0; i < arraysize(convert_cases); i++) {
std::wstring converted;
errno = 0;
const bool success = UTF8ToWide(convert_cases[i].utf8,
strlen(convert_cases[i].utf8),
&converted);
EXPECT_EQ(convert_cases[i].success, success);
// The original test always compared expected and converted, but don't do
// that because our implementation of UTF8ToWide() does not guarantee to
// produce the same output in error situations.
if (success) {
std::wstring expected(convert_cases[i].wide);
EXPECT_EQ(expected, converted);
} else {
EXPECT_EQ(EILSEQ, errno);
}
}
// Manually test an embedded NULL.
std::wstring converted;
EXPECT_TRUE(UTF8ToWide("\00Z\t", 3, &converted));
ASSERT_EQ(3U, converted.length());
EXPECT_EQ(static_cast<wchar_t>(0), converted[0]);
EXPECT_EQ('Z', converted[1]);
EXPECT_EQ('\t', converted[2]);
// Make sure that conversion replaces, not appends.
EXPECT_TRUE(UTF8ToWide("B", 1, &converted));
ASSERT_EQ(1U, converted.length());
EXPECT_EQ('B', converted[0]);
}
#if defined(WCHAR_T_IS_UTF16)
// This test is only valid when wchar_t == UTF-16.
TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) {
struct WideToUTF8Case {
const wchar_t* utf16;
const char* utf8;
bool success;
} convert_cases[] = {
// Regular UTF-16 input.
{L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
// Test a non-BMP character.
{L"\xd800\xdf00", "\xF0\x90\x8C\x80", true},
// Non-characters are passed through.
{L"\xffffHello", "\xEF\xBF\xBFHello", true},
{L"\xdbff\xdffeHello", "\xF4\x8F\xBF\xBEHello", true},
// The first character is a truncated UTF-16 character.
// Note that for whatever reason, this test fails on Windows XP.
{L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd",
#if (WINVER >= 0x0600)
// Only Vista and later has a new API/flag that correctly returns false.
false
#else
true
#endif
},
// Truncated at the end.
// Note that for whatever reason, this test fails on Windows XP.
{L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd",
#if (WINVER >= 0x0600)
// Only Vista and later has a new API/flag that correctly returns false.
false
#else
true
#endif
},
};
for (size_t i = 0; i < arraysize(convert_cases); i++) {
std::string converted;
errno = 0;
const bool success = WideToUTF8(convert_cases[i].utf16,
wcslen(convert_cases[i].utf16),
&converted);
EXPECT_EQ(convert_cases[i].success, success);
// The original test always compared expected and converted, but don't do
// that because our implementation of WideToUTF8() does not guarantee to
// produce the same output in error situations.
if (success) {
std::string expected(convert_cases[i].utf8);
EXPECT_EQ(expected, converted);
} else {
EXPECT_EQ(EILSEQ, errno);
}
}
}
#elif defined(WCHAR_T_IS_UTF32)
// This test is only valid when wchar_t == UTF-32.
TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) {
struct WideToUTF8Case {
const wchar_t* utf32;
const char* utf8;
bool success;
} convert_cases[] = {
// Regular 16-bit input.
{L"\x4f60\x597d", "\xe4\xbd\xa0\xe5\xa5\xbd", true},
// Test a non-BMP character.
{L"A\x10300z", "A\xF0\x90\x8C\x80z", true},
// Non-characters are passed through.
{L"\xffffHello", "\xEF\xBF\xBFHello", true},
{L"\x10fffeHello", "\xF4\x8F\xBF\xBEHello", true},
// Invalid Unicode code points.
{L"\xfffffffHello", "\xEF\xBF\xBDHello", false},
// The first character is a truncated UTF-16 character.
{L"\xd800\x597d", "\xef\xbf\xbd\xe5\xa5\xbd", false},
{L"\xdc01Hello", "\xef\xbf\xbdHello", false},
};
for (size_t i = 0; i < arraysize(convert_cases); i++) {
std::string converted;
EXPECT_EQ(convert_cases[i].success,
WideToUTF8(convert_cases[i].utf32,
wcslen(convert_cases[i].utf32),
&converted));
std::string expected(convert_cases[i].utf8);
EXPECT_EQ(expected, converted);
}
}
#endif // defined(WCHAR_T_IS_UTF32)
// The test below uses these types and functions, so just do enough to get the
// test running.
typedef wchar_t char16;
typedef std::wstring string16;
template<typename T>
static void* WriteInto(T* t, size_t size) {
// std::(w)string::resize() already includes space for a NULL terminator.
t->resize(size - 1);
return &(*t)[0];
}
// A stub implementation that calls a helper from above, just to get the test
// below working. This is just for testing and should not be moved to base
// because this ignores errors which is probably not a good idea, plus it takes
// a string16 type which we don't really have.
static std::string UTF16ToUTF8(const string16& utf16) {
return WideToUTF8(utf16);
}
TEST(UTFStringConversionsTest, ConvertMultiString) {
static char16 multi16[] = {
'f', 'o', 'o', '\0',
'b', 'a', 'r', '\0',
'b', 'a', 'z', '\0',
'\0'
};
static char multi[] = {
'f', 'o', 'o', '\0',
'b', 'a', 'r', '\0',
'b', 'a', 'z', '\0',
'\0'
};
string16 multistring16;
memcpy(WriteInto(&multistring16, arraysize(multi16)), multi16,
sizeof(multi16));
EXPECT_EQ(arraysize(multi16) - 1, multistring16.length());
std::string expected;
memcpy(WriteInto(&expected, arraysize(multi)), multi, sizeof(multi));
EXPECT_EQ(arraysize(multi) - 1, expected.length());
const std::string& converted = UTF16ToUTF8(multistring16);
EXPECT_EQ(arraysize(multi) - 1, converted.length());
EXPECT_EQ(expected, converted);
}
// The tests below from sys_string_conversions_unittest.cc call SysWideToUTF8()
// and SysUTF8ToWide(), so these are stub implementations that call the helpers
// above. These are just for testing and should not be moved to base because
// they ignore errors which is probably not a good idea.
static std::string SysWideToUTF8(const std::wstring& utf16) {
return WideToUTF8(utf16);
}
static std::wstring SysUTF8ToWide(const std::string& utf8) {
return UTF8ToWide(utf8);
}
// Below is adapted from https://chromium.googlesource.com/chromium/src/+/master/base/strings/sys_string_conversions_unittest.cc
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifdef WCHAR_T_IS_UTF32
static const std::wstring kSysWideOldItalicLetterA = L"\x10300";
#else
static const std::wstring kSysWideOldItalicLetterA = L"\xd800\xdf00";
#endif
TEST(SysStrings, SysWideToUTF8) {
EXPECT_EQ("Hello, world", SysWideToUTF8(L"Hello, world"));
EXPECT_EQ("\xe4\xbd\xa0\xe5\xa5\xbd", SysWideToUTF8(L"\x4f60\x597d"));
// >16 bits
EXPECT_EQ("\xF0\x90\x8C\x80", SysWideToUTF8(kSysWideOldItalicLetterA));
// Error case. When Windows finds a UTF-16 character going off the end of
// a string, it just converts that literal value to UTF-8, even though this
// is invalid.
//
// This is what XP does, but Vista has different behavior, so we don't bother
// verifying it:
// EXPECT_EQ("\xE4\xBD\xA0\xED\xA0\x80zyxw",
// SysWideToUTF8(L"\x4f60\xd800zyxw"));
// Test embedded NULLs.
std::wstring wide_null(L"a");
wide_null.push_back(0);
wide_null.push_back('b');
std::string expected_null("a");
expected_null.push_back(0);
expected_null.push_back('b');
EXPECT_EQ(expected_null, SysWideToUTF8(wide_null));
}
TEST(SysStrings, SysUTF8ToWide) {
EXPECT_EQ(L"Hello, world", SysUTF8ToWide("Hello, world"));
EXPECT_EQ(L"\x4f60\x597d", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5\xbd"));
// >16 bits
EXPECT_EQ(kSysWideOldItalicLetterA, SysUTF8ToWide("\xF0\x90\x8C\x80"));
// Error case. When Windows finds an invalid UTF-8 character, it just skips
// it. This seems weird because it's inconsistent with the reverse conversion.
//
// This is what XP does, but Vista has different behavior, so we don't bother
// verifying it:
// EXPECT_EQ(L"\x4f60zyxw", SysUTF8ToWide("\xe4\xbd\xa0\xe5\xa5zyxw"));
// Test embedded NULLs.
std::string utf8_null("a");
utf8_null.push_back(0);
utf8_null.push_back('b');
std::wstring expected_null(L"a");
expected_null.push_back(0);
expected_null.push_back('b');
EXPECT_EQ(expected_null, SysUTF8ToWide(utf8_null));
}
} // namespace base
} // namespace android

View File

@@ -1,74 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2005 Hewlett-Packard Co
Copyright (C) 2007 David Mosberger-Tang
Contributed by David Mosberger-Tang <dmosberger@gmail.com>
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. */
/* Compiler specific useful bits that are used in libunwind, and also in the
* tests. */
#ifndef COMPILER_H
#define COMPILER_H
#ifdef __GNUC__
# define ALIGNED(x) __attribute__((aligned(x)))
# define CONST_ATTR __attribute__((__const__))
# define UNUSED __attribute__((unused))
# define NOINLINE __attribute__((noinline))
# define NORETURN __attribute__((noreturn))
# define ALIAS(name) __attribute__((alias (#name)))
# if (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
# define ALWAYS_INLINE inline __attribute__((always_inline))
# define HIDDEN __attribute__((visibility ("hidden")))
# define PROTECTED __attribute__((visibility ("protected")))
# else
# define ALWAYS_INLINE
# define HIDDEN
# define PROTECTED
# endif
# define WEAK __attribute__((weak))
# if (__GNUC__ >= 3)
# define likely(x) __builtin_expect ((x), 1)
# define unlikely(x) __builtin_expect ((x), 0)
# else
# define likely(x) (x)
# define unlikely(x) (x)
# endif
#else
# define ALIGNED(x)
# define ALWAYS_INLINE
# define CONST_ATTR
# define UNUSED
# define NOINLINE
# define NORETURN
# define ALIAS(name)
# define HIDDEN
# define PROTECTED
# define WEAK
# define likely(x) (x)
# define unlikely(x) (x)
#endif
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
#endif /* COMPILER_H */

View File

@@ -1,255 +0,0 @@
/* include/config.h. Generated from config.h.in by configure. */
/* include/config.h.in. Generated from configure.ac by autoheader. */
/* Block signals before mutex operations */
/* #undef CONFIG_BLOCK_SIGNALS */
/* Enable Debug Frame */
#define CONFIG_DEBUG_FRAME 1
/* Support for Microsoft ABI extensions */
/* This is required to understand floating point registers on x86-64 */
#define CONFIG_MSABI_SUPPORT 1
/* Define to 1 if you want every memory access validated */
#define CONSERVATIVE_CHECKS 1
/* Allocate large structures rather than place them on the stack. */
#define CONSERVE_STACK /**/
/* Define to 1 if you have the <asm/ptrace_offsets.h> header file. */
/* #undef HAVE_ASM_PTRACE_OFFSETS_H */
/* Define to 1 if you have the <atomic_ops.h> header file. */
/* #undef HAVE_ATOMIC_OPS_H */
/* Define to 1 if you have the <byteswap.h> header file. */
#define HAVE_BYTESWAP_H 1
/* Define to 1 if you have the declaration of `PTRACE_CONT', and to 0 if you
don't. */
#define HAVE_DECL_PTRACE_CONT 1
/* Define to 1 if you have the declaration of `PTRACE_POKEDATA', and to 0 if
you don't. */
#define HAVE_DECL_PTRACE_POKEDATA 1
/* Define to 1 if you have the declaration of `PTRACE_POKEUSER', and to 0 if
you don't. */
#if defined(__aarch64__) || defined(__mips__)
#define HAVE_DECL_PTRACE_POKEUSER 0
#else
#define HAVE_DECL_PTRACE_POKEUSER 1
#endif
/* Define to 1 if you have the declaration of `PTRACE_SINGLESTEP', and to 0 if
you don't. */
#define HAVE_DECL_PTRACE_SINGLESTEP 1
/* Define to 1 if you have the declaration of `PTRACE_SYSCALL', and to 0 if
you don't. */
#define HAVE_DECL_PTRACE_SYSCALL 1
/* Define to 1 if you have the declaration of `PTRACE_TRACEME', and to 0 if
you don't. */
#define HAVE_DECL_PTRACE_TRACEME 1
/* Define to 1 if you have the declaration of `PT_CONTINUE', and to 0 if you
don't. */
#define HAVE_DECL_PT_CONTINUE 0
/* Define to 1 if you have the declaration of `PT_GETFPREGS', and to 0 if you
don't. */
#define HAVE_DECL_PT_GETFPREGS 0
/* Define to 1 if you have the declaration of `PT_GETREGS', and to 0 if you
don't. */
#if defined(__mips__)
#define HAVE_DECL_PT_GETREGS 1
#else
#define HAVE_DECL_PT_GETREGS 0
#endif
/* Define to 1 if you have the declaration of `PT_GETREGSET', and to 0 if you
don't. */
#if defined(__aarch64__)
#define HAVE_DECL_PT_GETREGSET 1
#else
#define HAVE_DECL_PT_GETREGSET 0
#endif
/* Define to 1 if you have the declaration of `PT_IO', and to 0 if you don't.
*/
#define HAVE_DECL_PT_IO 0
/* Define to 1 if you have the declaration of `PT_STEP', and to 0 if you
don't. */
#define HAVE_DECL_PT_STEP 0
/* Define to 1 if you have the declaration of `PT_SYSCALL', and to 0 if you
don't. */
#define HAVE_DECL_PT_SYSCALL 0
/* Define to 1 if you have the declaration of `PT_TRACE_ME', and to 0 if you
don't. */
#define HAVE_DECL_PT_TRACE_ME 0
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the `dlmodinfo' function. */
#define HAVE_DLMODINFO 1
/* Define to 1 if you have the `dl_iterate_phdr' function. */
#define HAVE_DL_ITERATE_PHDR 1
/* Define to 1 if you have the `dl_phdr_removals_counter' function. */
#define HAVE_DL_PHDR_REMOVALS_COUNTER 1
/* Define to 1 if you have the <elf.h> header file. */
#define HAVE_ELF_H 1
/* Define to 1 if you have the <endian.h> header file. */
#define HAVE_ENDIAN_H 1
/* Define to 1 if you have the <execinfo.h> header file. */
/* #undef HAVE_EXECINFO_H */
/* Define to 1 if you have the `getunwind' function. */
#define HAVE_GETUNWIND 1
/* Define to 1 if you have the <ia64intrin.h> header file. */
/* #undef HAVE_IA64INTRIN_H */
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `uca' library (-luca). */
/* #undef HAVE_LIBUCA */
/* Define to 1 if you have the <link.h> header file. */
#define HAVE_LINK_H 1
/* Define if you have liblzma */
#define HAVE_LZMA 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `mincore' function. */
#define HAVE_MINCORE 1
/* Define to 1 if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if `dlpi_subs' is a member of `struct dl_phdr_info'. */
/* #undef HAVE_STRUCT_DL_PHDR_INFO_DLPI_SUBS */
/* Define to 1 if the system has the type `struct elf_prstatus'. */
/* #undef HAVE_STRUCT_ELF_PRSTATUS */
/* Define to 1 if the system has the type `struct prstatus'. */
/* #undef HAVE_STRUCT_PRSTATUS */
/* Defined if __sync atomics are available */
#define HAVE_SYNC_ATOMICS 1
/* Define to 1 if you have the <sys/elf.h> header file. */
/* #undef HAVE_SYS_ELF_H */
/* Define to 1 if you have the <sys/endian.h> header file. */
#define HAVE_SYS_ENDIAN_H 1
/* Define to 1 if you have the <sys/link.h> header file. */
/* #undef HAVE_SYS_LINK_H */
/* Define to 1 if you have the <sys/procfs.h> header file. */
/* #undef HAVE_SYS_PROCFS_H */
/* Define to 1 if you have the <sys/ptrace.h> header file. */
#define HAVE_SYS_PTRACE_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/uc_access.h> header file. */
/* #undef HAVE_SYS_UC_ACCESS_H */
/* Define to 1 if you have the `ttrace' function. */
/* #undef HAVE_TTRACE */
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Defined if __builtin_unreachable() is available */
#define HAVE__BUILTIN_UNREACHABLE 1
/* Defined if __builtin___clear_cache() is available */
#define HAVE__BUILTIN___CLEAR_CACHE 1
/* Define to 1 if __thread keyword is supported by the C compiler. */
#define HAVE___THREAD 1
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#define LT_OBJDIR ".libs/"
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
/* #undef NO_MINUS_C_MINUS_O */
/* Name of package */
#define PACKAGE "libunwind"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "libunwind-devel@nongnu.org"
/* Define to the full name of this package. */
#define PACKAGE_NAME "libunwind"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "libunwind 1.1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libunwind"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.1"
/* The size of `off_t', as computed by sizeof. */
#define SIZEOF_OFF_T 4
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "1.1"
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */

View File

@@ -1,128 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (c) 2003 Hewlett-Packard Development Company, L.P.
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
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. */
#ifndef dwarf_eh_h
#define dwarf_eh_h
#include "dwarf.h"
/* This header file defines the format of a DWARF exception-header
section (.eh_frame_hdr, pointed to by program-header
PT_GNU_EH_FRAME). The exception-header is self-describing in the
sense that the format of the addresses contained in it is expressed
as a one-byte type-descriptor called a "pointer-encoding" (PE).
The exception header encodes the address of the .eh_frame section
and optionally contains a binary search table for the
Frame Descriptor Entries (FDEs) in the .eh_frame. The contents of
.eh_frame has the format described by the DWARF v3 standard
(http://www.eagercon.com/dwarf/dwarf3std.htm), except that code
addresses may be encoded in different ways. Also, .eh_frame has
augmentations that allow encoding a language-specific data-area
(LSDA) pointer and a pointer to a personality-routine.
Details:
The Common Information Entry (CIE) associated with an FDE may
contain an augmentation string. Each character in this string has
a specific meaning and either one or two associated operands. The
operands are stored in an augmentation body which appears right
after the "return_address_register" member and before the
"initial_instructions" member. The operands appear in the order
in which the characters appear in the string. For example, if the
augmentation string is "zL", the operand for 'z' would be first in
the augmentation body and the operand for 'L' would be second.
The following characters are supported for the CIE augmentation
string:
'z': The operand for this character is a uleb128 value that gives the
length of the CIE augmentation body, not counting the length
of the uleb128 operand itself. If present, this code must
appear as the first character in the augmentation body.
'L': Indicates that the FDE's augmentation body contains an LSDA
pointer. The operand for this character is a single byte
that specifies the pointer-encoding (PE) that is used for
the LSDA pointer.
'R': Indicates that the code-pointers (FDE members
"initial_location" and "address_range" and the operand for
DW_CFA_set_loc) in the FDE have a non-default encoding. The
operand for this character is a single byte that specifies
the pointer-encoding (PE) that is used for the
code-pointers. Note: the "address_range" member is always
encoded as an absolute value. Apart from that, the specified
FDE pointer-encoding applies.
'P': Indicates the presence of a personality routine (handler).
The first operand for this character specifies the
pointer-encoding (PE) that is used for the second operand,
which specifies the address of the personality routine.
If the augmentation string contains any other characters, the
remainder of the augmentation string should be ignored.
Furthermore, if the size of the augmentation body is unknown
(i.e., 'z' is not the first character of the augmentation string),
then the entire CIE as well all associated FDEs must be ignored.
A Frame Descriptor Entries (FDE) may contain an augmentation body
which, if present, appears right after the "address_range" member
and before the "instructions" member. The contents of this body
is implicitly defined by the augmentation string of the associated
CIE. The meaning of the characters in the CIE's augmentation
string as far as FDEs are concerned is as follows:
'z': The first operand in the FDE's augmentation body specifies
the total length of the augmentation body as a uleb128 (not
counting the length of the uleb128 operand itself).
'L': The operand for this character is an LSDA pointer, encoded
in the format specified by the corresponding operand in the
CIE's augmentation body.
*/
#define DW_EH_VERSION 1 /* The version we're implementing */
struct dwarf_eh_frame_hdr
{
unsigned char version;
unsigned char eh_frame_ptr_enc;
unsigned char fde_count_enc;
unsigned char table_enc;
/* The rest of the header is variable-length and consists of the
following members:
encoded_t eh_frame_ptr;
encoded_t fde_count;
struct
{
encoded_t start_ip; // first address covered by this FDE
encoded_t fde_addr; // address of the FDE
}
binary_search_table[fde_count]; */
};
#endif /* dwarf_eh_h */

Some files were not shown because too many files have changed in this diff Show More