From 768c2c02e72602df382ab4f92d7e99afcaa0c5c3 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 28 Aug 2014 11:43:46 -0700 Subject: [PATCH] - paranoia test; errlogFlush; fixed debug messages 1) Added a paranoia test to make sure an ill-formatted ELF string table is not overrun if there is no NULL char found. 2) Added errlogFlush() before and after stack dump (suggestion by Michael Davidsaver, thanks). 3) Fixed (out of sync) debug messages. --- src/libCom/osi/execinfoStackTrace.c | 40 ++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/src/libCom/osi/execinfoStackTrace.c b/src/libCom/osi/execinfoStackTrace.c index 3839815a9..7888196de 100644 --- a/src/libCom/osi/execinfoStackTrace.c +++ b/src/libCom/osi/execinfoStackTrace.c @@ -20,6 +20,8 @@ #define MAXDEPTH 100 +#define STACKTRACE_DEBUG 0 + /* Darwin and GNU have dladdr() but Darwin's backtrace_symbols() * already prints local symbols, too, whereas linux' does not. * Hence, on linux we want to use dladdr() and lookup static @@ -93,9 +95,10 @@ typedef union Sym_ { */ typedef struct MMap_ { void *addr; - off_t off; /* offset into the map where 'real' data start */ + off_t off; /* offset into the map where 'real' data start */ size_t len; - void (*freeMap)(struct MMap_*); /* 'method' to destroy the mapping */ + size_t max; /* max offset: legal data from addr+off .. addr+off+max-1 */ + void (*freeMap)(struct MMap_*); /* 'method' to destroy the mapping */ } *MMap; /* Structure describing symbol information @@ -196,6 +199,7 @@ size_t pgsz = sysconf(_SC_PAGESIZE); rval->off = FLD(c,(*shdr_p),sh_offset) & (pgsz-1); rval->len = (n + rval->off + (pgsz - 1)) & ~(pgsz - 1); + rval->max = rval->len - rval->off; if ( MAP_FAILED == (rval->addr = mmap(0, rval->len, PROT_READ, MAP_SHARED, fd, FLD(c,(*shdr_p),sh_offset) & ~(pgsz-1))) ) { errlogPrintf("elfRead - getscn() -- mapping section contents: %s\n", strerror(errno)); @@ -244,6 +248,7 @@ MMap rval = 0; rval->off = 0; rval->len = n; + rval->max = rval->len - rval->off; /* seek to symbol table contents */ if ( (off_t)-1 == lseek(fd, FLD(c,(*shdr_p),sh_offset), SEEK_SET) ) { @@ -290,6 +295,8 @@ Ehdr ehdr; Shdr shdr; uint8_t c; ESyms es; +ssize_t idx; +const char *cp; if ( !(es = malloc(sizeof(*es))) ) { /* no memory -- give up */ @@ -397,6 +404,14 @@ ESyms es; goto bail; } + /* Make sure there is a terminating NUL - unfortunately, memrchr is not portable */ + cp = es->strMap->addr + es->strMap->off; + for ( idx = es->strMap->max - 1; i >= 0; i-- ) { + if ( !cp[i] ) + break; + } + es->strMap->max = idx + 1; + switch ( FLD(c,ehdr,e_type) ) { case ET_EXEC: /* Symbols in an executable already has absolute addresses */ @@ -470,6 +485,7 @@ Sym sym; Sym nearest; const char *strtab; uint8_t c; +size_t idx; if ( ! dladdr(addr, &inf) || (!inf.dli_fname && !inf.dli_sname) ) { /* unable to lookup */ @@ -515,7 +531,9 @@ uint8_t c; * very often then it would be worthwhile constructing a sorted list of * symbol addresses but for the stack trace we don't care... */ - //printf("Looking for %p\n", addr); +#if (STACKTRACE_DEBUG & 1) + printf("Looking for %p\n", addr); +#endif if ( ELFCLASS32 == c ) { for ( i=0; insyms; i++ ) { @@ -524,7 +542,9 @@ uint8_t c; /* don't bother about undefined symbols */ if ( 0 == sym.e32[i].st_shndx ) continue; - //printf("Trying: %s (0x%x)\n", elf_strptr(es->elf, es->idx, es->syms[i].st_name), es->syms[i].st_value + es->addr); +#if (STACKTRACE_DEBUG & 1) + printf("Trying: %s (0x%lx)\n", strtab + sym.e32[i].st_name, (unsigned long)(sym.e32[i].st_value + es->addr)); +#endif if ( (uintptr_t)addr >= (uintptr_t)sym.e32[i].st_value + es->addr ) { off = (uintptr_t)addr - ((uintptr_t)sym.e32[i].st_value + es->addr); if ( off < minoff ) { @@ -540,7 +560,9 @@ uint8_t c; /* don't bother about undefined symbols */ if ( 0 == sym.e64[i].st_shndx ) continue; - //printf("Trying: %s (0x%x)\n", elf_strptr(es->elf, es->idx, es->syms[i].st_name), es->syms[i].st_value + es->addr); +#if (STACKTRACE_DEBUG & 1) + printf("Trying: %s (0x%llx)\n", strtab + sym.e64[i].st_name, (unsigned long long)(sym.e64[i].st_value + es->addr)); +#endif if ( (uintptr_t)addr >= (uintptr_t)sym.e64[i].st_value + es->addr ) { off = (uintptr_t)addr - ((uintptr_t)sym.e64[i].st_value + es->addr); if ( off < minoff ) { @@ -552,8 +574,8 @@ uint8_t c; } } - if ( nearest.raw ) { - errlogPrintf("%s(%s+0x%"PRIxPTR"): [%p]\n", es->fname, strtab + ARR(c,nearest,0,st_name), minoff, addr); + if ( nearest.raw && ( (idx = ARR(c,nearest,0,st_name)) < es->strMap->max ) ) { + errlogPrintf("%s(%s+0x%"PRIxPTR"): [%p]\n", es->fname, strtab + idx, minoff, addr); } else { errlogPrintf("%s[%p]\n", es->fname, addr); } @@ -568,6 +590,8 @@ char **bts; #endif int i,n; + errlogFlush(); + if ( ! (buf = malloc(sizeof(*buf) * MAXDEPTH)) ) { errlogPrintf("epicsStackTrace(): not enough memory for backtrace\n"); return; @@ -600,6 +624,8 @@ int i,n; } #endif + errlogFlush(); + free(buf); }