Merge "Show maps near native fault address"
This commit is contained in:
commit
90e6f931f2
|
@ -50,6 +50,74 @@ extern int unwind_backtrace_with_ptrace(int tfd, pid_t pid, mapinfo *map,
|
|||
int *frame0_pc_sane,
|
||||
bool at_fault);
|
||||
|
||||
/*
|
||||
* If this isn't clearly a null pointer dereference, dump the
|
||||
* /proc/maps entries near the fault address.
|
||||
*/
|
||||
static void show_nearby_maps(int tfd, int pid, mapinfo *map)
|
||||
{
|
||||
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));
|
||||
return;
|
||||
}
|
||||
if (!signal_has_address(si.si_signo))
|
||||
return;
|
||||
|
||||
uintptr_t addr = (uintptr_t) si.si_addr;
|
||||
addr &= ~0xfff; /* round to 4K page boundary */
|
||||
if (addr == 0) /* null-pointer deref */
|
||||
return;
|
||||
|
||||
_LOG(tfd, false, "\nmemory map around addr %08x:\n", si.si_addr);
|
||||
|
||||
/*
|
||||
* Search for a match, or for a hole where the match would be. The list
|
||||
* is backward from the file content, so it starts at high addresses.
|
||||
*/
|
||||
bool found = false;
|
||||
mapinfo *next = NULL;
|
||||
mapinfo *prev = NULL;
|
||||
while (map != NULL) {
|
||||
if (addr >= map->start && addr < map->end) {
|
||||
found = true;
|
||||
next = map->next;
|
||||
break;
|
||||
} else if (addr >= map->end) {
|
||||
/* map would be between "prev" and this entry */
|
||||
next = map;
|
||||
map = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
prev = map;
|
||||
map = map->next;
|
||||
}
|
||||
|
||||
/*
|
||||
* Show "next" then "match" then "prev" so that the addresses appear in
|
||||
* ascending order (like /proc/pid/maps).
|
||||
*/
|
||||
if (next != NULL) {
|
||||
_LOG(tfd, false, "%08x-%08x %s\n", next->start, next->end, next->name);
|
||||
} else {
|
||||
_LOG(tfd, false, "(no map below)\n");
|
||||
}
|
||||
if (map != NULL) {
|
||||
_LOG(tfd, false, "%08x-%08x %s\n", map->start, map->end, map->name);
|
||||
} else {
|
||||
_LOG(tfd, false, "(no map for address)\n");
|
||||
}
|
||||
if (prev != NULL) {
|
||||
_LOG(tfd, false, "%08x-%08x %s\n", prev->start, prev->end, prev->name);
|
||||
} else {
|
||||
_LOG(tfd, false, "(no map above)\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dump_stack_and_code(int tfd, int pid, mapinfo *map,
|
||||
int unwind_depth, unsigned int sp_list[],
|
||||
bool at_fault)
|
||||
|
@ -123,6 +191,8 @@ void dump_stack_and_code(int tfd, int pid, mapinfo *map,
|
|||
}
|
||||
}
|
||||
|
||||
show_nearby_maps(tfd, pid, map);
|
||||
|
||||
p = sp - 64;
|
||||
if (p > sp)
|
||||
p = 0;
|
||||
|
|
|
@ -70,14 +70,17 @@ mapinfo *parse_maps_line(char *line)
|
|||
mapinfo *mi;
|
||||
int len = strlen(line);
|
||||
|
||||
if(len < 1) return 0;
|
||||
if (len < 1) return 0; /* not expected */
|
||||
line[--len] = 0;
|
||||
|
||||
if(len < 50) return 0;
|
||||
if(line[20] != 'x') return 0;
|
||||
if (len < 50) {
|
||||
mi = malloc(sizeof(mapinfo) + 1);
|
||||
} else {
|
||||
mi = malloc(sizeof(mapinfo) + (len - 47));
|
||||
}
|
||||
if (mi == 0) return 0;
|
||||
|
||||
mi = malloc(sizeof(mapinfo) + (len - 47));
|
||||
if(mi == 0) return 0;
|
||||
mi->isExecutable = (line[20] == 'x');
|
||||
|
||||
mi->start = strtoul(line, 0, 16);
|
||||
mi->end = strtoul(line + 9, 0, 16);
|
||||
|
@ -87,7 +90,11 @@ mapinfo *parse_maps_line(char *line)
|
|||
mi->exidx_start = mi->exidx_end = 0;
|
||||
mi->symbols = 0;
|
||||
mi->next = 0;
|
||||
strcpy(mi->name, line + 49);
|
||||
if (len < 50) {
|
||||
mi->name[0] = '\0';
|
||||
} else {
|
||||
strcpy(mi->name, line + 49);
|
||||
}
|
||||
|
||||
return mi;
|
||||
}
|
||||
|
@ -165,11 +172,14 @@ void dump_fault_addr(int tfd, int pid, int sig)
|
|||
memset(&si, 0, sizeof(si));
|
||||
if(ptrace(PTRACE_GETSIGINFO, pid, 0, &si)){
|
||||
_LOG(tfd, false, "cannot get siginfo: %s\n", strerror(errno));
|
||||
} else {
|
||||
} else if (signal_has_address(sig)) {
|
||||
_LOG(tfd, false, "signal %d (%s), code %d (%s), fault addr %08x\n",
|
||||
sig, get_signame(sig),
|
||||
si.si_code, get_sigcode(sig, si.si_code),
|
||||
si.si_addr);
|
||||
} else {
|
||||
_LOG(tfd, false, "signal %d (%s), code %d (%s), fault addr --------\n",
|
||||
sig, get_signame(sig), si.si_code, get_sigcode(sig, si.si_code));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,6 +209,9 @@ static void parse_elf_info(mapinfo *milist, pid_t pid)
|
|||
{
|
||||
mapinfo *mi;
|
||||
for (mi = milist; mi != NULL; mi = mi->next) {
|
||||
if (!mi->isExecutable)
|
||||
continue;
|
||||
|
||||
Elf32_Ehdr ehdr;
|
||||
|
||||
memset(&ehdr, 0, sizeof(Elf32_Ehdr));
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/exec_elf.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
@ -82,3 +83,20 @@ const mapinfo *pc_to_mapinfo(mapinfo *mi, unsigned pc, unsigned *rel_pc)
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the specified signal has an associated address (i.e. it
|
||||
* sets siginfo_t.si_addr).
|
||||
*/
|
||||
bool signal_has_address(int sig)
|
||||
{
|
||||
switch (sig) {
|
||||
case SIGILL:
|
||||
case SIGFPE:
|
||||
case SIGSEGV:
|
||||
case SIGBUS:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ typedef struct mapinfo {
|
|||
unsigned exidx_start;
|
||||
unsigned exidx_end;
|
||||
struct symbol_table *symbols;
|
||||
bool isExecutable;
|
||||
char name[];
|
||||
} mapinfo;
|
||||
|
||||
|
@ -56,6 +57,9 @@ 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, ...);
|
||||
|
||||
/* Determine whether si_addr is valid for this signal */
|
||||
bool signal_has_address(int sig);
|
||||
|
||||
#define LOG(fmt...) _LOG(-1, 0, fmt)
|
||||
|
||||
/* Set to 1 for normal debug traces */
|
||||
|
|
Loading…
Reference in New Issue