debuggerd: IA version
Change-Id: I0c0d9c2d7e476b8d117aaf505a9480a47c0b5c05 Signed-off-by: Lei Li <lei.l.li@intel.com> Signed-off-by: Bruce Beare <bruce.j.beare@intel.com>
This commit is contained in:
parent
849249064c
commit
6cc4923087
11 changed files with 285 additions and 24 deletions
|
@ -1,6 +1,6 @@
|
|||
# Copyright 2005 The Android Open Source Project
|
||||
|
||||
ifeq ($(TARGET_ARCH),arm)
|
||||
ifneq ($(filter arm x86,$(TARGET_ARCH)),)
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
@ -50,4 +50,4 @@ LOCAL_SHARED_LIBRARIES := libcutils libc
|
|||
include $(BUILD_EXECUTABLE)
|
||||
endif # ARCH_ARM_HAVE_VFP == true
|
||||
|
||||
endif # TARGET_ARCH == arm
|
||||
endif # arm or x86 in TARGET_ARCH
|
||||
|
|
|
@ -451,7 +451,6 @@ static _Unwind_Reason_Code log_function(_Unwind_Context *context, pid_t pid,
|
|||
* 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);
|
||||
|
||||
/* See if we can determine what symbol this stack frame resides in */
|
||||
|
|
|
@ -240,6 +240,13 @@ void dump_crash_report(int tfd, unsigned pid, unsigned tid, bool at_fault)
|
|||
}
|
||||
|
||||
dump_stack_and_code(tfd, tid, milist, stack_depth, sp_list, at_fault);
|
||||
#elif __i386__
|
||||
/* If stack unwinder fails, use the default solution to dump the stack
|
||||
* content.
|
||||
*/
|
||||
stack_depth = unwind_backtrace_with_ptrace_x86(tfd, tid, milist,at_fault);
|
||||
#else
|
||||
#error "Unsupported architecture"
|
||||
#endif
|
||||
|
||||
while(milist) {
|
||||
|
|
|
@ -37,4 +37,3 @@ void dump_pc_and_lr(int tfd, int pid, mapinfo *map, int unwound_level, bool at_f
|
|||
void dump_stack_and_code(int tfd, int pid, mapinfo *map,
|
||||
int unwind_depth, unsigned int sp_list[],
|
||||
bool at_fault);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <sys/mman.h>
|
||||
|
||||
#include "symbol_table.h"
|
||||
#include "utility.h"
|
||||
|
||||
#include <linux/elf.h>
|
||||
|
||||
|
@ -49,6 +50,7 @@ struct symbol_table *symbol_table_create(const char *filename)
|
|||
int length;
|
||||
char *base;
|
||||
|
||||
XLOG("Creating symbol table for %s\n", filename);
|
||||
int fd = open(filename, O_RDONLY);
|
||||
|
||||
if(fd < 0) {
|
||||
|
@ -69,40 +71,70 @@ struct symbol_table *symbol_table_create(const char *filename)
|
|||
Elf32_Shdr *shdr = (Elf32_Shdr*)(base + hdr->e_shoff);
|
||||
|
||||
// Search for the dynamic symbols section
|
||||
int sym_idx = -1;
|
||||
int dynsym_idx = -1;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < hdr->e_shnum; i++) {
|
||||
if(shdr[i].sh_type == SHT_SYMTAB ) {
|
||||
sym_idx = i;
|
||||
}
|
||||
if(shdr[i].sh_type == SHT_DYNSYM ) {
|
||||
dynsym_idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if(dynsym_idx == -1) {
|
||||
if ((dynsym_idx == -1) && (sym_idx == -1)) {
|
||||
goto out_unmap;
|
||||
}
|
||||
|
||||
Elf32_Sym *dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset);
|
||||
int numsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize;
|
||||
|
||||
table = malloc(sizeof(struct symbol_table));
|
||||
if(!table) {
|
||||
goto out_unmap;
|
||||
}
|
||||
table->name = strdup(filename);
|
||||
table->num_symbols = 0;
|
||||
|
||||
// Iterate through the dynamic symbol table, and count how many symbols
|
||||
// are actually defined
|
||||
for(i = 0; i < numsyms; i++) {
|
||||
if(dynsyms[i].st_shndx != SHN_UNDEF) {
|
||||
table->num_symbols++;
|
||||
}
|
||||
}
|
||||
Elf32_Sym *dynsyms = (Elf32_Sym*)(base + shdr[dynsym_idx].sh_offset);
|
||||
Elf32_Sym *syms = (Elf32_Sym*)(base + shdr[sym_idx].sh_offset);
|
||||
|
||||
int dynnumsyms = shdr[dynsym_idx].sh_size / shdr[dynsym_idx].sh_entsize;
|
||||
int numsyms = shdr[sym_idx].sh_size / shdr[sym_idx].sh_entsize;
|
||||
|
||||
int dynstr_idx = shdr[dynsym_idx].sh_link;
|
||||
int str_idx = shdr[sym_idx].sh_link;
|
||||
|
||||
char *dynstr = base + shdr[dynstr_idx].sh_offset;
|
||||
char *str = base + shdr[str_idx].sh_offset;
|
||||
|
||||
int symbol_count = 0;
|
||||
int dynsymbol_count = 0;
|
||||
|
||||
if (dynsym_idx != -1) {
|
||||
// Iterate through the dynamic symbol table, and count how many symbols
|
||||
// are actually defined
|
||||
for(i = 0; i < dynnumsyms; i++) {
|
||||
if(dynsyms[i].st_shndx != SHN_UNDEF) {
|
||||
dynsymbol_count++;
|
||||
}
|
||||
}
|
||||
XLOG("Dynamic Symbol count: %d\n", dynsymbol_count);
|
||||
}
|
||||
|
||||
if (sym_idx != -1) {
|
||||
// Iterate through the symbol table, and count how many symbols
|
||||
// are actually defined
|
||||
for(i = 0; i < numsyms; i++) {
|
||||
if((syms[i].st_shndx != SHN_UNDEF) &&
|
||||
(strlen(str+syms[i].st_name)) &&
|
||||
(syms[i].st_value != 0) && (syms[i].st_size != 0)) {
|
||||
symbol_count++;
|
||||
}
|
||||
}
|
||||
XLOG("Symbol count: %d\n", symbol_count);
|
||||
}
|
||||
|
||||
// Now, create an entry in our symbol table structure for each symbol...
|
||||
table->num_symbols += symbol_count + dynsymbol_count;;
|
||||
table->symbols = malloc(table->num_symbols * sizeof(struct symbol));
|
||||
if(!table->symbols) {
|
||||
free(table);
|
||||
|
@ -110,14 +142,35 @@ struct symbol_table *symbol_table_create(const char *filename)
|
|||
goto out_unmap;
|
||||
}
|
||||
|
||||
// ...and populate them
|
||||
|
||||
int j = 0;
|
||||
for(i = 0; i < numsyms; i++) {
|
||||
if(dynsyms[i].st_shndx != SHN_UNDEF) {
|
||||
table->symbols[j].name = strdup(dynstr + dynsyms[i].st_name);
|
||||
table->symbols[j].addr = dynsyms[i].st_value;
|
||||
table->symbols[j].size = dynsyms[i].st_size;
|
||||
j++;
|
||||
if (dynsym_idx != -1) {
|
||||
// ...and populate them
|
||||
for(i = 0; i < dynnumsyms; i++) {
|
||||
if(dynsyms[i].st_shndx != SHN_UNDEF) {
|
||||
table->symbols[j].name = strdup(dynstr + dynsyms[i].st_name);
|
||||
table->symbols[j].addr = dynsyms[i].st_value;
|
||||
table->symbols[j].size = dynsyms[i].st_size;
|
||||
XLOG("name: %s, addr: %x, size: %x\n",
|
||||
table->symbols[j].name, table->symbols[j].addr, table->symbols[j].size);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (sym_idx != -1) {
|
||||
// ...and populate them
|
||||
for(i = 0; i < numsyms; i++) {
|
||||
if((syms[i].st_shndx != SHN_UNDEF) &&
|
||||
(strlen(str+syms[i].st_name)) &&
|
||||
(syms[i].st_value != 0) && (syms[i].st_size != 0)) {
|
||||
table->symbols[j].name = strdup(str + syms[i].st_name);
|
||||
table->symbols[j].addr = syms[i].st_value;
|
||||
table->symbols[j].size = syms[i].st_size;
|
||||
XLOG("name: %s, addr: %x, size: %x\n",
|
||||
table->symbols[j].name, table->symbols[j].addr, table->symbols[j].size);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ struct symbol {
|
|||
struct symbol_table {
|
||||
struct symbol *symbols;
|
||||
int num_symbols;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct symbol_table *symbol_table_create(const char *filename);
|
||||
|
|
|
@ -69,11 +69,12 @@ const char *map_to_name(mapinfo *mi, unsigned pc, const char* def)
|
|||
/* Find the containing map info for the pc */
|
||||
const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc)
|
||||
{
|
||||
*rel_pc = 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;
|
||||
*rel_pc -= mi->start;
|
||||
}
|
||||
return mi;
|
||||
}
|
||||
|
|
15
debuggerd/x86/crashglue.S
Normal file
15
debuggerd/x86/crashglue.S
Normal file
|
@ -0,0 +1,15 @@
|
|||
.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
|
61
debuggerd/x86/machine.c
Normal file
61
debuggerd/x86/machine.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/* 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 <errno.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.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/properties.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "../utility.h"
|
||||
#include "x86_utility.h"
|
||||
|
||||
void dump_registers(int tfd, int pid, bool at_fault)
|
||||
{
|
||||
struct pt_regs_x86 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;
|
||||
}
|
||||
//if there is no stack, no print just like arm
|
||||
if(!r.ebp)
|
||||
return;
|
||||
_LOG(tfd, only_in_tombstone, " eax %08x ebx %08x ecx %08x edx %08x\n",
|
||||
r.eax, r.ebx, r.ecx, r.edx);
|
||||
_LOG(tfd, only_in_tombstone, " esi %08x edi %08x\n",
|
||||
r.esi, r.edi);
|
||||
_LOG(tfd, only_in_tombstone, " xcs %08x xds %08x xes %08x xfs %08x xss %08x\n",
|
||||
r.xcs, r.xds, r.xes, r.xfs, r.xss);
|
||||
_LOG(tfd, only_in_tombstone,
|
||||
" eip %08x ebp %08x esp %08x flags %08x\n",
|
||||
r.eip, r.ebp, r.esp, r.eflags);
|
||||
}
|
85
debuggerd/x86/unwind.c
Normal file
85
debuggerd/x86/unwind.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
#include <cutils/logd.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include "../utility.h"
|
||||
#include "x86_utility.h"
|
||||
|
||||
|
||||
int unwind_backtrace_with_ptrace_x86(int tfd, pid_t pid, mapinfo *map,
|
||||
bool at_fault)
|
||||
{
|
||||
struct pt_regs_x86 r;
|
||||
unsigned int stack_level = 0;
|
||||
unsigned int stack_depth = 0;
|
||||
unsigned int rel_pc;
|
||||
unsigned int stack_ptr;
|
||||
unsigned int stack_content;
|
||||
|
||||
if(ptrace(PTRACE_GETREGS, pid, 0, &r)) return 0;
|
||||
unsigned int eip = (unsigned int)r.eip;
|
||||
unsigned int ebp = (unsigned int)r.ebp;
|
||||
unsigned int cur_sp = (unsigned int)r.esp;
|
||||
const mapinfo *mi;
|
||||
const struct symbol* sym = 0;
|
||||
|
||||
|
||||
//ebp==0, it indicates that the stack is poped to the bottom or there is no stack at all.
|
||||
while (ebp) {
|
||||
_LOG(tfd, !at_fault, "#0%d ",stack_level);
|
||||
mi = pc_to_mapinfo(map, eip, &rel_pc);
|
||||
|
||||
/* See if we can determine what symbol this stack frame resides in */
|
||||
if (mi != 0 && mi->symbols != 0) {
|
||||
sym = symbol_table_lookup(mi->symbols, rel_pc);
|
||||
}
|
||||
if (sym) {
|
||||
_LOG(tfd, !at_fault, " eip: %08x %s (%s)\n", eip, mi ? mi->name : "", sym->name);
|
||||
} else {
|
||||
_LOG(tfd, !at_fault, " eip: %08x %s\n", eip, mi ? mi->name : "");
|
||||
}
|
||||
|
||||
stack_level++;
|
||||
if (stack_level >= STACK_DEPTH || eip == 0)
|
||||
break;
|
||||
eip = ptrace(PTRACE_PEEKTEXT, pid, (void*)(ebp + 4), NULL);
|
||||
ebp = ptrace(PTRACE_PEEKTEXT, pid, (void*)ebp, NULL);
|
||||
}
|
||||
ebp = (unsigned int)r.ebp;
|
||||
stack_depth = stack_level;
|
||||
stack_level = 0;
|
||||
if (ebp)
|
||||
_LOG(tfd, !at_fault, "stack: \n");
|
||||
while (ebp) {
|
||||
_LOG(tfd, !at_fault, "#0%d \n",stack_level);
|
||||
stack_ptr = cur_sp;
|
||||
while((int)(ebp - stack_ptr) >= 0) {
|
||||
stack_content = ptrace(PTRACE_PEEKTEXT, pid, (void*)stack_ptr, NULL);
|
||||
mi = pc_to_mapinfo(map, stack_content, &rel_pc);
|
||||
|
||||
/* See if we can determine what symbol this stack frame resides in */
|
||||
if (mi != 0 && mi->symbols != 0) {
|
||||
sym = symbol_table_lookup(mi->symbols, rel_pc);
|
||||
}
|
||||
if (sym) {
|
||||
_LOG(tfd, !at_fault, " %08x %08x %s (%s)\n",
|
||||
stack_ptr, stack_content, mi ? mi->name : "", sym->name);
|
||||
} else {
|
||||
_LOG(tfd, !at_fault, " %08x %08x %s\n", stack_ptr, stack_content, mi ? mi->name : "");
|
||||
}
|
||||
|
||||
stack_ptr = stack_ptr + 4;
|
||||
//the stack frame may be very deep.
|
||||
if((int)(stack_ptr - cur_sp) >= STACK_FRAME_DEPTH) {
|
||||
_LOG(tfd, !at_fault, " ...... ...... \n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
cur_sp = ebp + 4;
|
||||
stack_level++;
|
||||
if (stack_level >= STACK_DEPTH || stack_level >= stack_depth)
|
||||
break;
|
||||
ebp = ptrace(PTRACE_PEEKTEXT, pid, (void*)ebp, NULL);
|
||||
}
|
||||
|
||||
return stack_depth;
|
||||
}
|
||||
|
40
debuggerd/x86/x86_utility.h
Normal file
40
debuggerd/x86/x86_utility.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
**
|
||||
** 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 STACK_DEPTH 8
|
||||
#define STACK_FRAME_DEPTH 64
|
||||
|
||||
typedef struct pt_regs_x86 {
|
||||
long ebx;
|
||||
long ecx;
|
||||
long edx;
|
||||
long esi;
|
||||
long edi;
|
||||
long ebp;
|
||||
long eax;
|
||||
int xds;
|
||||
int xes;
|
||||
int xfs;
|
||||
int xgs;
|
||||
long orig_eax;
|
||||
long eip;
|
||||
int xcs;
|
||||
long eflags;
|
||||
long esp;
|
||||
int xss;
|
||||
}pt_regs_x86;
|
||||
|
Loading…
Reference in a new issue