diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:29:04 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:29:04 -0800 |
commit | e54eebbf1a908d65ee8cf80bab62821c05666d70 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /debuggerd | |
parent | a1e1c1b106423de09bc918502e7a51d4ffe5a4ae (diff) | |
download | system_core-e54eebbf1a908d65ee8cf80bab62821c05666d70.zip system_core-e54eebbf1a908d65ee8cf80bab62821c05666d70.tar.gz system_core-e54eebbf1a908d65ee8cf80bab62821c05666d70.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'debuggerd')
-rw-r--r-- | debuggerd/Android.mk | 26 | ||||
-rw-r--r-- | debuggerd/MODULE_LICENSE_APACHE2 | 0 | ||||
-rw-r--r-- | debuggerd/NOTICE | 190 | ||||
-rw-r--r-- | debuggerd/crasher.c | 105 | ||||
-rw-r--r-- | debuggerd/crashglue.S | 28 | ||||
-rw-r--r-- | debuggerd/debuggerd.c | 852 | ||||
-rw-r--r-- | debuggerd/getevent.c | 219 | ||||
-rw-r--r-- | debuggerd/pr-support.c | 345 | ||||
-rw-r--r-- | debuggerd/unwind-arm.c | 654 | ||||
-rw-r--r-- | debuggerd/utility.c | 83 | ||||
-rw-r--r-- | debuggerd/utility.h | 56 |
11 files changed, 0 insertions, 2558 deletions
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk deleted file mode 100644 index b22e1a8..0000000 --- a/debuggerd/Android.mk +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2005 The Android Open Source Project - -ifeq ($(TARGET_ARCH),arm) - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= debuggerd.c getevent.c unwind-arm.c pr-support.c utility.c -LOCAL_CFLAGS := -Wall -LOCAL_MODULE := debuggerd - -LOCAL_STATIC_LIBRARIES := libcutils libc - -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := crasher.c -LOCAL_SRC_FILES += crashglue.S -LOCAL_MODULE := crasher -LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) -LOCAL_MODULE_TAGS := eng -#LOCAL_FORCE_STATIC_EXECUTABLE := true -LOCAL_SHARED_LIBRARIES := libcutils libc -include $(BUILD_EXECUTABLE) - -endif # TARGET_ARCH == arm diff --git a/debuggerd/MODULE_LICENSE_APACHE2 b/debuggerd/MODULE_LICENSE_APACHE2 deleted file mode 100644 index e69de29..0000000 --- a/debuggerd/MODULE_LICENSE_APACHE2 +++ /dev/null diff --git a/debuggerd/NOTICE b/debuggerd/NOTICE deleted file mode 100644 index c5b1efa..0000000 --- a/debuggerd/NOTICE +++ /dev/null @@ -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 - diff --git a/debuggerd/crasher.c b/debuggerd/crasher.c deleted file mode 100644 index f4a5a62..0000000 --- a/debuggerd/crasher.c +++ /dev/null @@ -1,105 +0,0 @@ - -//#include <cutils/misc.h> - -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sched.h> -#include <errno.h> - -#include <signal.h> -#include <sys/ptrace.h> -#include <sys/wait.h> -#include <sys/socket.h> - -#include <pthread.h> - -#include <cutils/sockets.h> - -void crash1(void); -void crashnostack(void); - -static void debuggerd_connect() -{ - char tmp[1]; - int s; - sprintf(tmp, "%d", gettid()); - s = socket_local_client("android:debuggerd", - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); - if(s >= 0) { - read(s, tmp, 1); - close(s); - } -} - -void test_call1() -{ - *((int*) 32) = 1; -} - -void *test_thread(void *x) -{ - printf("crasher: thread pid=%d tid=%d\n", getpid(), gettid()); - - sleep(1); - test_call1(); - printf("goodbye\n"); - - return 0; -} - -void *noisy(void *x) -{ - char c = (unsigned) x; - for(;;) { - usleep(250*1000); - write(2, &c, 1); - if(c == 'C') *((unsigned*) 0) = 42; - } - return 0; -} - -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; -} - -int main(int argc, char **argv) -{ - pthread_t thr; - pthread_attr_t attr; - - fprintf(stderr,"crasher: " __TIME__ "!@\n"); - fprintf(stderr,"crasher: init pid=%d tid=%d\n", getpid(), gettid()); - - if(argc > 1) { - if(!strcmp(argv[1],"nostack")) crashnostack(); - if(!strcmp(argv[1],"ctest")) return ctest(); - if(!strcmp(argv[1],"exit")) exit(1); - if(!strcmp(argv[1],"abort")) maybeabort(); - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&thr, &attr, test_thread, 0); - while(1) sleep(1); - } else { - crash1(); -// *((int*) 0) = 42; - } - - return 0; -} - -void maybeabort() -{ - if(time(0) != 42) abort(); -} diff --git a/debuggerd/crashglue.S b/debuggerd/crashglue.S deleted file mode 100644 index 888951b..0000000 --- a/debuggerd/crashglue.S +++ /dev/null @@ -1,28 +0,0 @@ -.globl crash1 -.globl crashnostack - -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 - - mov lr, #0 - ldr lr, [lr] - b . - - -crashnostack: - mov sp, #0 - mov r0, #0 - ldr r0, [r0] - b .
\ No newline at end of file diff --git a/debuggerd/debuggerd.c b/debuggerd/debuggerd.c deleted file mode 100644 index 9394e1c..0000000 --- a/debuggerd/debuggerd.c +++ /dev/null @@ -1,852 +0,0 @@ -/* system/debuggerd/debuggerd.c -** -** 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 <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <signal.h> -#include <pthread.h> -#include <stdarg.h> -#include <fcntl.h> -#include <sys/types.h> -#include <dirent.h> - -#include <sys/ptrace.h> -#include <sys/wait.h> -#include <sys/exec_elf.h> -#include <sys/stat.h> - -#include <cutils/sockets.h> -#include <cutils/logd.h> -#include <cutils/sockets.h> -#include <cutils/properties.h> - -#include <linux/input.h> - -#include <private/android_filesystem_config.h> - -#include "utility.h" - -/* Main entry point to get the backtrace from the crashing process */ -extern int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map, - unsigned int sp_list[], - int *frame0_pc_sane, - bool at_fault); - -static char **process_name_ptr; - -static int logsocket = -1; - -#define ANDROID_LOG_INFO 4 - -/* Log information onto the tombstone */ -void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...) -{ - char buf[128]; - - va_list ap; - va_start(ap, fmt); - - if (tfd >= 0) { - int len; - vsnprintf(buf, sizeof(buf), fmt, ap); - len = strlen(buf); - if(tfd >= 0) write(tfd, buf, len); - } - - if (!in_tombstone_only) - __android_log_vprint(ANDROID_LOG_INFO, "DEBUG", fmt, ap); -} - -#define LOG(fmt...) _LOG(-1, 0, fmt) -#if 0 -#define XLOG(fmt...) _LOG(-1, 0, fmt) -#else -#define XLOG(fmt...) do {} while(0) -#endif - -// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so -// 012345678901234567890123456789012345678901234567890123456789 -// 0 1 2 3 4 5 - -mapinfo *parse_maps_line(char *line) -{ - mapinfo *mi; - int len = strlen(line); - - if(len < 1) return 0; - line[--len] = 0; - - if(len < 50) return 0; - if(line[20] != 'x') return 0; - - mi = malloc(sizeof(mapinfo) + (len - 47)); - if(mi == 0) return 0; - - mi->start = strtoul(line, 0, 16); - mi->end = strtoul(line + 9, 0, 16); - /* To be filled in parse_exidx_info if the mapped section starts with - * elf_header - */ - mi->exidx_start = mi->exidx_end = 0; - mi->next = 0; - strcpy(mi->name, line + 49); - - return mi; -} - -void dump_build_info(int tfd) -{ - char fingerprint[PROPERTY_VALUE_MAX]; - - property_get("ro.build.fingerprint", fingerprint, "unknown"); - - _LOG(tfd, false, "Build fingerprint: '%s'\n", fingerprint); -} - - -void dump_stack_and_code(int tfd, int pid, mapinfo *map, - int unwind_depth, unsigned int sp_list[], - int frame0_pc_sane, bool at_fault) -{ - unsigned int sp, pc, p, end, data; - struct pt_regs r; - int sp_depth; - bool only_in_tombstone = !at_fault; - - if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return; - sp = r.ARM_sp; - pc = r.ARM_pc; - - /* Died because calling the weeds - dump - * the code around the PC in the next frame instead. - */ - if (frame0_pc_sane == 0) { - pc = r.ARM_lr; - } - - _LOG(tfd, true, "code%s:\n", frame0_pc_sane ? "" : " (around frame #01)"); - - end = p = pc & ~3; - p -= 16; - - /* Dump the code as: - * PC contents - * 00008d34 fffffcd0 4c0eb530 b0934a0e 1c05447c - * 00008d44 f7ff18a0 490ced94 68035860 d0012b00 - */ - while (p <= end) { - int i; - - _LOG(tfd, true, " %08x ", p); - for (i = 0; i < 4; i++) { - data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); - _LOG(tfd, true, " %08x", data); - p += 4; - } - _LOG(tfd, true, "\n", p); - } - - p = sp - 64; - p &= ~3; - if (unwind_depth != 0) { - if (unwind_depth < STACK_CONTENT_DEPTH) { - end = sp_list[unwind_depth-1]; - } - else { - end = sp_list[STACK_CONTENT_DEPTH-1]; - } - } - else { - end = sp | 0x000000ff; - end += 0xff; - } - - _LOG(tfd, only_in_tombstone, "stack:\n"); - - /* If the crash is due to PC == 0, there will be two frames that - * have identical SP value. - */ - if (sp_list[0] == sp_list[1]) { - sp_depth = 1; - } - else { - sp_depth = 0; - } - - while (p <= end) { - char *prompt; - char level[16]; - data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); - if (p == sp_list[sp_depth]) { - sprintf(level, "#%02d", sp_depth++); - prompt = level; - } - else { - prompt = " "; - } - - /* Print the stack content in the log for the first 3 frames. For the - * rest only print them in the tombstone file. - */ - _LOG(tfd, (sp_depth > 2) || only_in_tombstone, - "%s %08x %08x %s\n", prompt, p, data, - map_to_name(map, data, "")); - p += 4; - } - /* print another 64-byte of stack data after the last frame */ - - end = p+64; - while (p <= end) { - data = ptrace(PTRACE_PEEKTEXT, pid, (void*)p, NULL); - _LOG(tfd, (sp_depth > 2) || only_in_tombstone, - " %08x %08x %s\n", p, data, - map_to_name(map, data, "")); - p += 4; - } -} - -void dump_pc_and_lr(int tfd, int pid, mapinfo *map, int unwound_level, - bool at_fault) -{ - struct pt_regs r; - - if(ptrace(PTRACE_GETREGS, pid, 0, &r)) { - _LOG(tfd, !at_fault, "tid %d not responding!\n", pid); - return; - } - - if (unwound_level == 0) { - _LOG(tfd, !at_fault, " #%02d pc %08x %s\n", 0, r.ARM_pc, - map_to_name(map, r.ARM_pc, "<unknown>")); - } - _LOG(tfd, !at_fault, " #%02d lr %08x %s\n", 1, r.ARM_lr, - map_to_name(map, r.ARM_lr, "<unknown>")); -} - -void dump_registers(int tfd, int pid, bool at_fault) -{ - struct pt_regs r; - bool only_in_tombstone = !at_fault; - - if(ptrace(PTRACE_GETREGS, pid, 0, &r)) { - _LOG(tfd, only_in_tombstone, - "cannot get registers: %s\n", strerror(errno)); - return; - } - - _LOG(tfd, only_in_tombstone, " r0 %08x r1 %08x r2 %08x r3 %08x\n", - r.ARM_r0, r.ARM_r1, r.ARM_r2, r.ARM_r3); - _LOG(tfd, only_in_tombstone, " r4 %08x r5 %08x r6 %08x r7 %08x\n", - r.ARM_r4, r.ARM_r5, r.ARM_r6, r.ARM_r7); - _LOG(tfd, only_in_tombstone, " r8 %08x r9 %08x 10 %08x fp %08x\n", - r.ARM_r8, r.ARM_r9, r.ARM_r10, r.ARM_fp); - _LOG(tfd, only_in_tombstone, - " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n", - r.ARM_ip, r.ARM_sp, r.ARM_lr, r.ARM_pc, r.ARM_cpsr); -} - -const char *get_signame(int sig) -{ - switch(sig) { - case SIGILL: return "SIGILL"; - case SIGABRT: return "SIGABRT"; - case SIGBUS: return "SIGBUS"; - case SIGFPE: return "SIGFPE"; - case SIGSEGV: return "SIGSEGV"; - case SIGSTKFLT: return "SIGSTKFLT"; - default: return "?"; - } -} - -void dump_fault_addr(int tfd, int pid, int sig) -{ - siginfo_t si; - - memset(&si, 0, sizeof(si)); - if(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)){ - _LOG(tfd, false, "cannot get siginfo: %s\n", strerror(errno)); - } else { - _LOG(tfd, false, "signal %d (%s), fault addr %08x\n", - sig, get_signame(sig), si.si_addr); - } -} - -void dump_crash_banner(int tfd, unsigned pid, unsigned tid, int sig) -{ - char data[1024]; - char *x = 0; - FILE *fp; - - sprintf(data, "/proc/%d/cmdline", pid); - fp = fopen(data, "r"); - if(fp) { - x = fgets(data, 1024, fp); - fclose(fp); - } - - _LOG(tfd, false, - "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); - dump_build_info(tfd); - _LOG(tfd, false, "pid: %d, tid: %d >>> %s <<<\n", - pid, tid, x ? x : "UNKNOWN"); - - if(sig) dump_fault_addr(tfd, tid, sig); -} - -static void parse_exidx_info(mapinfo *milist, pid_t pid) -{ - mapinfo *mi; - for (mi = milist; mi != NULL; mi = mi->next) { - Elf32_Ehdr ehdr; - - memset(&ehdr, 0, sizeof(Elf32_Ehdr)); - /* Read in sizeof(Elf32_Ehdr) worth of data from the beginning of - * mapped section. - */ - get_remote_struct(pid, (void *) (mi->start), &ehdr, - sizeof(Elf32_Ehdr)); - /* Check if it has the matching magic words */ - if (IS_ELF(ehdr)) { - Elf32_Phdr phdr; - Elf32_Phdr *ptr; - int i; - - ptr = (Elf32_Phdr *) (mi->start + ehdr.e_phoff); - for (i = 0; i < ehdr.e_phnum; i++) { - /* Parse the program header */ - get_remote_struct(pid, (void *) ptr+i, &phdr, - sizeof(Elf32_Phdr)); - /* Found a EXIDX segment? */ - if (phdr.p_type == PT_ARM_EXIDX) { - mi->exidx_start = mi->start + phdr.p_offset; - mi->exidx_end = mi->exidx_start + phdr.p_filesz; - break; - } - } - } - } -} - -void dump_crash_report(int tfd, unsigned pid, unsigned tid, bool at_fault) -{ - char data[1024]; - FILE *fp; - mapinfo *milist = 0; - unsigned int sp_list[STACK_CONTENT_DEPTH]; - int stack_depth; - int frame0_pc_sane = 1; - - if (!at_fault) { - _LOG(tfd, true, - "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); - _LOG(tfd, true, "pid: %d, tid: %d\n", pid, tid); - } - - dump_registers(tfd, tid, at_fault); - - /* Clear stack pointer records */ - memset(sp_list, 0, sizeof(sp_list)); - - sprintf(data, "/proc/%d/maps", pid); - fp = fopen(data, "r"); - if(fp) { - while(fgets(data, 1024, fp)) { - mapinfo *mi = parse_maps_line(data); - if(mi) { - mi->next = milist; - milist = mi; - } - } - fclose(fp); - } - - parse_exidx_info(milist, tid); - - /* If stack unwinder fails, use the default solution to dump the stack - * content. - */ - stack_depth = unwind_backtrace_with_ptrace(tfd, tid, milist, sp_list, - &frame0_pc_sane, at_fault); - - /* The stack unwinder should at least unwind two levels of stack. If less - * level is seen we make sure at lease pc and lr are dumped. - */ - if (stack_depth < 2) { - dump_pc_and_lr(tfd, tid, milist, stack_depth, at_fault); - } - - dump_stack_and_code(tfd, tid, milist, stack_depth, sp_list, frame0_pc_sane, - at_fault); - - while(milist) { - mapinfo *next = milist->next; - free(milist); - milist = next; - } -} - -/* FIXME: unused: use it or lose it*/ -#if 0 -static -void start_gdbserver_vs(int pid, int port) -{ - pid_t p; - char *args[5]; - char commspec[16]; - char pidspec[16]; - - p = fork(); - if(p < 0) { - LOG("could not fork()\n"); - return; - } - - if(p == 0) { - sprintf(commspec, ":%d", port); - sprintf(pidspec, "%d", pid); - args[0] = "/system/bin/gdbserver"; - args[1] = commspec; - args[2] = "--attach"; - args[3] = pidspec; - args[4] = 0; - exit(execv(args[0], args)); - } else { - LOG("gdbserver pid=%d port=%d targetpid=%d\n", - p, port, pid); - - sleep(5); - } -} -#endif - -#define MAX_TOMBSTONES 10 - -#define typecheck(x,y) { \ - typeof(x) __dummy1; \ - typeof(y) __dummy2; \ - (void)(&__dummy1 == &__dummy2); } - -#define TOMBSTONE_DIR "/data/tombstones" - -/* - * find_and_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. - */ -static int find_and_open_tombstone(void) -{ - unsigned long mtime = ULONG_MAX; - struct stat sb; - char path[128]; - int fd, i, oldest = 0; - - /* - * XXX: Our stat.st_mtime isn't time_t. If it changes, as it probably ought - * to, our logic breaks. This check will generate a warning if that happens. - */ - typecheck(mtime, sb.st_mtime); - - /* - * In a single wolf-like pass, find an available slot and, in case none - * exist, find and record the least-recently-modified file. - */ - for (i = 0; i < MAX_TOMBSTONES; i++) { - snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", i); - - if (!stat(path, &sb)) { - if (sb.st_mtime < mtime) { - oldest = i; - mtime = sb.st_mtime; - } - continue; - } - if (errno != ENOENT) - continue; - - fd = open(path, O_CREAT | O_EXCL | O_WRONLY, 0600); - if (fd < 0) - continue; /* raced ? */ - - fchown(fd, AID_SYSTEM, AID_SYSTEM); - return fd; - } - - /* we didn't find an available file, so we clobber the oldest one */ - snprintf(path, sizeof(path), TOMBSTONE_DIR"/tombstone_%02d", oldest); - fd = open(path, O_CREAT | O_TRUNC | O_WRONLY, 0600); - fchown(fd, AID_SYSTEM, AID_SYSTEM); - - return fd; -} - -/* Return true if some thread is not detached cleanly */ -static bool dump_sibling_thread_report(int tfd, unsigned pid, unsigned tid) -{ - char task_path[1024]; - - sprintf(task_path, "/proc/%d/task", pid); - DIR *d; - struct dirent *de; - int need_cleanup = 0; - - d = opendir(task_path); - /* Bail early if cannot open the task directory */ - if (d == NULL) { - XLOG("Cannot open /proc/%d/task\n", pid); - return false; - } - while ((de = readdir(d)) != NULL) { - unsigned new_tid; - /* Ignore "." and ".." */ - if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) - continue; - new_tid = atoi(de->d_name); - /* The main thread at fault has been handled individually */ - if (new_tid == tid) - continue; - - /* Skip this thread if cannot ptrace it */ - if (ptrace(PTRACE_ATTACH, new_tid, 0, 0) < 0) - continue; - - dump_crash_report(tfd, pid, new_tid, false); - need_cleanup |= ptrace(PTRACE_DETACH, new_tid, 0, 0); - } - closedir(d); - return need_cleanup != 0; -} - -/* Return true if some thread is not detached cleanly */ -static bool engrave_tombstone(unsigned pid, unsigned tid, int debug_uid, - int signal) -{ - int fd; - bool need_cleanup = false; - - mkdir(TOMBSTONE_DIR, 0755); - chown(TOMBSTONE_DIR, AID_SYSTEM, AID_SYSTEM); - - fd = find_and_open_tombstone(); - if (fd < 0) - return need_cleanup; - - dump_crash_banner(fd, pid, tid, signal); - dump_crash_report(fd, pid, tid, true); - /* - * If the user has requested to attach gdb, don't collect the per-thread - * information as it increases the chance to lose track of the process. - */ - if ((signed)pid > debug_uid) { - need_cleanup = dump_sibling_thread_report(fd, pid, tid); - } - - close(fd); - return need_cleanup; -} - -static int -write_string(const char* file, const char* string) -{ - int len; - int fd; - ssize_t amt; - fd = open(file, O_RDWR); - len = strlen(string); - if (fd < 0) - return -errno; - amt = write(fd, string, len); - close(fd); - return amt >= 0 ? 0 : -errno; -} - -static -void init_debug_led(void) -{ - // trout leds - write_string("/sys/class/leds/red/brightness", "0"); - write_string("/sys/class/leds/green/brightness", "0"); - write_string("/sys/class/leds/blue/brightness", "0"); - write_string("/sys/class/leds/red/device/blink", "0"); - // sardine leds - write_string("/sys/class/leds/left/cadence", "0,0"); -} - -static -void enable_debug_led(void) -{ - // trout leds - write_string("/sys/class/leds/red/brightness", "255"); - // sardine leds - write_string("/sys/class/leds/left/cadence", "1,0"); -} - -static -void disable_debug_led(void) -{ - // trout leds - write_string("/sys/class/leds/red/brightness", "0"); - // sardine leds - write_string("/sys/class/leds/left/cadence", "0,0"); -} - -extern int init_getevent(); -extern void uninit_getevent(); -extern int get_event(struct input_event* event, int timeout); - -static void wait_for_user_action(unsigned tid, struct ucred* cr) -{ - (void)tid; - /* First log a helpful message */ - LOG( "********************************************************\n" - "* process %d crashed. debuggerd waiting for gdbserver \n" - "* \n" - "* adb shell gdbserver :port --attach %d & \n" - "* \n" - "* and press the HOME key. \n" - "********************************************************\n", - cr->pid, cr->pid); - - /* wait for HOME key */ - if (init_getevent() == 0) { - int ms = 1200 / 10; - int dit = 1; - int dah = 3*dit; - int _ = -dit; - int ___ = 3*_; - int _______ = 7*_; - const signed char codes[] = { - dit,_,dit,_,dit,___,dah,_,dah,_,dah,___,dit,_,dit,_,dit,_______ - }; - size_t s = 0; - struct input_event e; - int home = 0; - init_debug_led(); - enable_debug_led(); - do { - int timeout = abs((int)(codes[s])) * ms; - int res = get_event(&e, timeout); - if (res == 0) { - if (e.type==EV_KEY && e.code==KEY_HOME && e.value==0) - home = 1; - } else if (res == 1) { - if (++s >= sizeof(codes)/sizeof(*codes)) - s = 0; - if (codes[s] > 0) { - enable_debug_led(); - } else { - disable_debug_led(); - } - } - } while (!home); - uninit_getevent(); - } - - /* don't forget to turn debug led off */ - disable_debug_led(); - - /* close filedescriptor */ - LOG("debuggerd resuming process %d", cr->pid); - } - -static void handle_crashing_process(int fd) -{ - char buf[64]; - struct stat s; - unsigned tid; - struct ucred cr; - int n, len, status; - int tid_attach_status = -1; - unsigned retry = 30; - bool need_cleanup = false; - - char value[PROPERTY_VALUE_MAX]; - property_get("debug.db.uid", value, "-1"); - int debug_uid = atoi(value); - - XLOG("handle_crashing_process(%d)\n", fd); - - len = sizeof(cr); - n = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len); - if(n != 0) { - LOG("cannot get credentials\n"); - goto done; - } - - XLOG("reading tid\n"); - fcntl(fd, F_SETFL, O_NONBLOCK); - while((n = read(fd, &tid, sizeof(unsigned))) != sizeof(unsigned)) { - if(errno == EINTR) continue; - if(errno == EWOULDBLOCK) { - if(retry-- > 0) { - usleep(100 * 1000); - continue; - } - LOG("timed out reading tid\n"); - goto done; - } - LOG("read failure? %s\n", strerror(errno)); - goto done; - } - - sprintf(buf,"/proc/%d/task/%d", cr.pid, tid); - if(stat(buf, &s)) { - LOG("tid %d does not exist in pid %d. ignorning debug request\n", - tid, cr.pid); - close(fd); - return; - } - - XLOG("BOOM: pid=%d uid=%d gid=%d tid=%d\n", cr.pid, cr.uid, cr.gid, tid); - - tid_attach_status = ptrace(PTRACE_ATTACH, tid, 0, 0); - if(tid_attach_status < 0) { - LOG("ptrace attach failed: %s\n", strerror(errno)); - goto done; - } - - close(fd); - fd = -1; - - for(;;) { - n = waitpid(tid, &status, __WALL); - - if(n < 0) { - if(errno == EAGAIN) continue; - LOG("waitpid failed: %s\n", strerror(errno)); - goto done; - } - - XLOG("waitpid: n=%d status=%08x\n", n, status); - - if(WIFSTOPPED(status)){ - n = WSTOPSIG(status); - switch(n) { - case SIGSTOP: - XLOG("stopped -- continuing\n"); - n = ptrace(PTRACE_CONT, tid, 0, 0); - if(n) { - LOG("ptrace failed: %s\n", strerror(errno)); - goto done; - } - continue; - - case SIGILL: - case SIGABRT: - case SIGBUS: - case SIGFPE: - case SIGSEGV: - case SIGSTKFLT: { - XLOG("stopped -- fatal signal\n"); - need_cleanup = engrave_tombstone(cr.pid, tid, debug_uid, n); - kill(tid, SIGSTOP); - goto done; - } - - default: - XLOG("stopped -- unexpected signal\n"); - goto done; - } - } else { - XLOG("unexpected waitpid response\n"); - goto done; - } - } - -done: - XLOG("detaching\n"); - - /* stop the process so we can debug */ - kill(cr.pid, SIGSTOP); - - /* - * If a thread has been attached by ptrace, make sure it is detached - * successfully otherwise we will get a zombie. - */ - if (tid_attach_status == 0) { - int detach_status; - /* detach so we can attach gdbserver */ - detach_status = ptrace(PTRACE_DETACH, tid, 0, 0); - need_cleanup |= (detach_status != 0); - } - - /* - * if debug.db.uid is set, its value indicates if we should wait - * for user action for the crashing process. - * in this case, we log a message and turn the debug LED on - * waiting for a gdb connection (for instance) - */ - - if ((signed)cr.uid <= debug_uid) { - wait_for_user_action(tid, &cr); - } - - /* resume stopped process (so it can crash in peace) */ - kill(cr.pid, SIGCONT); - - if (need_cleanup) { - LOG("debuggerd committing suicide to free the zombie!\n"); - kill(getpid(), SIGKILL); - } - - if(fd != -1) close(fd); -} - -int main(int argc, char **argv) -{ - int s; - struct sigaction act; - - process_name_ptr = argv; - - logsocket = socket_local_client("logd", - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_DGRAM); - if(logsocket < 0) { - logsocket = -1; - } else { - fcntl(logsocket, F_SETFD, FD_CLOEXEC); - } - - act.sa_handler = SIG_DFL; - sigemptyset(&act.sa_mask); - sigaddset(&act.sa_mask,SIGCHLD); - act.sa_flags = SA_NOCLDWAIT; - sigaction(SIGCHLD, &act, 0); - - s = socket_local_server("android:debuggerd", - ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM); - if(s < 0) return -1; - fcntl(s, F_SETFD, FD_CLOEXEC); - - LOG("debuggerd: " __DATE__ " " __TIME__ "\n"); - - for(;;) { - struct sockaddr addr; - socklen_t alen; - int fd; - - alen = sizeof(addr); - fd = accept(s, &addr, &alen); - if(fd < 0) continue; - - fcntl(fd, F_SETFD, FD_CLOEXEC); - - handle_crashing_process(fd); - } - return 0; -} diff --git a/debuggerd/getevent.c b/debuggerd/getevent.c deleted file mode 100644 index ebd070c..0000000 --- a/debuggerd/getevent.c +++ /dev/null @@ -1,219 +0,0 @@ -#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) { - //fprintf(stderr, "could not get device name for %s, %s\n", device, strerror(errno)); - name[0] = '\0'; - } - if(ioctl(fd, EVIOCGPHYS(sizeof(location) - 1), &location) < 1) { - //fprintf(stderr, "could not get location for %s, %s\n", device, strerror(errno)); - location[0] = '\0'; - } - if(ioctl(fd, EVIOCGUNIQ(sizeof(idstr) - 1), &idstr) < 1) { - //fprintf(stderr, "could not get idstring for %s, %s\n", device, strerror(errno)); - idstr[0] = '\0'; - } - - new_ufds = 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 = 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; - } - //printf("got %d bytes of event information\n", res); - - strcpy(devname, dirname); - filename = devname + strlen(devname); - *filename++ = '/'; - - while(res >= (int)sizeof(*event)) { - event = (struct inotify_event *)(event_buf + event_pos); - //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); - 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 = 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 < (int)sizeof(event)) { - fprintf(stderr, "could not get event\n"); - return -1; - } - return 0; - } - } - } - } - return 0; -} diff --git a/debuggerd/pr-support.c b/debuggerd/pr-support.c deleted file mode 100644 index 358d9b7..0000000 --- a/debuggerd/pr-support.c +++ /dev/null @@ -1,345 +0,0 @@ -/* ARM EABI compliant unwinding routines - Copyright (C) 2004, 2005 Free Software Foundation, Inc. - Contributed by Paul Brook - - This file is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - In addition to the permissions in the GNU General Public License, the - Free Software Foundation gives you unlimited permission to link the - compiled version of this file into combinations with other programs, - and to distribute those combinations without any restriction coming - from the use of this file. (The General Public License restrictions - do apply in other respects; for example, they cover modification of - the file, and distribution when not linked into a combine - executable.) - - This file is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/**************************************************************************** - * The functions here are derived from gcc/config/arm/pr-support.c from the - * 4.3.x release. The main changes here involve the use of ptrace to retrieve - * memory/processor states from a remote process. - ****************************************************************************/ - -#include <sys/types.h> -#include <unwind.h> - -#include "utility.h" - -/* We add a prototype for abort here to avoid creating a dependency on - target headers. */ -extern void abort (void); - -/* Derived from _Unwind_VRS_Pop to use ptrace */ -extern _Unwind_VRS_Result -unwind_VRS_Pop_with_ptrace (_Unwind_Context *context, - _Unwind_VRS_RegClass regclass, - _uw discriminator, - _Unwind_VRS_DataRepresentation representation, - pid_t pid); - -typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */ - -/* Misc constants. */ -#define R_IP 12 -#define R_SP 13 -#define R_LR 14 -#define R_PC 15 - -#define uint32_highbit (((_uw) 1) << 31) - -void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp); - -/* Unwind descriptors. */ - -typedef struct -{ - _uw16 length; - _uw16 offset; -} EHT16; - -typedef struct -{ - _uw length; - _uw offset; -} EHT32; - -/* Personality routine helper functions. */ - -#define CODE_FINISH (0xb0) - -/* Derived from next_unwind_byte to use ptrace */ -/* Return the next byte of unwinding information, or CODE_FINISH if there is - no data remaining. */ -static inline _uw8 -next_unwind_byte_with_ptrace (__gnu_unwind_state * uws, pid_t pid) -{ - _uw8 b; - - if (uws->bytes_left == 0) - { - /* Load another word */ - if (uws->words_left == 0) - return CODE_FINISH; /* Nothing left. */ - uws->words_left--; - uws->data = get_remote_word(pid, uws->next); - uws->next++; - uws->bytes_left = 3; - } - else - uws->bytes_left--; - - /* Extract the most significant byte. */ - b = (uws->data >> 24) & 0xff; - uws->data <<= 8; - return b; -} - -/* Execute the unwinding instructions described by UWS. */ -_Unwind_Reason_Code -unwind_execute_with_ptrace(_Unwind_Context * context, __gnu_unwind_state * uws, - pid_t pid) -{ - _uw op; - int set_pc; - _uw reg; - - set_pc = 0; - for (;;) - { - op = next_unwind_byte_with_ptrace (uws, pid); - if (op == CODE_FINISH) - { - /* If we haven't already set pc then copy it from lr. */ - if (!set_pc) - { - _Unwind_VRS_Get (context, _UVRSC_CORE, R_LR, _UVRSD_UINT32, - ®); - _Unwind_VRS_Set (context, _UVRSC_CORE, R_PC, _UVRSD_UINT32, - ®); - set_pc = 1; - } - /* Drop out of the loop. */ - break; - } - if ((op & 0x80) == 0) - { - /* vsp = vsp +- (imm6 << 2 + 4). */ - _uw offset; - - offset = ((op & 0x3f) << 2) + 4; - _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); - if (op & 0x40) - reg -= offset; - else - reg += offset; - _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); - continue; - } - - if ((op & 0xf0) == 0x80) - { - op = (op << 8) | next_unwind_byte_with_ptrace (uws, pid); - if (op == 0x8000) - { - /* Refuse to unwind. */ - return _URC_FAILURE; - } - /* Pop r4-r15 under mask. */ - op = (op << 4) & 0xfff0; - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, op, _UVRSD_UINT32, - pid) - != _UVRSR_OK) - return _URC_FAILURE; - if (op & (1 << R_PC)) - set_pc = 1; - continue; - } - if ((op & 0xf0) == 0x90) - { - op &= 0xf; - if (op == 13 || op == 15) - /* Reserved. */ - return _URC_FAILURE; - /* vsp = r[nnnn]. */ - _Unwind_VRS_Get (context, _UVRSC_CORE, op, _UVRSD_UINT32, ®); - _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, ®); - continue; - } - if ((op & 0xf0) == 0xa0) - { - /* Pop r4-r[4+nnn], [lr]. */ - _uw mask; - - mask = (0xff0 >> (7 - (op & 7))) & 0xff0; - if (op & 8) - mask |= (1 << R_LR); - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, mask, _UVRSD_UINT32, - pid) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if ((op & 0xf0) == 0xb0) - { - /* op == 0xb0 already handled. */ - if (op == 0xb1) - { - op = next_unwind_byte_with_ptrace (uws, pid); - if (op == 0 || ((op & 0xf0) != 0)) - /* Spare. */ - return _URC_FAILURE; - /* Pop r0-r4 under mask. */ - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_CORE, op, - _UVRSD_UINT32, pid) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if (op == 0xb2) - { - /* vsp = vsp + 0x204 + (uleb128 << 2). */ - int shift; - - _Unwind_VRS_Get (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, - ®); - op = next_unwind_byte_with_ptrace (uws, pid); - shift = 2; - while (op & 0x80) - { - reg += ((op & 0x7f) << shift); - shift += 7; - op = next_unwind_byte_with_ptrace (uws, pid); - } - reg += ((op & 0x7f) << shift) + 0x204; - _Unwind_VRS_Set (context, _UVRSC_CORE, R_SP, _UVRSD_UINT32, - ®); - continue; - } - if (op == 0xb3) - { - /* Pop VFP registers with fldmx. */ - op = next_unwind_byte_with_ptrace (uws, pid); - op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_VFPX, - pid) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if ((op & 0xfc) == 0xb4) - { - /* Pop FPA E[4]-E[4+nn]. */ - op = 0x40000 | ((op & 3) + 1); - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_FPA, op, _UVRSD_FPAX, - pid) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - /* op & 0xf8 == 0xb8. */ - /* Pop VFP D[8]-D[8+nnn] with fldmx. */ - op = 0x80000 | ((op & 7) + 1); - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_VFPX, pid) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if ((op & 0xf0) == 0xc0) - { - if (op == 0xc6) - { - /* Pop iWMMXt D registers. */ - op = next_unwind_byte_with_ptrace (uws, pid); - op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXD, op, - _UVRSD_UINT64, pid) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if (op == 0xc7) - { - op = next_unwind_byte_with_ptrace (uws, pid); - if (op == 0 || (op & 0xf0) != 0) - /* Spare. */ - return _URC_FAILURE; - /* Pop iWMMXt wCGR{3,2,1,0} under mask. */ - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXC, op, - _UVRSD_UINT32, pid) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if ((op & 0xf8) == 0xc0) - { - /* Pop iWMMXt wR[10]-wR[10+nnn]. */ - op = 0xa0000 | ((op & 0xf) + 1); - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_WMMXD, op, - _UVRSD_UINT64, pid) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - if (op == 0xc8) - { -#ifndef __VFP_FP__ - /* Pop FPA registers. */ - op = next_unwind_byte_with_ptrace (uws, pid); - op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_FPA, op, _UVRSD_FPAX, - pid) - != _UVRSR_OK) - return _URC_FAILURE; - continue; -#else - /* Pop VFPv3 registers D[16+ssss]-D[16+ssss+cccc] with vldm. */ - op = next_unwind_byte_with_ptrace (uws, pid); - op = (((op & 0xf0) + 16) << 12) | ((op & 0xf) + 1); - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, - _UVRSD_DOUBLE, pid) - != _UVRSR_OK) - return _URC_FAILURE; - continue; -#endif - } - if (op == 0xc9) - { - /* Pop VFP registers with fldmd. */ - op = next_unwind_byte_with_ptrace (uws, pid); - op = ((op & 0xf0) << 12) | ((op & 0xf) + 1); - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, - _UVRSD_DOUBLE, pid) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - /* Spare. */ - return _URC_FAILURE; - } - if ((op & 0xf8) == 0xd0) - { - /* Pop VFP D[8]-D[8+nnn] with fldmd. */ - op = 0x80000 | ((op & 7) + 1); - if (unwind_VRS_Pop_with_ptrace (context, _UVRSC_VFP, op, _UVRSD_DOUBLE, - pid) - != _UVRSR_OK) - return _URC_FAILURE; - continue; - } - /* Spare. */ - return _URC_FAILURE; - } - return _URC_OK; -} diff --git a/debuggerd/unwind-arm.c b/debuggerd/unwind-arm.c deleted file mode 100644 index 9642d2e..0000000 --- a/debuggerd/unwind-arm.c +++ /dev/null @@ -1,654 +0,0 @@ -/* ARM EABI compliant unwinding routines. - Copyright (C) 2004, 2005 Free Software Foundation, Inc. - Contributed by Paul Brook - - This file is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - In addition to the permissions in the GNU General Public License, the - Free Software Foundation gives you unlimited permission to link the - compiled version of this file into combinations with other programs, - and to distribute those combinations without any restriction coming - from the use of this file. (The General Public License restrictions - do apply in other respects; for example, they cover modification of - the file, and distribution when not linked into a combine - executable.) - - This file is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; see the file COPYING. If not, write to - the Free Software Foundation, 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ - -/**************************************************************************** - * The functions here are derived from gcc/config/arm/unwind-arm.c from the - * 4.3.x release. The main changes here involve the use of ptrace to retrieve - * memory/processor states from a remote process. - ****************************************************************************/ - -#include <cutils/logd.h> -#include <sys/ptrace.h> -#include <unwind.h> -#include "utility.h" - -typedef struct _ZSt9type_info type_info; /* This names C++ type_info type */ - -void __attribute__((weak)) __cxa_call_unexpected(_Unwind_Control_Block *ucbp); -bool __attribute__((weak)) __cxa_begin_cleanup(_Unwind_Control_Block *ucbp); -bool __attribute__((weak)) __cxa_type_match(_Unwind_Control_Block *ucbp, - const type_info *rttip, - bool is_reference, - void **matched_object); - -/* Misc constants. */ -#define R_IP 12 -#define R_SP 13 -#define R_LR 14 -#define R_PC 15 - -#define EXIDX_CANTUNWIND 1 -#define uint32_highbit (((_uw) 1) << 31) - -#define UCB_FORCED_STOP_FN(ucbp) ((ucbp)->unwinder_cache.reserved1) -#define UCB_PR_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved2) -#define UCB_SAVED_CALLSITE_ADDR(ucbp) ((ucbp)->unwinder_cache.reserved3) -#define UCB_FORCED_STOP_ARG(ucbp) ((ucbp)->unwinder_cache.reserved4) - -struct core_regs -{ - _uw r[16]; -}; - -/* We use normal integer types here to avoid the compiler generating - coprocessor instructions. */ -struct vfp_regs -{ - _uw64 d[16]; - _uw pad; -}; - -struct vfpv3_regs -{ - /* Always populated via VSTM, so no need for the "pad" field from - vfp_regs (which is used to store the format word for FSTMX). */ - _uw64 d[16]; -}; - -struct fpa_reg -{ - _uw w[3]; -}; - -struct fpa_regs -{ - struct fpa_reg f[8]; -}; - -struct wmmxd_regs -{ - _uw64 wd[16]; -}; - -struct wmmxc_regs -{ - _uw wc[4]; -}; - -/* Unwind descriptors. */ - -typedef struct -{ - _uw16 length; - _uw16 offset; -} EHT16; - -typedef struct -{ - _uw length; - _uw offset; -} EHT32; - -/* The ABI specifies that the unwind routines may only use core registers, - except when actually manipulating coprocessor state. This allows - us to write one implementation that works on all platforms by - demand-saving coprocessor registers. - - During unwinding we hold the coprocessor state in the actual hardware - registers and allocate demand-save areas for use during phase1 - unwinding. */ - -typedef struct -{ - /* The first fields must be the same as a phase2_vrs. */ - _uw demand_save_flags; - struct core_regs core; - _uw prev_sp; /* Only valid during forced unwinding. */ - struct vfp_regs vfp; - struct vfpv3_regs vfp_regs_16_to_31; - struct fpa_regs fpa; - struct wmmxd_regs wmmxd; - struct wmmxc_regs wmmxc; -} phase1_vrs; - -/* This must match the structure created by the assembly wrappers. */ -typedef struct -{ - _uw demand_save_flags; - struct core_regs core; -} phase2_vrs; - - -/* An exception index table entry. */ - -typedef struct __EIT_entry -{ - _uw fnoffset; - _uw content; -} __EIT_entry; - -/* Derived version to use ptrace */ -typedef _Unwind_Reason_Code (*personality_routine_with_ptrace) - (_Unwind_State, - _Unwind_Control_Block *, - _Unwind_Context *, - pid_t); - -/* Derived version to use ptrace */ -/* ABI defined personality routines. */ -static _Unwind_Reason_Code unwind_cpp_pr0_with_ptrace (_Unwind_State, - _Unwind_Control_Block *, _Unwind_Context *, pid_t); -static _Unwind_Reason_Code unwind_cpp_pr1_with_ptrace (_Unwind_State, - _Unwind_Control_Block *, _Unwind_Context *, pid_t); -static _Unwind_Reason_Code unwind_cpp_pr2_with_ptrace (_Unwind_State, - _Unwind_Control_Block *, _Unwind_Context *, pid_t); - -/* Execute the unwinding instructions described by UWS. */ -extern _Unwind_Reason_Code -unwind_execute_with_ptrace(_Unwind_Context * context, __gnu_unwind_state * uws, - pid_t pid); - -/* Derived version to use ptrace. Only handles core registers. Disregards - * FP and others. - */ -/* ABI defined function to pop registers off the stack. */ - -_Unwind_VRS_Result unwind_VRS_Pop_with_ptrace (_Unwind_Context *context, - _Unwind_VRS_RegClass regclass, - _uw discriminator, - _Unwind_VRS_DataRepresentation representation, - pid_t pid) -{ - phase1_vrs *vrs = (phase1_vrs *) context; - - switch (regclass) - { - case _UVRSC_CORE: - { - _uw *ptr; - _uw mask; - int i; - - if (representation != _UVRSD_UINT32) - return _UVRSR_FAILED; - - mask = discriminator & 0xffff; - ptr = (_uw *) vrs->core.r[R_SP]; - /* Pop the requested registers. */ - for (i = 0; i < 16; i++) - { - if (mask & (1 << i)) { - vrs->core.r[i] = get_remote_word(pid, ptr); - ptr++; - } - } - /* Writeback the stack pointer value if it wasn't restored. */ - if ((mask & (1 << R_SP)) == 0) - vrs->core.r[R_SP] = (_uw) ptr; - } - return _UVRSR_OK; - - default: - return _UVRSR_FAILED; - } -} - -/* Core unwinding functions. */ - -/* Calculate the address encoded by a 31-bit self-relative offset at address - P. */ -static inline _uw -selfrel_offset31 (const _uw *p, pid_t pid) -{ - _uw offset = get_remote_word(pid, (void*)p); - - //offset = *p; - /* Sign extend to 32 bits. */ - if (offset & (1 << 30)) - offset |= 1u << 31; - else - offset &= ~(1u << 31); - - return offset + (_uw) p; -} - - -/* Perform a binary search for RETURN_ADDRESS in TABLE. The table contains - NREC entries. */ - -static const __EIT_entry * -search_EIT_table (const __EIT_entry * table, int nrec, _uw return_address, - pid_t pid) -{ - _uw next_fn; - _uw this_fn; - int n, left, right; - - if (nrec == 0) - return (__EIT_entry *) 0; - - left = 0; - right = nrec - 1; - - while (1) - { - n = (left + right) / 2; - this_fn = selfrel_offset31 (&table[n].fnoffset, pid); - if (n != nrec - 1) - next_fn = selfrel_offset31 (&table[n + 1].fnoffset, pid) - 1; - else - next_fn = (_uw)0 - 1; - - if (return_address < this_fn) - { - if (n == left) - return (__EIT_entry *) 0; - right = n - 1; - } - else if (return_address <= next_fn) - return &table[n]; - else - left = n + 1; - } -} - -/* Find the exception index table eintry for the given address. */ -static const __EIT_entry* -get_eitp(_uw return_address, pid_t pid, mapinfo *map, mapinfo **containing_map) -{ - const __EIT_entry *eitp = NULL; - int nrec; - mapinfo *mi; - - /* The return address is the address of the instruction following the - call instruction (plus one in thumb mode). If this was the last - instruction in the function the address will lie in the following - function. Subtract 2 from the address so that it points within the call - instruction itself. */ - if (return_address >= 2) - return_address -= 2; - - for (mi = map; mi != NULL; mi = mi->next) { - if (return_address >= mi->start && return_address <= mi->end) break; - } - - if (mi) { - if (containing_map) *containing_map = mi; - eitp = (__EIT_entry *) mi->exidx_start; - nrec = (mi->exidx_end - mi->exidx_start)/sizeof(__EIT_entry); - eitp = search_EIT_table (eitp, nrec, return_address, pid); - } - return eitp; -} - -/* Find the exception index table eintry for the given address. - Fill in the relevant fields of the UCB. - Returns _URC_FAILURE if an error occurred, _URC_OK on success. */ - -static _Unwind_Reason_Code -get_eit_entry (_Unwind_Control_Block *ucbp, _uw return_address, pid_t pid, - mapinfo *map, mapinfo **containing_map) -{ - const __EIT_entry *eitp; - - eitp = get_eitp(return_address, pid, map, containing_map); - - if (!eitp) - { - UCB_PR_ADDR (ucbp) = 0; - return _URC_FAILURE; - } - ucbp->pr_cache.fnstart = selfrel_offset31 (&eitp->fnoffset, pid); - - _uw eitp_content = get_remote_word(pid, (void *)&eitp->content); - - /* Can this frame be unwound at all? */ - if (eitp_content == EXIDX_CANTUNWIND) - { - UCB_PR_ADDR (ucbp) = 0; - return _URC_END_OF_STACK; - } - - /* Obtain the address of the "real" __EHT_Header word. */ - - if (eitp_content & uint32_highbit) - { - /* It is immediate data. */ - ucbp->pr_cache.ehtp = (_Unwind_EHT_Header *)&eitp->content; - ucbp->pr_cache.additional = 1; - } - else - { - /* The low 31 bits of the content field are a self-relative - offset to an _Unwind_EHT_Entry structure. */ - ucbp->pr_cache.ehtp = - (_Unwind_EHT_Header *) selfrel_offset31 (&eitp->content, pid); - ucbp->pr_cache.additional = 0; - } - - /* Discover the personality routine address. */ - if (get_remote_word(pid, ucbp->pr_cache.ehtp) & (1u << 31)) - { - /* One of the predefined standard routines. */ - _uw idx = (get_remote_word(pid, ucbp->pr_cache.ehtp) >> 24) & 0xf; - if (idx == 0) - UCB_PR_ADDR (ucbp) = (_uw) &unwind_cpp_pr0_with_ptrace; - else if (idx == 1) - UCB_PR_ADDR (ucbp) = (_uw) &unwind_cpp_pr1_with_ptrace; - else if (idx == 2) - UCB_PR_ADDR (ucbp) = (_uw) &unwind_cpp_pr2_with_ptrace; - else - { /* Failed */ - UCB_PR_ADDR (ucbp) = 0; - return _URC_FAILURE; - } - } - else - { - /* Execute region offset to PR */ - UCB_PR_ADDR (ucbp) = selfrel_offset31 (ucbp->pr_cache.ehtp, pid); - /* Since we are unwinding the stack from a different process, it is - * impossible to execute the personality routine in debuggerd. Punt here. - */ - return _URC_FAILURE; - } - return _URC_OK; -} - -/* Print out the current call level, pc, and module name in the crash log */ -static _Unwind_Reason_Code log_function(_Unwind_Context *context, pid_t pid, - int tfd, - int stack_level, - mapinfo *map, - unsigned int sp_list[], - bool at_fault) -{ - _uw pc; - _uw rel_pc; - phase2_vrs *vrs = (phase2_vrs*) context; - const mapinfo *mi; - bool only_in_tombstone = !at_fault; - - if (stack_level < STACK_CONTENT_DEPTH) { - sp_list[stack_level] = vrs->core.r[R_SP]; - } - pc = vrs->core.r[R_PC]; - - // Top level frame - if (stack_level == 0) { - pc &= ~1; - } - // For deeper framers, rollback pc by one instruction - else { - pc = vrs->core.r[R_PC]; - /* Thumb mode - need to check whether the bl(x) has long offset or not. - * Examples: - * - * arm blx in the middle of thumb: - * 187ae: 2300 movs r3, #0 - * 187b0: f7fe ee1c blx 173ec - * 187b4: 2c00 cmp r4, #0 - * - * arm bl in the middle of thumb: - * 187d8: 1c20 adds r0, r4, #0 - * 187da: f136 fd15 bl 14f208 - * 187de: 2800 cmp r0, #0 - * - * pure thumb: - * 18894: 189b adds r3, r3, r2 - * 18896: 4798 blx r3 - * 18898: b001 add sp, #4 - */ - if (pc & 1) { - _uw prev_word; - pc = (pc & ~1); - prev_word = get_remote_word(pid, (void *) pc-4); - // Long offset - if ((prev_word & 0xf0000000) == 0xf0000000 && - (prev_word & 0x0000e000) == 0x0000e000) { - pc -= 4; - } - else { - pc -= 2; - } - } - else { - pc -= 4; - } - } - - /* We used to print the absolute PC in the back trace, and mask out the top - * 3 bits to guesstimate the offset in the .so file. This is not working for - * non-prelinked libraries since the starting offset may not be aligned on - * 1MB boundaries, and the library may be larger than 1MB. So for .so - * addresses we print the relative offset in back trace. - */ - rel_pc = pc; - mi = pc_to_mapinfo(map, pc, &rel_pc); - - _LOG(tfd, only_in_tombstone, - " #%02d pc %08x %s\n", stack_level, rel_pc, - mi ? mi->name : ""); - - return _URC_NO_REASON; -} - -/* Derived from __gnu_Unwind_Backtrace to use ptrace */ -/* Perform stack backtrace through unwind data. Return the level of stack it - * unwinds. - */ -int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map, - unsigned int sp_list[], int *frame0_pc_sane, - bool at_fault) -{ - phase1_vrs saved_vrs; - _Unwind_Reason_Code code = _URC_OK; - struct pt_regs r; - int i; - int stack_level = 0; - - _Unwind_Control_Block ucb; - _Unwind_Control_Block *ucbp = &ucb; - - if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return 0; - - for (i = 0; i < 16; i++) { - saved_vrs.core.r[i] = r.uregs[i]; - /* - _LOG(tfd, "r[%d] = 0x%x\n", i, saved_vrs.core.r[i]); - */ - } - - /* Set demand-save flags. */ - saved_vrs.demand_save_flags = ~(_uw) 0; - - /* - * If the app crashes because of calling the weeds, we cannot pass the PC - * to the usual unwinding code as the EXIDX mapping will fail. - * Instead, we simply print out the 0 as the top frame, and resume the - * unwinding process with the value stored in LR. - */ - if (get_eitp(saved_vrs.core.r[R_PC], pid, map, NULL) == NULL) { - *frame0_pc_sane = 0; - log_function ((_Unwind_Context *) &saved_vrs, pid, tfd, stack_level, - map, sp_list, at_fault); - saved_vrs.core.r[R_PC] = saved_vrs.core.r[R_LR]; - stack_level++; - } - - do { - mapinfo *this_map = NULL; - /* Find the entry for this routine. */ - if (get_eit_entry(ucbp, saved_vrs.core.r[R_PC], pid, map, &this_map) - != _URC_OK) { - /* Uncomment the code below to study why the unwinder failed */ -#if 0 - /* Shed more debugging info for stack unwinder improvement */ - if (this_map) { - _LOG(tfd, 1, - "Relative PC=%#x from %s not contained in EXIDX\n", - saved_vrs.core.r[R_PC] - this_map->start, this_map->name); - } - _LOG(tfd, 1, "PC=%#x SP=%#x\n", - saved_vrs.core.r[R_PC], saved_vrs.core.r[R_SP]); -#endif - code = _URC_FAILURE; - break; - } - - /* The dwarf unwinder assumes the context structure holds things - like the function and LSDA pointers. The ARM implementation - caches these in the exception header (UCB). To avoid - rewriting everything we make the virtual IP register point at - the UCB. */ - _Unwind_SetGR((_Unwind_Context *)&saved_vrs, 12, (_Unwind_Ptr) ucbp); - - /* Call log function. */ - if (log_function ((_Unwind_Context *) &saved_vrs, pid, tfd, stack_level, - map, sp_list, at_fault) != _URC_NO_REASON) { - code = _URC_FAILURE; - break; - } - stack_level++; - - /* Call the pr to decide what to do. */ - code = ((personality_routine_with_ptrace) UCB_PR_ADDR (ucbp))( - _US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, ucbp, - (void *) &saved_vrs, pid); - /* - * In theory the unwinding process will stop when the end of stack is - * reached or there is no unwinding information for the code address. - * To add another level of guarantee that the unwinding process - * will terminate we will stop it when the STACK_CONTENT_DEPTH is reached. - */ - } while (code != _URC_END_OF_STACK && code != _URC_FAILURE && - stack_level < STACK_CONTENT_DEPTH); - return stack_level; -} - - -/* Derived version to use ptrace */ -/* Common implementation for ARM ABI defined personality routines. - ID is the index of the personality routine, other arguments are as defined - by __aeabi_unwind_cpp_pr{0,1,2}. */ - -static _Unwind_Reason_Code -unwind_pr_common_with_ptrace (_Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context, - int id, - pid_t pid) -{ - __gnu_unwind_state uws; - _uw *data; - int phase2_call_unexpected_after_unwind = 0; - - state &= _US_ACTION_MASK; - - data = (_uw *) ucbp->pr_cache.ehtp; - uws.data = get_remote_word(pid, data); - data++; - uws.next = data; - if (id == 0) - { - uws.data <<= 8; - uws.words_left = 0; - uws.bytes_left = 3; - } - else - { - uws.words_left = (uws.data >> 16) & 0xff; - uws.data <<= 16; - uws.bytes_left = 2; - data += uws.words_left; - } - - /* Restore the saved pointer. */ - if (state == _US_UNWIND_FRAME_RESUME) - data = (_uw *) ucbp->cleanup_cache.bitpattern[0]; - - if ((ucbp->pr_cache.additional & 1) == 0) - { - /* Process descriptors. */ - while (get_remote_word(pid, data)) { - /********************************************************************** - * The original code here seems to deal with exceptions that are not - * applicable in our toolchain, thus there is no way to test it for now. - * Instead of leaving it here and causing potential instability in - * debuggerd, we'd better punt here and leave the stack unwound. - * In the future when we discover cases where the stack should be unwound - * further but is not, we can revisit the code here. - **********************************************************************/ - return _URC_FAILURE; - } - /* Finished processing this descriptor. */ - } - - if (unwind_execute_with_ptrace (context, &uws, pid) != _URC_OK) - return _URC_FAILURE; - - if (phase2_call_unexpected_after_unwind) - { - /* Enter __cxa_unexpected as if called from the call site. */ - _Unwind_SetGR (context, R_LR, _Unwind_GetGR (context, R_PC)); - _Unwind_SetGR (context, R_PC, (_uw) &__cxa_call_unexpected); - return _URC_INSTALL_CONTEXT; - } - - return _URC_CONTINUE_UNWIND; -} - - -/* ABI defined personality routine entry points. */ - -static _Unwind_Reason_Code -unwind_cpp_pr0_with_ptrace (_Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context, - pid_t pid) -{ - return unwind_pr_common_with_ptrace (state, ucbp, context, 0, pid); -} - -static _Unwind_Reason_Code -unwind_cpp_pr1_with_ptrace (_Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context, - pid_t pid) -{ - return unwind_pr_common_with_ptrace (state, ucbp, context, 1, pid); -} - -static _Unwind_Reason_Code -unwind_cpp_pr2_with_ptrace (_Unwind_State state, - _Unwind_Control_Block *ucbp, - _Unwind_Context *context, - pid_t pid) -{ - return unwind_pr_common_with_ptrace (state, ucbp, context, 2, pid); -} diff --git a/debuggerd/utility.c b/debuggerd/utility.c deleted file mode 100644 index 8f3931c..0000000 --- a/debuggerd/utility.c +++ /dev/null @@ -1,83 +0,0 @@ -/* system/debuggerd/utility.c -** -** 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. -*/ - -#include <sys/ptrace.h> -#include <sys/exec_elf.h> -#include <assert.h> -#include <string.h> -#include <errno.h> - -#include "utility.h" - -/* Get a word from pid using ptrace. The result is the return value. */ -int get_remote_word(int pid, void *src) -{ - return ptrace(PTRACE_PEEKTEXT, pid, src, NULL); -} - - -/* Handy routine to read aggregated data from pid using ptrace. The read - * values are written to the dest locations directly. - */ -void get_remote_struct(int pid, void *src, void *dst, size_t size) -{ - unsigned int i; - - for (i = 0; i+4 <= size; i+=4) { - *(int *)(dst+i) = ptrace(PTRACE_PEEKTEXT, pid, src+i, NULL); - } - - if (i < size) { - int val; - - assert((size - i) < 4); - val = ptrace(PTRACE_PEEKTEXT, pid, src+i, NULL); - while (i < size) { - ((unsigned char *)dst)[i] = val & 0xff; - i++; - val >>= 8; - } - } -} - -/* Map a pc address to the name of the containing ELF file */ -const char *map_to_name(mapinfo *mi, unsigned pc, const char* def) -{ - while(mi) { - if((pc >= mi->start) && (pc < mi->end)){ - return mi->name; - } - mi = mi->next; - } - return def; -} - -/* Find the containing map info for the pc */ -const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc) -{ - while(mi) { - if((pc >= mi->start) && (pc < mi->end)){ - // Only calculate the relative offset for shared libraries - if (strstr(mi->name, ".so")) { - *rel_pc = pc - mi->start; - } - return mi; - } - mi = mi->next; - } - return NULL; -} diff --git a/debuggerd/utility.h b/debuggerd/utility.h deleted file mode 100644 index 49f5951..0000000 --- a/debuggerd/utility.h +++ /dev/null @@ -1,56 +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 __utility_h -#define __utility_h - -#include <stddef.h> -#include <stdbool.h> - -#ifndef PT_ARM_EXIDX -#define PT_ARM_EXIDX 0x70000001 /* .ARM.exidx segment */ -#endif - -#define STACK_CONTENT_DEPTH 32 - -typedef struct mapinfo { - struct mapinfo *next; - unsigned start; - unsigned end; - unsigned exidx_start; - unsigned exidx_end; - char name[]; -} mapinfo; - -/* Get a word from pid using ptrace. The result is the return value. */ -extern int get_remote_word(int pid, void *src); - -/* Handy routine to read aggregated data from pid using ptrace. The read - * values are written to the dest locations directly. - */ -extern void get_remote_struct(int pid, void *src, void *dst, size_t size); - -/* Find the containing map for the pc */ -const mapinfo *pc_to_mapinfo (mapinfo *mi, unsigned pc, unsigned *rel_pc); - -/* Map a pc address to the name of the containing ELF file */ -const char *map_to_name(mapinfo *mi, unsigned pc, const char* def); - -/* Log information onto the tombstone */ -extern void _LOG(int tfd, bool in_tombstone_only, const char *fmt, ...); - -#endif |