From b71aa81a474ed87c4b7e03efc65d7ab9850c6458 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Fri, 26 Aug 2011 14:40:15 -0700 Subject: [PATCH 01/41] - compute and print stack trace (on select architectures) from cantProceed and epicsAssert --- configure/os/CONFIG.Common.linuxCommon | 4 +- src/libCom/misc/cantProceed.c | 6 + src/libCom/osi/Makefile | 9 + src/libCom/osi/RULES | 4 + src/libCom/osi/epicsStacktrace.h | 17 + src/libCom/osi/execinfoStacktrace.c | 595 ++++++++++++++++++++++ src/libCom/osi/os/Darwin/osdStacktrace.c | 11 + src/libCom/osi/os/Linux/osdStacktrace.c | 11 + src/libCom/osi/os/default/osdAssert.c | 7 + src/libCom/osi/os/default/osdStacktrace.c | 5 + 10 files changed, 668 insertions(+), 1 deletion(-) create mode 100644 src/libCom/osi/epicsStacktrace.h create mode 100644 src/libCom/osi/execinfoStacktrace.c create mode 100644 src/libCom/osi/os/Darwin/osdStacktrace.c create mode 100644 src/libCom/osi/os/Linux/osdStacktrace.c create mode 100644 src/libCom/osi/os/default/osdStacktrace.c diff --git a/configure/os/CONFIG.Common.linuxCommon b/configure/os/CONFIG.Common.linuxCommon index a230d1734..d3c5c2dc8 100644 --- a/configure/os/CONFIG.Common.linuxCommon +++ b/configure/os/CONFIG.Common.linuxCommon @@ -20,7 +20,9 @@ POSIX_LDLIBS = -lpthread # -D_BSD_SOURCE for gethostname() in unistd.h as needed by cacChannelIO.cpp. OP_SYS_CPPFLAGS += -D_BSD_SOURCE OP_SYS_CPPFLAGS += -Dlinux -OP_SYS_LDLIBS += -lrt -ldl +# add -rdynamic so that more symbols (all globals, not only +# cross-referenced ones) are available to 'backtrace'. +OP_SYS_LDLIBS += -lrt -ldl -rdynamic # Added here for cross-target builds which include this file STATIC_LDFLAGS_YES= -Wl,-Bstatic diff --git a/src/libCom/misc/cantProceed.c b/src/libCom/misc/cantProceed.c index 832622ad0..3a6db7742 100644 --- a/src/libCom/misc/cantProceed.c +++ b/src/libCom/misc/cantProceed.c @@ -19,6 +19,7 @@ #include "errlog.h" #include "cantProceed.h" #include "epicsThread.h" +#include "epicsStacktrace.h" epicsShareFunc void * callocMustSucceed(size_t count, size_t size, const char *msg) { @@ -62,6 +63,11 @@ epicsShareFunc void cantProceed(const char *msg, ...) errlogPrintf("Thread %s (%p) can't proceed, suspending.\n", epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf()); + + errlogPrintf("Dumping a stack trace:\n"); + epicsStacktrace(); + errlogPrintf("\n"); + errlogFlush(); epicsThreadSleep(1.0); diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index 96d4540f2..86cd3fc35 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -56,6 +56,7 @@ INC += epicsStdio.h INC += epicsStdioRedirect.h INC += epicsTempFile.h INC += epicsGetopt.h +INC += epicsStacktrace.h INC += devLib.h INC += devLibVME.h @@ -140,3 +141,11 @@ Com_SRCS_WIN32 += epicsGetopt.c Com_SRCS_WIN32 += setThreadName.cpp #Com_SRCS_WIN32 += dllmain.cpp Com_SRCS_WIN32 += forceBadAllocException.cpp + +#Stacktrace support +Com_SRCS += osdStacktrace.c +Com_SRCS_Linux += execinfoStacktrace.c +Com_SRCS_Darwin += execinfoStacktrace.c +#we could use execinfoStacktrace.c on freebsd, too, but AFAIK +#you need libexecinfo.a and execinfo.h. I don't know if that +#is routinely available so we don't use it for now. diff --git a/src/libCom/osi/RULES b/src/libCom/osi/RULES index 71776c4a4..642a5f506 100644 --- a/src/libCom/osi/RULES +++ b/src/libCom/osi/RULES @@ -13,3 +13,7 @@ epicsTime$(DEP): $(COMMON_DIR)/epicsVersion.h osdNetIntf$(DEP): $(COMMON_DIR)/epicsVersion.h osdSock$(DEP): $(COMMON_DIR)/epicsVersion.h +execinfoConfig.h: + touch $@ + +execinfoStacktrace$(OBJ): execinfoConfig.h diff --git a/src/libCom/osi/epicsStacktrace.h b/src/libCom/osi/epicsStacktrace.h new file mode 100644 index 000000000..e98d2a1b2 --- /dev/null +++ b/src/libCom/osi/epicsStacktrace.h @@ -0,0 +1,17 @@ +#ifndef INC_epicsStacktrace_H +#define INC_epicsStacktrace_H + +#include "shareLib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dump a stacktrace to the errlog */ +epicsShareFunc void epicsStackTrace(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libCom/osi/execinfoStacktrace.c b/src/libCom/osi/execinfoStacktrace.c new file mode 100644 index 000000000..f4693d10b --- /dev/null +++ b/src/libCom/osi/execinfoStacktrace.c @@ -0,0 +1,595 @@ +#include "epicsStacktrace.h" +#include "epicsThread.h" +#include "epicsMutex.h" +#include +#include +#include +#include +#include +#include +#include + +#define MAXDEPTH 100 + +/* 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 + * symbols in the ELF symbol table. + */ +#define __USE_GNU + +#ifdef freebsd +/* Some freebsd versions seem to export dladdr() only if __BSD_VISIBLE */ +#define __BSD_VISIBLE 1 +#endif + +#include + +/* Check if we actually have the gnu/darwin extensions */ +#ifdef RTLD_DEFAULT + +#if defined(__linux__) || defined(linux) +#define USE_ELF +#define USE_MMAP +#elif defined(freebsd) +#define USE_ELF +#define USE_MMAP +#endif + +#ifdef USE_ELF +#include +#include +#include + +#ifdef USE_MMAP +#include +#endif /* USE_MMAP */ + +#endif /* USE_ELF */ + +#else /* RTLD_DEFAULT */ +#undef USE_ELF +#endif /* RTLD_DEFAULT */ + +#ifdef USE_ELF + +/* Macros to handle elf32 vs. elf64 access to unions etc. */ + +#define FLD(c,s,f) (ELFCLASS32==c ? s.e32.f : s.e64.f ) +#define ARR(c,s,i,f) (ELFCLASS32==c ? s.e32[i].f : s.e64[i].f) + +/* Elf header */ +typedef union Ehdr_ { + Elf32_Ehdr e32; + Elf64_Ehdr e64; +} Ehdr; + +/* Section header */ +typedef union Shdr_ { + Elf32_Shdr e32; + Elf64_Shdr e64; +} Shdr; + +/* Elf symbol */ +typedef union Sym_ { + void *raw; + Elf32_Sym *e32; + Elf64_Sym *e64; +} Sym; + +/* Memory mapped portion of a file; we must + * keep additional information because the + * map's starting address + length must be + * page-aligned (man mmap). + */ +typedef struct MMap_ { + void *addr; + off_t off; /* offset into the map where 'real' data start */ + size_t len; + void (*freeMap)(struct MMap_*); /* 'method' to destroy the mapping */ +} *MMap; + +/* Structure describing symbol information + * contained in a file. + * We keep these around (so that the file + * doesn't have to be opened + parsed every + * time we do a lookup). + */ +typedef struct ESyms_ { + struct ESyms_ *next; /* linked list; one struct per executable */ + const char *fname; /* file name */ + int fd; /* file descriptor */ + uintptr_t addr; /* address where file is loaded */ + MMap symMap; + MMap strMap; + size_t nsyms; + uint8_t class; +} *ESyms; + +/* Linked list where we keep all our ESyms */ +static ESyms elfs = 0; +static epicsThreadOnceId elfsInitId = EPICS_THREAD_ONCE_INIT; +static epicsMutexId elfsMtx; + +static void elfsInit(void *unused) +{ + elfsMtx = epicsMutexMustCreate(); +} + +static void elfsLock(void) +{ + epicsThreadOnce( &elfsInitId, elfsInit, 0 ); + epicsMutexLock( elfsMtx ); +} + +static void elfsUnlock(void) +{ + epicsMutexUnlock( elfsMtx ); +} + + +static void +freeMap(MMap m) +{ + if ( m ) { + m->freeMap(m); + free(m); + } +} + +/* Helper to read exactly 'sz' bytes into 'buf' + * RETURNS: # chars read or negative value on error. + */ +static size_t +do_read(int fd, void *buf, size_t sz) +{ +size_t got; +void *ptr=buf; + while ( sz > 0 ) { + if ( (got=read(fd,ptr,sz)) < 0 ) { + return got; + } + ptr+=got; + sz -=got; + } + return ptr-buf; +} + +#ifdef USE_MMAP + +/* Destructor for data that is mmap()ed */ +static void +freeMapMmap(MMap m) +{ + if ( MAP_FAILED != m->addr ) + munmap( m->addr, m->len ); +} + +/* Obtain section data with mmap() */ +static MMap +getscn(int fd, uint8_t c, Shdr *shdr_p) +{ +size_t n; +MMap rval = 0; +size_t pgsz = sysconf(_SC_PAGESIZE); + + if ( 0 == (n=FLD(c,(*shdr_p),sh_size)) ) { + errlogPrintf("elfRead - getscn() -- no section data\n"); + goto bail; + } + + if ( ! (rval = malloc(sizeof(*rval))) ) { + errlogPrintf("elfRead - getscn() -- no memory for section map\n"); + goto bail; + } + + rval->freeMap = freeMapMmap; + + rval->off = FLD(c,(*shdr_p),sh_offset) & (pgsz-1); + rval->len = (n + rval->off + (pgsz - 1)) & ~(pgsz - 1); + + 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)); + goto bail; + } + + return rval; + +bail: + freeMap(rval); + return 0; +} + +#else /* USE_MMAP */ + +/* Destructor for data that is read into a malloc()ed buffer */ +static void +freeMapMalloc(MMap m) +{ + free(m->addr); +} + +/* Read section data into a malloc()ed buffer */ +static MMap +getscn(int fd, uint8_t c, Shdr *shdr_p) +{ +size_t n; +MMap rval = 0; + + if ( 0 == (n=FLD(c,(*shdr_p),sh_size)) ) { + errlogPrintf("elfRead - getscn() -- no section data\n"); + goto bail; + } + + if ( ! (rval = malloc(sizeof(*rval))) ) { + errlogPrintf("elfRead - getscn() -- no memory for section map\n"); + goto bail; + } + + rval->freeMap = freeMapMalloc; + + if ( ! (rval->addr = malloc(n)) ) { + errlogPrintf("elfRead - getscn() -- no memory for section data\n"); + goto bail; + } + + rval->off = 0; + rval->len = n; + + /* seek to symbol table contents */ + if ( (off_t)-1 == lseek(fd, FLD(c,(*shdr_p),sh_offset), SEEK_SET) ) { + errlogPrintf("elfRead - getscn() -- seeking to sh_offset: %s\n", strerror(errno)); + goto bail; + } + + if ( n != do_read(fd, rval->addr, n) ) { + errlogPrintf("elfRead - getscn() -- reading section contents: %s\n", strerror(errno)); + goto bail; + } + + return rval; + +bail: + freeMap(rval); + return 0; +} +#endif /* USE_MMAP */ + +/* Release resources but keep filename so that + * a file w/o symbol table is not read over and over again. + */ +static void +elfSymsRelease(ESyms es) +{ + if ( es ) { + freeMap(es->symMap); + es->symMap = 0; + freeMap(es->strMap); + es->strMap = 0; + if ( es->fd >= 0 ) + close(es->fd); + es->fd = -1; + es->nsyms = 0; + } +} + +static ESyms +elfRead(const char *fname, uintptr_t fbase) +{ +int i,n; +Ehdr ehdr; +Shdr shdr; +uint8_t c; +ESyms es; + + if ( !(es = malloc(sizeof(*es))) ) { + /* no memory -- give up */ + return 0; + } + + memset(es, 0, sizeof(*es)); + es->fd = -1; + es->fname = fname; + + if ( (es->fd = open(fname, O_RDONLY)) < 0 ) { + errlogPrintf("elfRead() -- unable to open file: %s\n", strerror(errno)); + goto bail; + } + + if ( EI_NIDENT != do_read(es->fd, &ehdr, EI_NIDENT) ) { + errlogPrintf("elfRead() -- unable to read ELF e_ident: %s\n", strerror(errno)); + goto bail; + } + + if ( ELFMAG0 != ehdr.e32.e_ident[EI_MAG0] + || ELFMAG1 != ehdr.e32.e_ident[EI_MAG1] + || ELFMAG2 != ehdr.e32.e_ident[EI_MAG2] + || ELFMAG3 != ehdr.e32.e_ident[EI_MAG3] ) { + errlogPrintf("bad ELF magic number\n"); + goto bail; + } + + if ( EV_CURRENT != ehdr.e32.e_ident[EI_VERSION] ) { + errlogPrintf("bad ELF version\n"); + goto bail; + } + + switch ( (es->class = c = ehdr.e32.e_ident[EI_CLASS]) ) { + default: + errlogPrintf("bad ELF class\n"); + goto bail; + + case ELFCLASS32: + n = sizeof(Elf32_Ehdr); + break; + case ELFCLASS64: + n = sizeof(Elf64_Ehdr); + break; + } + n -= EI_NIDENT; + + /* read rest */ + if ( n != do_read(es->fd, ehdr.e32.e_ident + EI_NIDENT, n) ) { + errlogPrintf("elfRead() -- unable to read ELF ehdr: %s\n", strerror(errno)); + goto bail; + } + + /* seek to section header table */ + if ( (off_t)-1 == lseek(es->fd, FLD(c,ehdr,e_shoff), SEEK_SET) ) { + errlogPrintf("elfRead() -- unable to seek to shoff: %s\n", strerror(errno)); + goto bail; + } + + n = ELFCLASS32 == c ? sizeof(shdr.e32) : sizeof(shdr.e64); + + for ( i = 0; ifd, &shdr, n) ) { + errlogPrintf("elfRead() -- unable to read section header: %s\n", strerror(errno)); + goto bail; + } + if ( SHT_SYMTAB == FLD(c,shdr,sh_type) ) + break; + } + + if ( i>=FLD(c,ehdr,e_shnum) ) { + errlogPrintf("elfRead() -- no symbol table found\n"); + goto bail; + } + + if ( 0 == (n=FLD(c,shdr,sh_size)) ) { + errlogPrintf("elfRead() -- no symbol table data\n"); + goto bail; + } + + if ( !(es->symMap = getscn(es->fd, c, &shdr)) ) { + errlogPrintf("elfRead() -- unable to read ELF symtab\n"); + goto bail; + } + + es->nsyms = n / (ELFCLASS32==c ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym)); + + /* find and read string table */ + + n = ELFCLASS32 == c ? sizeof(shdr.e32) : sizeof(shdr.e64); + + /* seek to section header table */ + if ( (off_t)-1 == lseek(es->fd, FLD(c,ehdr,e_shoff) + n * FLD(c,shdr,sh_link), SEEK_SET) ) { + errlogPrintf("elfRead() -- unable to lseek to ELF e_shoff: %s\n", strerror(errno)); + goto bail; + } + + if ( n != do_read(es->fd, &shdr, n) ) { + errlogPrintf("elfRead() -- unable to read ELF strtab section header: %s\n", strerror(errno)); + goto bail; + } + + if ( !(es->strMap = getscn(es->fd,c,&shdr)) ) { + errlogPrintf("elfRead() -- unable to read ELF strtab\n"); + goto bail; + } + + switch ( FLD(c,ehdr,e_type) ) { + case ET_EXEC: + /* Symbols in an executable already has absolute addresses */ + es->addr = 0; + break; + case ET_DYN: + /* Symbols in an shared library are relative to base address */ + es->addr = fbase; + break; + default: + errlogPrintf("elfLookupAddr(): Unexpected ELF object file type %u\n", FLD(c,ehdr,e_type)); + goto bail; + } + + return es; + +bail: + elfSymsRelease(es); + return es; +} + +#if 0 +/* IMPLEMENTATION IS INCORRECT: + * with only a single lock 'elfLookupAddr()' would + * have to hold that the entire time while accessing + * a symbol table. This is inefficient if there are + * multiple readers. A better implementation would + * use a 'multiple-readers/single-writer' type of lock + * to protect the symbol tables. + * + * ATM we simply don't support destroying the + * tables (after dumping a stack trace the process is + * likely to be terminated anyways). + */ + +/* Destroy a cached ELF symbol table */ +static void +elfSymsDestroy(ESyms es) +{ + if ( es ) { + elfSymsRelease(es); + free(es); + } +} + +/* Destroy all cached ELF symbol tables */ +static void +elfSymsFlush() +{ +ESyms es; + + elfsLock(); + while ( (es = elfs) ) { + elfs = es->next; + es->next = 0; /* paranoia */ + elfSymsDestroy(es); + } + elfsUnlock(); + +} +#endif + +static void +elfLookupAddr(void *addr) +{ +Dl_info inf; +ESyms es; +uintptr_t minoff,off; +int i; +Sym sym; +Sym nearest; +const char *strtab; +uint8_t c; + + if ( ! dladdr(addr, &inf) || (!inf.dli_fname && !inf.dli_sname) ) { + /* unable to lookup */ + errlogPrintf("[%p]\n", addr); + return; + } + + if ( inf.dli_sname ) { + /* Have a symbol name - just use it and be done */ + errlogPrintf("%s(%s+0x%lu): [%p]\n", inf.dli_fname ? inf.dli_fname : "", inf.dli_sname, addr - inf.dli_saddr, addr); + return; + } + + /* No symbol info; try to access ELF file and ready symbol table from there */ + + elfsLock(); + + /* See if we have loaded this file already */ + for ( es=elfs; es && strcmp(inf.dli_fname, es->fname); es = es->next ) + /* nothing else to do */; + + if ( !es ) { + if ( ! (es = elfRead(inf.dli_fname, (uintptr_t)inf.dli_fbase)) ) { + elfsUnlock(); + /* this path can only be taken if there is no memory for '*es' */ + return; + } + es->next = elfs; + elfs = es; + } + + elfsUnlock(); + + nearest.raw = 0; + minoff = (uintptr_t)-1LL; + + if ( es->nsyms ) { + c = es->class; + sym.raw = es->symMap->addr + es->symMap->off; + strtab = es->strMap->addr + es->strMap->off; + + /* Do a brute-force search through the symbol table; if this is executed + * 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 ( ELFCLASS32 == c ) { + for ( i=0; insyms; i++ ) { + if ( STT_FUNC != ELF32_ST_TYPE(sym.e32[i].st_info) ) + continue; + /* 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 ( (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 ) { + minoff = off; + nearest.e32 = &sym.e32[i]; + } + } + } + } else { + for ( i=0; insyms; i++ ) { + if ( STT_FUNC != ELF64_ST_TYPE(sym.e64[i].st_info) ) + continue; + /* 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 ( (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 ) { + minoff = off; + nearest.e64 = &sym.e64[i]; + } + } + } + } + } + + if ( nearest.raw ) { + errlogPrintf("%s(%s+0x%"PRIxPTR"): [%p]\n", es->fname, strtab + ARR(c,nearest,0,st_name), minoff, addr); + } else { + errlogPrintf("%s[%p]\n", es->fname, addr); + } +} +#endif + +epicsShareFunc void epicsStacktrace(void) +{ +void **buf; +#ifndef USE_ELF +char **bts; +#endif +int i,n; + + if ( ! (buf = malloc(sizeof(*buf) * MAXDEPTH)) ) { + errlogPrintf("epicsStacktrace(): not enough memory for backtrace\n"); + return; + } + + n = backtrace(buf, MAXDEPTH); + + /* backtrace_symbols() only works for global symbols on linux. + * If we have dladdr() and then we can actually lookup local + * symbols, too. + */ +#ifdef USE_ELF + for ( i=0; i Date: Fri, 26 Aug 2011 17:02:02 -0700 Subject: [PATCH 02/41] - added copyright and author info. --- src/libCom/osi/epicsStacktrace.h | 9 +++++++++ src/libCom/osi/execinfoStacktrace.c | 9 +++++++++ src/libCom/osi/os/Darwin/osdStacktrace.c | 9 +++++++++ src/libCom/osi/os/Linux/osdStacktrace.c | 9 +++++++++ src/libCom/osi/os/default/osdStacktrace.c | 9 +++++++++ 5 files changed, 45 insertions(+) diff --git a/src/libCom/osi/epicsStacktrace.h b/src/libCom/osi/epicsStacktrace.h index e98d2a1b2..44c7098ab 100644 --- a/src/libCom/osi/epicsStacktrace.h +++ b/src/libCom/osi/epicsStacktrace.h @@ -1,3 +1,12 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + #ifndef INC_epicsStacktrace_H #define INC_epicsStacktrace_H diff --git a/src/libCom/osi/execinfoStacktrace.c b/src/libCom/osi/execinfoStacktrace.c index f4693d10b..3d36511f2 100644 --- a/src/libCom/osi/execinfoStacktrace.c +++ b/src/libCom/osi/execinfoStacktrace.c @@ -1,3 +1,12 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + #include "epicsStacktrace.h" #include "epicsThread.h" #include "epicsMutex.h" diff --git a/src/libCom/osi/os/Darwin/osdStacktrace.c b/src/libCom/osi/os/Darwin/osdStacktrace.c index 341dbec5f..c7b26c59c 100644 --- a/src/libCom/osi/os/Darwin/osdStacktrace.c +++ b/src/libCom/osi/os/Darwin/osdStacktrace.c @@ -1,3 +1,12 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + /* THIS FILE IS INTENTIONALLY EMPTY * * The presence of this file prevents the build diff --git a/src/libCom/osi/os/Linux/osdStacktrace.c b/src/libCom/osi/os/Linux/osdStacktrace.c index 341dbec5f..c7b26c59c 100644 --- a/src/libCom/osi/os/Linux/osdStacktrace.c +++ b/src/libCom/osi/os/Linux/osdStacktrace.c @@ -1,3 +1,12 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + /* THIS FILE IS INTENTIONALLY EMPTY * * The presence of this file prevents the build diff --git a/src/libCom/osi/os/default/osdStacktrace.c b/src/libCom/osi/os/default/osdStacktrace.c index 024ad32e8..3cb60c75d 100644 --- a/src/libCom/osi/os/default/osdStacktrace.c +++ b/src/libCom/osi/os/default/osdStacktrace.c @@ -1,3 +1,12 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + #include "epicsStacktrace.h" epicsShareFunc void epicsStacktrace(void) From 8b2b03482f8beca6db58af5dd85eafa7031b2925 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 28 Aug 2014 10:47:59 -0700 Subject: [PATCH 03/41] - consistent naming: 'StackTrace' everywhere. --- src/libCom/osi/Makefile | 12 +++--- src/libCom/osi/RULES | 2 +- src/libCom/osi/epicsStackTrace.h | 40 +++++++++++++++++++ src/libCom/osi/epicsStacktrace.h | 26 ------------ ...cinfoStacktrace.c => execinfoStackTrace.c} | 25 ++++++++++-- .../{osdStacktrace.c => osdStackTrace.c} | 2 +- .../{osdStacktrace.c => osdStackTrace.c} | 2 +- src/libCom/osi/os/default/osdAssert.c | 4 +- .../{osdStacktrace.c => osdStackTrace.c} | 10 ++++- 9 files changed, 80 insertions(+), 43 deletions(-) create mode 100644 src/libCom/osi/epicsStackTrace.h delete mode 100644 src/libCom/osi/epicsStacktrace.h rename src/libCom/osi/{execinfoStacktrace.c => execinfoStackTrace.c} (95%) rename src/libCom/osi/os/Darwin/{osdStacktrace.c => osdStackTrace.c} (92%) rename src/libCom/osi/os/Linux/{osdStacktrace.c => osdStackTrace.c} (92%) rename src/libCom/osi/os/default/{osdStacktrace.c => osdStackTrace.c} (66%) diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index 86cd3fc35..38fdf71c0 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -56,7 +56,7 @@ INC += epicsStdio.h INC += epicsStdioRedirect.h INC += epicsTempFile.h INC += epicsGetopt.h -INC += epicsStacktrace.h +INC += epicsStackTrace.h INC += devLib.h INC += devLibVME.h @@ -142,10 +142,10 @@ Com_SRCS_WIN32 += setThreadName.cpp #Com_SRCS_WIN32 += dllmain.cpp Com_SRCS_WIN32 += forceBadAllocException.cpp -#Stacktrace support -Com_SRCS += osdStacktrace.c -Com_SRCS_Linux += execinfoStacktrace.c -Com_SRCS_Darwin += execinfoStacktrace.c -#we could use execinfoStacktrace.c on freebsd, too, but AFAIK +#Stack trace support +Com_SRCS += osdStackTrace.c +Com_SRCS_Linux += execinfoStackTrace.c +Com_SRCS_Darwin += execinfoStackTrace.c +#we could use execinfoStackTrace.c on freebsd, too, but AFAIK #you need libexecinfo.a and execinfo.h. I don't know if that #is routinely available so we don't use it for now. diff --git a/src/libCom/osi/RULES b/src/libCom/osi/RULES index 642a5f506..e55cb0eed 100644 --- a/src/libCom/osi/RULES +++ b/src/libCom/osi/RULES @@ -16,4 +16,4 @@ osdSock$(DEP): $(COMMON_DIR)/epicsVersion.h execinfoConfig.h: touch $@ -execinfoStacktrace$(OBJ): execinfoConfig.h +execinfoStackTrace$(OBJ): execinfoConfig.h diff --git a/src/libCom/osi/epicsStackTrace.h b/src/libCom/osi/epicsStackTrace.h new file mode 100644 index 000000000..5aec62806 --- /dev/null +++ b/src/libCom/osi/epicsStackTrace.h @@ -0,0 +1,40 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011, 2014 + */ + +#ifndef INC_epicsStackTrace_H +#define INC_epicsStackTrace_H + +#include "shareLib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Dump a stack trace to the errlog */ +epicsShareFunc void epicsStackTrace(void); + +/* Inquire about functionality implemented on your system */ + +/* StackTrace is able to lookup local symbols */ +#define EPICS_STACKTRACE_LCL_SYMBOLS (1<<0) + +/* StackTrace is able to lookup global symbols */ +#define EPICS_STACKTRACE_GBL_SYMBOLS (1<<1) + +/* StackTrace provides numerical addresses */ +#define EPICS_STACKTRACE_ADDRESSES (1<<2) + +/* returns ORed bitset of supported features */ +epicsShareFunc int epicsStackTraceGetFeatures(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libCom/osi/epicsStacktrace.h b/src/libCom/osi/epicsStacktrace.h deleted file mode 100644 index 44c7098ab..000000000 --- a/src/libCom/osi/epicsStacktrace.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright: Stanford University / SLAC National Laboratory. - * - * EPICS BASE is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - * - * Author: Till Straumann , 2011 - */ - -#ifndef INC_epicsStacktrace_H -#define INC_epicsStacktrace_H - -#include "shareLib.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* Dump a stacktrace to the errlog */ -epicsShareFunc void epicsStackTrace(void); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/libCom/osi/execinfoStacktrace.c b/src/libCom/osi/execinfoStackTrace.c similarity index 95% rename from src/libCom/osi/execinfoStacktrace.c rename to src/libCom/osi/execinfoStackTrace.c index 3d36511f2..3839815a9 100644 --- a/src/libCom/osi/execinfoStacktrace.c +++ b/src/libCom/osi/execinfoStackTrace.c @@ -4,10 +4,10 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. * - * Author: Till Straumann , 2011 + * Author: Till Straumann , 2011, 2014 */ -#include "epicsStacktrace.h" +#include "epicsStackTrace.h" #include "epicsThread.h" #include "epicsMutex.h" #include @@ -560,7 +560,7 @@ uint8_t c; } #endif -epicsShareFunc void epicsStacktrace(void) +epicsShareFunc void epicsStackTrace(void) { void **buf; #ifndef USE_ELF @@ -569,7 +569,7 @@ char **bts; int i,n; if ( ! (buf = malloc(sizeof(*buf) * MAXDEPTH)) ) { - errlogPrintf("epicsStacktrace(): not enough memory for backtrace\n"); + errlogPrintf("epicsStackTrace(): not enough memory for backtrace\n"); return; } @@ -602,3 +602,20 @@ int i,n; free(buf); } + + +epicsShareFunc int epicsStackTraceGetFeatures(void) +{ +#ifdef USE_ELF + return EPICS_STACKTRACE_LCL_SYMBOLS + | EPICS_STACKTRACE_GBL_SYMBOLS + | EPICS_STACKTRACE_ADDRESSES; +#elif defined(__linux__) || defined(linux) + return EPICS_STACKTRACE_GBL_SYMBOLS + EPICS_STACKTRACE_ADDRESSES; +#else + return EPICS_STACKTRACE_LCL_SYMBOLS + | EPICS_STACKTRACE_GBL_SYMBOLS + | EPICS_STACKTRACE_ADDRESSES; +#endif +} diff --git a/src/libCom/osi/os/Darwin/osdStacktrace.c b/src/libCom/osi/os/Darwin/osdStackTrace.c similarity index 92% rename from src/libCom/osi/os/Darwin/osdStacktrace.c rename to src/libCom/osi/os/Darwin/osdStackTrace.c index c7b26c59c..3f25a0591 100644 --- a/src/libCom/osi/os/Darwin/osdStacktrace.c +++ b/src/libCom/osi/os/Darwin/osdStackTrace.c @@ -11,7 +11,7 @@ * * The presence of this file prevents the build * system from using the no-op implementation of - * epicsStacktrace() in default/osdStacktrace.c. + * epicsStackTrace() in default/osdStackTrace.c. * * This OS uses a generic implementation which * may be used by various OSes. The source file diff --git a/src/libCom/osi/os/Linux/osdStacktrace.c b/src/libCom/osi/os/Linux/osdStackTrace.c similarity index 92% rename from src/libCom/osi/os/Linux/osdStacktrace.c rename to src/libCom/osi/os/Linux/osdStackTrace.c index c7b26c59c..3f25a0591 100644 --- a/src/libCom/osi/os/Linux/osdStacktrace.c +++ b/src/libCom/osi/os/Linux/osdStackTrace.c @@ -11,7 +11,7 @@ * * The presence of this file prevents the build * system from using the no-op implementation of - * epicsStacktrace() in default/osdStacktrace.c. + * epicsStackTrace() in default/osdStackTrace.c. * * This OS uses a generic implementation which * may be used by various OSes. The source file diff --git a/src/libCom/osi/os/default/osdAssert.c b/src/libCom/osi/os/default/osdAssert.c index 3ec9c6442..26f94a14f 100644 --- a/src/libCom/osi/os/default/osdAssert.c +++ b/src/libCom/osi/os/default/osdAssert.c @@ -20,7 +20,7 @@ #include "epicsThread.h" #include "epicsTime.h" #include "cantProceed.h" -#include "epicsStacktrace.h" +#include "epicsStackTrace.h" void epicsAssert (const char *pFile, const unsigned line, @@ -35,7 +35,7 @@ void epicsAssert (const char *pFile, const unsigned line, errlogPrintf("\n" "I'll try to dump a stack trace:\n"); - epicsStacktrace(); + epicsStackTrace(); errlogPrintf("\n"); errlogPrintf("EPICS Release %s.\n", epicsReleaseVersion); diff --git a/src/libCom/osi/os/default/osdStacktrace.c b/src/libCom/osi/os/default/osdStackTrace.c similarity index 66% rename from src/libCom/osi/os/default/osdStacktrace.c rename to src/libCom/osi/os/default/osdStackTrace.c index 3cb60c75d..e10a24736 100644 --- a/src/libCom/osi/os/default/osdStacktrace.c +++ b/src/libCom/osi/os/default/osdStackTrace.c @@ -7,8 +7,14 @@ * Author: Till Straumann , 2011 */ -#include "epicsStacktrace.h" +#include "epicsStackTrace.h" -epicsShareFunc void epicsStacktrace(void) +epicsShareFunc void epicsStackTrace(void) { } + +epicsShareFunc int epicsStackTraceGetFeatures(void) +{ + return 0; +} + From ccb5be72dddb125a3d5489290e8fe2627356afcb Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 28 Aug 2014 10:49:22 -0700 Subject: [PATCH 04/41] - consistent naming: 'StackTrace' everywhere... --- src/libCom/misc/cantProceed.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libCom/misc/cantProceed.c b/src/libCom/misc/cantProceed.c index 3a6db7742..d782a07c7 100644 --- a/src/libCom/misc/cantProceed.c +++ b/src/libCom/misc/cantProceed.c @@ -19,7 +19,7 @@ #include "errlog.h" #include "cantProceed.h" #include "epicsThread.h" -#include "epicsStacktrace.h" +#include "epicsStackTrace.h" epicsShareFunc void * callocMustSucceed(size_t count, size_t size, const char *msg) { @@ -65,7 +65,7 @@ epicsShareFunc void cantProceed(const char *msg, ...) epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf()); errlogPrintf("Dumping a stack trace:\n"); - epicsStacktrace(); + epicsStackTrace(); errlogPrintf("\n"); errlogFlush(); From 5a06c118c8fb166b7f91c3e730a456288e78e0aa Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 28 Aug 2014 10:50:03 -0700 Subject: [PATCH 05/41] - added unit test for epicsStackTrace --- src/libCom/test/Makefile | 5 + src/libCom/test/epicsStackTraceTest.c | 215 ++++++++++++++++++++++++++ 2 files changed, 220 insertions(+) create mode 100644 src/libCom/test/epicsStackTraceTest.c diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index fd4800953..6bd9f8232 100755 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -184,6 +184,11 @@ epicsMessageQueueTest_SRCS += epicsMessageQueueTest.cpp testHarness_SRCS += epicsMessageQueueTest.cpp TESTS += epicsMessageQueueTest +TESTPROD_HOST += epicsStackTraceTest +epicsStackTraceTest_SRCS += epicsStackTraceTest.c +testHarness_SRCS += epicsStackTraceTest.c +TESTS += epicsStackTraceTest + # The testHarness runs all the test programs in a known working order. testHarness_SRCS += epicsRunLibComTests.c diff --git a/src/libCom/test/epicsStackTraceTest.c b/src/libCom/test/epicsStackTraceTest.c new file mode 100644 index 000000000..d7166a47d --- /dev/null +++ b/src/libCom/test/epicsStackTraceTest.c @@ -0,0 +1,215 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2014 + */ + +/* + * Check stack trace functionality + */ + +#include "epicsStackTrace.h" +#include "errlog.h" +#include "epicsUnitTest.h" +#include "testMain.h" +#include "inttypes.h" + +#include + +#undef TEST_DEBUG + +#define TST_BUFSZ 10000 + +#define MAXP 10 + +/* estimated size of (compiled) epicsStackTraceRecurseGbl */ +#define WINDOW_SZ 400 + +typedef struct TestDataRec_ { + char buf[TST_BUFSZ]; + int pos; +} TestDataRec, *TestData; + +typedef void (*RecFn)(int); + +/* We want a stack trace and need a few nested routines. + * The whole magic here is intended to prevent a compiler + * from optimizing the call stack away: + * - call via a volatile pointer + * - add a call to a no-op function at the end so that + * tail-call optimization doesn't eliminate the call + * stack. + * + * We use a local (static) and a global routine to test + * if the stacktrace supports either flavor. + */ + +void epicsStackTraceRecurseGbl(int lvl); +static void epicsStackTraceRecurseLcl(int lvl); + +void nopFn(int lvl) +{ +} + +RecFn volatile lfp = epicsStackTraceRecurseLcl; +RecFn volatile gfp = epicsStackTraceRecurseGbl; +RecFn volatile nop = nopFn; + +static void +epicsStackTraceRecurseLcl(int lvl) +{ + if ( lvl ) + gfp(lvl-1); + else + epicsStackTrace(); + + /* call something so that the call through gfp() doesn't + * get optimized into a jump (tail-call optimization) + */ + nop(0); +} + +void epicsStackTraceRecurseGbl(int lvl) +{ + if ( lvl ) + lfp(lvl-1); + else + epicsStackTrace(); + + /* call something so that the call through gfp() doesn't + * get optimized into a jump (tail-call optimization) + */ + nop(0); +} + +static void logClient(void *ptr, const char *msg) +{ +TestData td = ptr; +size_t sz = strlen(msg); +size_t mx = sizeof(td->buf) - td->pos - 1; + + if ( sz > mx ) + sz = mx; + strncpy( td->buf+td->pos, msg, sz ); + td->pos += sz; +} + +static int +findStringOcc(const char *buf, const char *what) +{ +int rval; +size_t l = strlen(what); + + for ( rval=0; (buf=strstr(buf, what)); buf+=l ) + rval++; + +#ifdef TEST_DEBUG + printf("found %i x %s\n", rval, what); +#endif + + return rval; +} + +static int +findNumOcc(const char *buf) +{ +void *ptrs[MAXP]; +int n_ptrs = 0; +int i,j; +int rval = 0; + + while ( n_ptrs < sizeof(ptrs)/sizeof(*ptrs[0]) && (buf=strchr(buf,'[')) ) { + if ( 1 == sscanf(buf+1,"%p", &ptrs[n_ptrs]) ) + n_ptrs++; + buf++; + } + /* We should find an address close to epicsStackTraceRecurseGbl twice */ + for (i=0; i= (void*)epicsStackTraceRecurseGbl && ptrs[i] < (void*)epicsStackTraceRecurseGbl + WINDOW_SZ ) { + rval ++; +#ifdef TEST_DEBUG + printf("found address %p again\n", ptrs[i]); +#endif + } + } + j++; + } + } + return rval; +} + +MAIN(epicsStackTraceTest) +{ +int features, all_features; +TestDataRec testData; +int gblFound, lclFound, numFound; + + testData.pos = 0; + + testPlan(4); + + features = epicsStackTraceGetFeatures(); + + all_features = EPICS_STACKTRACE_LCL_SYMBOLS + | EPICS_STACKTRACE_GBL_SYMBOLS + | EPICS_STACKTRACE_ADDRESSES; + + if ( ! testOk( (features & ~all_features) == 0, + "epicsStackTraceGetFeatures() obtains features") ) + testAbort("epicsStackTraceGetFeatures() not working as expected"); + + testData.pos = 0; + + testDiag("calling a few nested routines and eventually dump a stack trace"); + + eltc(0); + errlogAddListener( logClient, &testData ); + epicsStackTraceRecurseGbl(3); + errlogRemoveListeners( logClient, &testData ); + eltc(1); + + /* ensure there's a terminating NUL -- we have reserved space for it */ + testData.buf[testData.pos] = 0; + + testDiag("now scan the result for what we expect"); + + gblFound = findStringOcc( testData.buf, "epicsStackTraceRecurseGbl" ); + lclFound = findStringOcc( testData.buf, "epicsStackTraceRecurseLcl" ); + numFound = findNumOcc ( testData.buf ); + + if ( (features & EPICS_STACKTRACE_GBL_SYMBOLS) ) { + testOk( gblFound == 2, "dumping global symbols" ); + } else { + testOk( 1 , "no support for dumping global symbols on this platform"); + } + + if ( (features & EPICS_STACKTRACE_LCL_SYMBOLS) ) { + testOk( lclFound == 2, "dumping local symbols" ); + } else { + testOk( 1 , "no support for dumping local symbols on this platform"); + } + + if ( (features & EPICS_STACKTRACE_ADDRESSES) ) { + testOk( numFound > 0, "dumping addresses" ); + } else { + testOk( 1 , "no support for dumping addresses on this platform"); + } + + +#ifdef TEST_DEBUG + fputs(testData.buf, stdout); +#endif + + testDone(); + + return 0; +} From 47408ed14cc4ebb57c275f6a0b8390247da7dd50 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 28 Aug 2014 11:43:18 -0700 Subject: [PATCH 06/41] - indentation --- src/libCom/test/epicsStackTraceTest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/test/epicsStackTraceTest.c b/src/libCom/test/epicsStackTraceTest.c index d7166a47d..a4d66fe6d 100644 --- a/src/libCom/test/epicsStackTraceTest.c +++ b/src/libCom/test/epicsStackTraceTest.c @@ -19,7 +19,7 @@ #include -#undef TEST_DEBUG +#undef TEST_DEBUG #define TST_BUFSZ 10000 From 768c2c02e72602df382ab4f92d7e99afcaa0c5c3 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 28 Aug 2014 11:43:46 -0700 Subject: [PATCH 07/41] - 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); } From 079357c2423d401d2e7315d693015abd3ea48c58 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 28 Aug 2014 15:10:12 -0700 Subject: [PATCH 08/41] - let default (no-op) version of stack trace print informative message that stack traces are not supported. --- src/libCom/osi/os/default/osdStackTrace.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libCom/osi/os/default/osdStackTrace.c b/src/libCom/osi/os/default/osdStackTrace.c index e10a24736..ad18726ef 100644 --- a/src/libCom/osi/os/default/osdStackTrace.c +++ b/src/libCom/osi/os/default/osdStackTrace.c @@ -8,9 +8,13 @@ */ #include "epicsStackTrace.h" +#include "errlog.h" epicsShareFunc void epicsStackTrace(void) { + errlogFlush(); + errlogPrintf("StackTrace not supported on this platform, sorry\n"); + errlogFlush(); } epicsShareFunc int epicsStackTraceGetFeatures(void) From 0d323db997694b50c857e6ec6425fb5be667a3b2 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Fri, 29 Aug 2014 15:00:54 -0700 Subject: [PATCH 09/41] - removed obsolete rule (used during development) --- src/libCom/osi/RULES | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libCom/osi/RULES b/src/libCom/osi/RULES index e55cb0eed..71776c4a4 100644 --- a/src/libCom/osi/RULES +++ b/src/libCom/osi/RULES @@ -13,7 +13,3 @@ epicsTime$(DEP): $(COMMON_DIR)/epicsVersion.h osdNetIntf$(DEP): $(COMMON_DIR)/epicsVersion.h osdSock$(DEP): $(COMMON_DIR)/epicsVersion.h -execinfoConfig.h: - touch $@ - -execinfoStackTrace$(OBJ): execinfoConfig.h From 32c6888e1b8a89d60a25ba5d802128c0fccf9a9e Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Fri, 29 Aug 2014 15:02:20 -0700 Subject: [PATCH 10/41] - removed message about a stack trace going to be printed --- src/libCom/misc/cantProceed.c | 2 -- src/libCom/osi/os/default/osdAssert.c | 3 --- 2 files changed, 5 deletions(-) diff --git a/src/libCom/misc/cantProceed.c b/src/libCom/misc/cantProceed.c index d782a07c7..d8267b912 100644 --- a/src/libCom/misc/cantProceed.c +++ b/src/libCom/misc/cantProceed.c @@ -64,9 +64,7 @@ epicsShareFunc void cantProceed(const char *msg, ...) errlogPrintf("Thread %s (%p) can't proceed, suspending.\n", epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf()); - errlogPrintf("Dumping a stack trace:\n"); epicsStackTrace(); - errlogPrintf("\n"); errlogFlush(); diff --git a/src/libCom/osi/os/default/osdAssert.c b/src/libCom/osi/os/default/osdAssert.c index 26f94a14f..1c860a3e0 100644 --- a/src/libCom/osi/os/default/osdAssert.c +++ b/src/libCom/osi/os/default/osdAssert.c @@ -33,10 +33,7 @@ void epicsAssert (const char *pFile, const unsigned line, " by thread '%s' failed in %s line %u.\n", pExp, epicsThreadGetNameSelf(), pFile, line); - errlogPrintf("\n" - "I'll try to dump a stack trace:\n"); epicsStackTrace(); - errlogPrintf("\n"); errlogPrintf("EPICS Release %s.\n", epicsReleaseVersion); From f2626442b672cae243c87c08744f43c554f6e615 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Fri, 29 Aug 2014 15:03:04 -0700 Subject: [PATCH 11/41] - removed message; if there is no support remain silent --- src/libCom/osi/os/default/osdStackTrace.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libCom/osi/os/default/osdStackTrace.c b/src/libCom/osi/os/default/osdStackTrace.c index ad18726ef..d56711267 100644 --- a/src/libCom/osi/os/default/osdStackTrace.c +++ b/src/libCom/osi/os/default/osdStackTrace.c @@ -12,9 +12,6 @@ epicsShareFunc void epicsStackTrace(void) { - errlogFlush(); - errlogPrintf("StackTrace not supported on this platform, sorry\n"); - errlogFlush(); } epicsShareFunc int epicsStackTraceGetFeatures(void) From 16bef44e5d342c3bfe3f7070b09ba989d3a8e993 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Fri, 29 Aug 2014 15:03:56 -0700 Subject: [PATCH 12/41] - print header message --- src/libCom/osi/execinfoStackTrace.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libCom/osi/execinfoStackTrace.c b/src/libCom/osi/execinfoStackTrace.c index 7888196de..a9393161a 100644 --- a/src/libCom/osi/execinfoStackTrace.c +++ b/src/libCom/osi/execinfoStackTrace.c @@ -590,6 +590,8 @@ char **bts; #endif int i,n; + errlogPrintf("Dumping a stack trace:\n"); + errlogFlush(); if ( ! (buf = malloc(sizeof(*buf) * MAXDEPTH)) ) { @@ -624,6 +626,8 @@ int i,n; } #endif + errlogPrintf("\n"); + errlogFlush(); free(buf); From f399b354e6e6f063648f9de075e6ac11fbecaef7 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Wed, 3 Sep 2014 08:13:15 -0700 Subject: [PATCH 13/41] - replaced TABs by four blanks --- src/libCom/osi/execinfoStackTrace.c | 658 ++++++++++++++-------------- 1 file changed, 329 insertions(+), 329 deletions(-) diff --git a/src/libCom/osi/execinfoStackTrace.c b/src/libCom/osi/execinfoStackTrace.c index a9393161a..95d32b3f1 100644 --- a/src/libCom/osi/execinfoStackTrace.c +++ b/src/libCom/osi/execinfoStackTrace.c @@ -71,21 +71,21 @@ /* Elf header */ typedef union Ehdr_ { - Elf32_Ehdr e32; - Elf64_Ehdr e64; + Elf32_Ehdr e32; + Elf64_Ehdr e64; } Ehdr; /* Section header */ typedef union Shdr_ { - Elf32_Shdr e32; - Elf64_Shdr e64; + Elf32_Shdr e32; + Elf64_Shdr e64; } Shdr; /* Elf symbol */ typedef union Sym_ { - void *raw; - Elf32_Sym *e32; - Elf64_Sym *e64; + void *raw; + Elf32_Sym *e32; + Elf64_Sym *e64; } Sym; /* Memory mapped portion of a file; we must @@ -94,11 +94,11 @@ typedef union Sym_ { * page-aligned (man mmap). */ typedef struct MMap_ { - void *addr; - off_t off; /* offset into the map where 'real' data start */ - size_t len; - size_t max; /* max offset: legal data from addr+off .. addr+off+max-1 */ - void (*freeMap)(struct MMap_*); /* 'method' to destroy the mapping */ + void *addr; + off_t off; /* offset into the map where 'real' data start */ + size_t len; + 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 @@ -108,14 +108,14 @@ typedef struct MMap_ { * time we do a lookup). */ typedef struct ESyms_ { - struct ESyms_ *next; /* linked list; one struct per executable */ - const char *fname; /* file name */ - int fd; /* file descriptor */ - uintptr_t addr; /* address where file is loaded */ - MMap symMap; - MMap strMap; - size_t nsyms; - uint8_t class; + struct ESyms_ *next; /* linked list; one struct per executable */ + const char *fname; /* file name */ + int fd; /* file descriptor */ + uintptr_t addr; /* address where file is loaded */ + MMap symMap; + MMap strMap; + size_t nsyms; + uint8_t class; } *ESyms; /* Linked list where we keep all our ESyms */ @@ -125,28 +125,28 @@ static epicsMutexId elfsMtx; static void elfsInit(void *unused) { - elfsMtx = epicsMutexMustCreate(); + elfsMtx = epicsMutexMustCreate(); } static void elfsLock(void) { - epicsThreadOnce( &elfsInitId, elfsInit, 0 ); - epicsMutexLock( elfsMtx ); + epicsThreadOnce( &elfsInitId, elfsInit, 0 ); + epicsMutexLock( elfsMtx ); } static void elfsUnlock(void) { - epicsMutexUnlock( elfsMtx ); + epicsMutexUnlock( elfsMtx ); } static void freeMap(MMap m) { - if ( m ) { - m->freeMap(m); - free(m); - } + if ( m ) { + m->freeMap(m); + free(m); + } } /* Helper to read exactly 'sz' bytes into 'buf' @@ -157,14 +157,14 @@ do_read(int fd, void *buf, size_t sz) { size_t got; void *ptr=buf; - while ( sz > 0 ) { - if ( (got=read(fd,ptr,sz)) < 0 ) { - return got; - } - ptr+=got; - sz -=got; - } - return ptr-buf; + while ( sz > 0 ) { + if ( (got=read(fd,ptr,sz)) < 0 ) { + return got; + } + ptr+=got; + sz -=got; + } + return ptr-buf; } #ifdef USE_MMAP @@ -173,8 +173,8 @@ void *ptr=buf; static void freeMapMmap(MMap m) { - if ( MAP_FAILED != m->addr ) - munmap( m->addr, m->len ); + if ( MAP_FAILED != m->addr ) + munmap( m->addr, m->len ); } /* Obtain section data with mmap() */ @@ -185,32 +185,32 @@ size_t n; MMap rval = 0; size_t pgsz = sysconf(_SC_PAGESIZE); - if ( 0 == (n=FLD(c,(*shdr_p),sh_size)) ) { - errlogPrintf("elfRead - getscn() -- no section data\n"); - goto bail; - } + if ( 0 == (n=FLD(c,(*shdr_p),sh_size)) ) { + errlogPrintf("elfRead - getscn() -- no section data\n"); + goto bail; + } - if ( ! (rval = malloc(sizeof(*rval))) ) { - errlogPrintf("elfRead - getscn() -- no memory for section map\n"); - goto bail; - } + if ( ! (rval = malloc(sizeof(*rval))) ) { + errlogPrintf("elfRead - getscn() -- no memory for section map\n"); + goto bail; + } - rval->freeMap = freeMapMmap; + rval->freeMap = freeMapMmap; - 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; + 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)); - goto bail; - } + 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)); + goto bail; + } - return rval; + return rval; bail: - freeMap(rval); - return 0; + freeMap(rval); + return 0; } #else /* USE_MMAP */ @@ -219,7 +219,7 @@ bail: static void freeMapMalloc(MMap m) { - free(m->addr); + free(m->addr); } /* Read section data into a malloc()ed buffer */ @@ -229,43 +229,43 @@ getscn(int fd, uint8_t c, Shdr *shdr_p) size_t n; MMap rval = 0; - if ( 0 == (n=FLD(c,(*shdr_p),sh_size)) ) { - errlogPrintf("elfRead - getscn() -- no section data\n"); - goto bail; - } + if ( 0 == (n=FLD(c,(*shdr_p),sh_size)) ) { + errlogPrintf("elfRead - getscn() -- no section data\n"); + goto bail; + } - if ( ! (rval = malloc(sizeof(*rval))) ) { - errlogPrintf("elfRead - getscn() -- no memory for section map\n"); - goto bail; - } + if ( ! (rval = malloc(sizeof(*rval))) ) { + errlogPrintf("elfRead - getscn() -- no memory for section map\n"); + goto bail; + } - rval->freeMap = freeMapMalloc; + rval->freeMap = freeMapMalloc; - if ( ! (rval->addr = malloc(n)) ) { - errlogPrintf("elfRead - getscn() -- no memory for section data\n"); - goto bail; - } + if ( ! (rval->addr = malloc(n)) ) { + errlogPrintf("elfRead - getscn() -- no memory for section data\n"); + goto bail; + } - rval->off = 0; - rval->len = n; - rval->max = rval->len - rval->off; + 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) ) { - errlogPrintf("elfRead - getscn() -- seeking to sh_offset: %s\n", strerror(errno)); - goto bail; - } + /* seek to symbol table contents */ + if ( (off_t)-1 == lseek(fd, FLD(c,(*shdr_p),sh_offset), SEEK_SET) ) { + errlogPrintf("elfRead - getscn() -- seeking to sh_offset: %s\n", strerror(errno)); + goto bail; + } - if ( n != do_read(fd, rval->addr, n) ) { - errlogPrintf("elfRead - getscn() -- reading section contents: %s\n", strerror(errno)); - goto bail; - } + if ( n != do_read(fd, rval->addr, n) ) { + errlogPrintf("elfRead - getscn() -- reading section contents: %s\n", strerror(errno)); + goto bail; + } - return rval; + return rval; bail: - freeMap(rval); - return 0; + freeMap(rval); + return 0; } #endif /* USE_MMAP */ @@ -275,16 +275,16 @@ bail: static void elfSymsRelease(ESyms es) { - if ( es ) { - freeMap(es->symMap); - es->symMap = 0; - freeMap(es->strMap); - es->strMap = 0; - if ( es->fd >= 0 ) - close(es->fd); - es->fd = -1; - es->nsyms = 0; - } + if ( es ) { + freeMap(es->symMap); + es->symMap = 0; + freeMap(es->strMap); + es->strMap = 0; + if ( es->fd >= 0 ) + close(es->fd); + es->fd = -1; + es->nsyms = 0; + } } static ESyms @@ -298,139 +298,139 @@ ESyms es; ssize_t idx; const char *cp; - if ( !(es = malloc(sizeof(*es))) ) { - /* no memory -- give up */ - return 0; - } + if ( !(es = malloc(sizeof(*es))) ) { + /* no memory -- give up */ + return 0; + } - memset(es, 0, sizeof(*es)); - es->fd = -1; - es->fname = fname; + memset(es, 0, sizeof(*es)); + es->fd = -1; + es->fname = fname; - if ( (es->fd = open(fname, O_RDONLY)) < 0 ) { - errlogPrintf("elfRead() -- unable to open file: %s\n", strerror(errno)); - goto bail; - } + if ( (es->fd = open(fname, O_RDONLY)) < 0 ) { + errlogPrintf("elfRead() -- unable to open file: %s\n", strerror(errno)); + goto bail; + } - if ( EI_NIDENT != do_read(es->fd, &ehdr, EI_NIDENT) ) { - errlogPrintf("elfRead() -- unable to read ELF e_ident: %s\n", strerror(errno)); - goto bail; - } + if ( EI_NIDENT != do_read(es->fd, &ehdr, EI_NIDENT) ) { + errlogPrintf("elfRead() -- unable to read ELF e_ident: %s\n", strerror(errno)); + goto bail; + } - if ( ELFMAG0 != ehdr.e32.e_ident[EI_MAG0] - || ELFMAG1 != ehdr.e32.e_ident[EI_MAG1] - || ELFMAG2 != ehdr.e32.e_ident[EI_MAG2] - || ELFMAG3 != ehdr.e32.e_ident[EI_MAG3] ) { - errlogPrintf("bad ELF magic number\n"); - goto bail; - } + if ( ELFMAG0 != ehdr.e32.e_ident[EI_MAG0] + || ELFMAG1 != ehdr.e32.e_ident[EI_MAG1] + || ELFMAG2 != ehdr.e32.e_ident[EI_MAG2] + || ELFMAG3 != ehdr.e32.e_ident[EI_MAG3] ) { + errlogPrintf("bad ELF magic number\n"); + goto bail; + } - if ( EV_CURRENT != ehdr.e32.e_ident[EI_VERSION] ) { - errlogPrintf("bad ELF version\n"); - goto bail; - } + if ( EV_CURRENT != ehdr.e32.e_ident[EI_VERSION] ) { + errlogPrintf("bad ELF version\n"); + goto bail; + } - switch ( (es->class = c = ehdr.e32.e_ident[EI_CLASS]) ) { - default: - errlogPrintf("bad ELF class\n"); - goto bail; + switch ( (es->class = c = ehdr.e32.e_ident[EI_CLASS]) ) { + default: + errlogPrintf("bad ELF class\n"); + goto bail; - case ELFCLASS32: - n = sizeof(Elf32_Ehdr); - break; - case ELFCLASS64: - n = sizeof(Elf64_Ehdr); - break; - } - n -= EI_NIDENT; + case ELFCLASS32: + n = sizeof(Elf32_Ehdr); + break; + case ELFCLASS64: + n = sizeof(Elf64_Ehdr); + break; + } + n -= EI_NIDENT; - /* read rest */ - if ( n != do_read(es->fd, ehdr.e32.e_ident + EI_NIDENT, n) ) { - errlogPrintf("elfRead() -- unable to read ELF ehdr: %s\n", strerror(errno)); - goto bail; - } + /* read rest */ + if ( n != do_read(es->fd, ehdr.e32.e_ident + EI_NIDENT, n) ) { + errlogPrintf("elfRead() -- unable to read ELF ehdr: %s\n", strerror(errno)); + goto bail; + } - /* seek to section header table */ - if ( (off_t)-1 == lseek(es->fd, FLD(c,ehdr,e_shoff), SEEK_SET) ) { - errlogPrintf("elfRead() -- unable to seek to shoff: %s\n", strerror(errno)); - goto bail; - } + /* seek to section header table */ + if ( (off_t)-1 == lseek(es->fd, FLD(c,ehdr,e_shoff), SEEK_SET) ) { + errlogPrintf("elfRead() -- unable to seek to shoff: %s\n", strerror(errno)); + goto bail; + } - n = ELFCLASS32 == c ? sizeof(shdr.e32) : sizeof(shdr.e64); + n = ELFCLASS32 == c ? sizeof(shdr.e32) : sizeof(shdr.e64); - for ( i = 0; ifd, &shdr, n) ) { - errlogPrintf("elfRead() -- unable to read section header: %s\n", strerror(errno)); - goto bail; - } - if ( SHT_SYMTAB == FLD(c,shdr,sh_type) ) - break; - } + for ( i = 0; ifd, &shdr, n) ) { + errlogPrintf("elfRead() -- unable to read section header: %s\n", strerror(errno)); + goto bail; + } + if ( SHT_SYMTAB == FLD(c,shdr,sh_type) ) + break; + } - if ( i>=FLD(c,ehdr,e_shnum) ) { - errlogPrintf("elfRead() -- no symbol table found\n"); - goto bail; - } + if ( i>=FLD(c,ehdr,e_shnum) ) { + errlogPrintf("elfRead() -- no symbol table found\n"); + goto bail; + } - if ( 0 == (n=FLD(c,shdr,sh_size)) ) { - errlogPrintf("elfRead() -- no symbol table data\n"); - goto bail; - } + if ( 0 == (n=FLD(c,shdr,sh_size)) ) { + errlogPrintf("elfRead() -- no symbol table data\n"); + goto bail; + } - if ( !(es->symMap = getscn(es->fd, c, &shdr)) ) { - errlogPrintf("elfRead() -- unable to read ELF symtab\n"); - goto bail; - } + if ( !(es->symMap = getscn(es->fd, c, &shdr)) ) { + errlogPrintf("elfRead() -- unable to read ELF symtab\n"); + goto bail; + } - es->nsyms = n / (ELFCLASS32==c ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym)); + es->nsyms = n / (ELFCLASS32==c ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym)); - /* find and read string table */ - - n = ELFCLASS32 == c ? sizeof(shdr.e32) : sizeof(shdr.e64); + /* find and read string table */ + + n = ELFCLASS32 == c ? sizeof(shdr.e32) : sizeof(shdr.e64); - /* seek to section header table */ - if ( (off_t)-1 == lseek(es->fd, FLD(c,ehdr,e_shoff) + n * FLD(c,shdr,sh_link), SEEK_SET) ) { - errlogPrintf("elfRead() -- unable to lseek to ELF e_shoff: %s\n", strerror(errno)); - goto bail; - } + /* seek to section header table */ + if ( (off_t)-1 == lseek(es->fd, FLD(c,ehdr,e_shoff) + n * FLD(c,shdr,sh_link), SEEK_SET) ) { + errlogPrintf("elfRead() -- unable to lseek to ELF e_shoff: %s\n", strerror(errno)); + goto bail; + } - if ( n != do_read(es->fd, &shdr, n) ) { - errlogPrintf("elfRead() -- unable to read ELF strtab section header: %s\n", strerror(errno)); - goto bail; - } + if ( n != do_read(es->fd, &shdr, n) ) { + errlogPrintf("elfRead() -- unable to read ELF strtab section header: %s\n", strerror(errno)); + goto bail; + } - if ( !(es->strMap = getscn(es->fd,c,&shdr)) ) { - errlogPrintf("elfRead() -- unable to read ELF strtab\n"); - goto bail; - } + if ( !(es->strMap = getscn(es->fd,c,&shdr)) ) { + errlogPrintf("elfRead() -- unable to read ELF strtab\n"); + 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; + /* 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 */ - es->addr = 0; - break; - case ET_DYN: - /* Symbols in an shared library are relative to base address */ - es->addr = fbase; - break; - default: - errlogPrintf("elfLookupAddr(): Unexpected ELF object file type %u\n", FLD(c,ehdr,e_type)); - goto bail; - } - - return es; + switch ( FLD(c,ehdr,e_type) ) { + case ET_EXEC: + /* Symbols in an executable already has absolute addresses */ + es->addr = 0; + break; + case ET_DYN: + /* Symbols in an shared library are relative to base address */ + es->addr = fbase; + break; + default: + errlogPrintf("elfLookupAddr(): Unexpected ELF object file type %u\n", FLD(c,ehdr,e_type)); + goto bail; + } + + return es; bail: - elfSymsRelease(es); - return es; + elfSymsRelease(es); + return es; } #if 0 @@ -451,10 +451,10 @@ bail: static void elfSymsDestroy(ESyms es) { - if ( es ) { - elfSymsRelease(es); - free(es); - } + if ( es ) { + elfSymsRelease(es); + free(es); + } } /* Destroy all cached ELF symbol tables */ @@ -463,13 +463,13 @@ elfSymsFlush() { ESyms es; - elfsLock(); - while ( (es = elfs) ) { - elfs = es->next; - es->next = 0; /* paranoia */ - elfSymsDestroy(es); - } - elfsUnlock(); + elfsLock(); + while ( (es = elfs) ) { + elfs = es->next; + es->next = 0; /* paranoia */ + elfSymsDestroy(es); + } + elfsUnlock(); } #endif @@ -487,98 +487,98 @@ const char *strtab; uint8_t c; size_t idx; - if ( ! dladdr(addr, &inf) || (!inf.dli_fname && !inf.dli_sname) ) { - /* unable to lookup */ - errlogPrintf("[%p]\n", addr); - return; - } + if ( ! dladdr(addr, &inf) || (!inf.dli_fname && !inf.dli_sname) ) { + /* unable to lookup */ + errlogPrintf("[%p]\n", addr); + return; + } - if ( inf.dli_sname ) { - /* Have a symbol name - just use it and be done */ - errlogPrintf("%s(%s+0x%lu): [%p]\n", inf.dli_fname ? inf.dli_fname : "", inf.dli_sname, addr - inf.dli_saddr, addr); - return; - } + if ( inf.dli_sname ) { + /* Have a symbol name - just use it and be done */ + errlogPrintf("%s(%s+0x%lu): [%p]\n", inf.dli_fname ? inf.dli_fname : "", inf.dli_sname, addr - inf.dli_saddr, addr); + return; + } - /* No symbol info; try to access ELF file and ready symbol table from there */ + /* No symbol info; try to access ELF file and ready symbol table from there */ - elfsLock(); + elfsLock(); - /* See if we have loaded this file already */ - for ( es=elfs; es && strcmp(inf.dli_fname, es->fname); es = es->next ) - /* nothing else to do */; + /* See if we have loaded this file already */ + for ( es=elfs; es && strcmp(inf.dli_fname, es->fname); es = es->next ) + /* nothing else to do */; - if ( !es ) { - if ( ! (es = elfRead(inf.dli_fname, (uintptr_t)inf.dli_fbase)) ) { - elfsUnlock(); - /* this path can only be taken if there is no memory for '*es' */ - return; - } - es->next = elfs; - elfs = es; - } + if ( !es ) { + if ( ! (es = elfRead(inf.dli_fname, (uintptr_t)inf.dli_fbase)) ) { + elfsUnlock(); + /* this path can only be taken if there is no memory for '*es' */ + return; + } + es->next = elfs; + elfs = es; + } - elfsUnlock(); + elfsUnlock(); - nearest.raw = 0; - minoff = (uintptr_t)-1LL; + nearest.raw = 0; + minoff = (uintptr_t)-1LL; - if ( es->nsyms ) { - c = es->class; - sym.raw = es->symMap->addr + es->symMap->off; - strtab = es->strMap->addr + es->strMap->off; + if ( es->nsyms ) { + c = es->class; + sym.raw = es->symMap->addr + es->symMap->off; + strtab = es->strMap->addr + es->strMap->off; - /* Do a brute-force search through the symbol table; if this is executed - * very often then it would be worthwhile constructing a sorted list of - * symbol addresses but for the stack trace we don't care... - */ + /* Do a brute-force search through the symbol table; if this is executed + * very often then it would be worthwhile constructing a sorted list of + * symbol addresses but for the stack trace we don't care... + */ #if (STACKTRACE_DEBUG & 1) - printf("Looking for %p\n", addr); + printf("Looking for %p\n", addr); #endif - if ( ELFCLASS32 == c ) { - for ( i=0; insyms; i++ ) { - if ( STT_FUNC != ELF32_ST_TYPE(sym.e32[i].st_info) ) - continue; - /* don't bother about undefined symbols */ - if ( 0 == sym.e32[i].st_shndx ) - continue; + if ( ELFCLASS32 == c ) { + for ( i=0; insyms; i++ ) { + if ( STT_FUNC != ELF32_ST_TYPE(sym.e32[i].st_info) ) + continue; + /* don't bother about undefined symbols */ + if ( 0 == sym.e32[i].st_shndx ) + continue; #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)); + 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 ) { - minoff = off; - nearest.e32 = &sym.e32[i]; - } - } - } - } else { - for ( i=0; insyms; i++ ) { - if ( STT_FUNC != ELF64_ST_TYPE(sym.e64[i].st_info) ) - continue; - /* don't bother about undefined symbols */ - if ( 0 == sym.e64[i].st_shndx ) - continue; + 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 ) { + minoff = off; + nearest.e32 = &sym.e32[i]; + } + } + } + } else { + for ( i=0; insyms; i++ ) { + if ( STT_FUNC != ELF64_ST_TYPE(sym.e64[i].st_info) ) + continue; + /* don't bother about undefined symbols */ + if ( 0 == sym.e64[i].st_shndx ) + continue; #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)); + 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 ) { - minoff = off; - nearest.e64 = &sym.e64[i]; - } - } - } - } - } + 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 ) { + minoff = off; + nearest.e64 = &sym.e64[i]; + } + } + } + } + } - 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); - } + 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); + } } #endif @@ -590,62 +590,62 @@ char **bts; #endif int i,n; - errlogPrintf("Dumping a stack trace:\n"); + errlogPrintf("Dumping a stack trace:\n"); - errlogFlush(); + errlogFlush(); - if ( ! (buf = malloc(sizeof(*buf) * MAXDEPTH)) ) { - errlogPrintf("epicsStackTrace(): not enough memory for backtrace\n"); - return; - } + if ( ! (buf = malloc(sizeof(*buf) * MAXDEPTH)) ) { + errlogPrintf("epicsStackTrace(): not enough memory for backtrace\n"); + return; + } - n = backtrace(buf, MAXDEPTH); + n = backtrace(buf, MAXDEPTH); - /* backtrace_symbols() only works for global symbols on linux. - * If we have dladdr() and then we can actually lookup local - * symbols, too. - */ + /* backtrace_symbols() only works for global symbols on linux. + * If we have dladdr() and then we can actually lookup local + * symbols, too. + */ #ifdef USE_ELF - for ( i=0; i Date: Wed, 3 Sep 2014 09:39:15 -0700 Subject: [PATCH 14/41] - replaced TABs by four blanks --- src/libCom/test/epicsStackTraceTest.c | 193 +++++++++++++------------- 1 file changed, 97 insertions(+), 96 deletions(-) diff --git a/src/libCom/test/epicsStackTraceTest.c b/src/libCom/test/epicsStackTraceTest.c index a4d66fe6d..e9983b8e1 100644 --- a/src/libCom/test/epicsStackTraceTest.c +++ b/src/libCom/test/epicsStackTraceTest.c @@ -18,8 +18,7 @@ #include "inttypes.h" #include - -#undef TEST_DEBUG +#include #define TST_BUFSZ 10000 @@ -28,9 +27,11 @@ /* estimated size of (compiled) epicsStackTraceRecurseGbl */ #define WINDOW_SZ 400 +static int test_debug = 0; + typedef struct TestDataRec_ { - char buf[TST_BUFSZ]; - int pos; + char buf[TST_BUFSZ]; + int pos; } TestDataRec, *TestData; typedef void (*RecFn)(int); @@ -61,28 +62,28 @@ RecFn volatile nop = nopFn; static void epicsStackTraceRecurseLcl(int lvl) { - if ( lvl ) - gfp(lvl-1); - else - epicsStackTrace(); + if ( lvl ) + gfp(lvl-1); + else + epicsStackTrace(); - /* call something so that the call through gfp() doesn't + /* call something so that the call through gfp() doesn't * get optimized into a jump (tail-call optimization) - */ - nop(0); + */ + nop(0); } void epicsStackTraceRecurseGbl(int lvl) { - if ( lvl ) - lfp(lvl-1); - else - epicsStackTrace(); + if ( lvl ) + lfp(lvl-1); + else + epicsStackTrace(); - /* call something so that the call through gfp() doesn't + /* call something so that the call through gfp() doesn't * get optimized into a jump (tail-call optimization) - */ - nop(0); + */ + nop(0); } static void logClient(void *ptr, const char *msg) @@ -91,10 +92,10 @@ TestData td = ptr; size_t sz = strlen(msg); size_t mx = sizeof(td->buf) - td->pos - 1; - if ( sz > mx ) - sz = mx; - strncpy( td->buf+td->pos, msg, sz ); - td->pos += sz; + if ( sz > mx ) + sz = mx; + strncpy( td->buf+td->pos, msg, sz ); + td->pos += sz; } static int @@ -103,14 +104,13 @@ findStringOcc(const char *buf, const char *what) int rval; size_t l = strlen(what); - for ( rval=0; (buf=strstr(buf, what)); buf+=l ) - rval++; + for ( rval=0; (buf=strstr(buf, what)); buf+=l ) + rval++; -#ifdef TEST_DEBUG - printf("found %i x %s\n", rval, what); -#endif + if ( test_debug ) + printf("found %i x %s\n", rval, what); - return rval; + return rval; } static int @@ -121,30 +121,29 @@ int n_ptrs = 0; int i,j; int rval = 0; - while ( n_ptrs < sizeof(ptrs)/sizeof(*ptrs[0]) && (buf=strchr(buf,'[')) ) { - if ( 1 == sscanf(buf+1,"%p", &ptrs[n_ptrs]) ) - n_ptrs++; - buf++; - } - /* We should find an address close to epicsStackTraceRecurseGbl twice */ - for (i=0; i= (void*)epicsStackTraceRecurseGbl && ptrs[i] < (void*)epicsStackTraceRecurseGbl + WINDOW_SZ ) { - rval ++; -#ifdef TEST_DEBUG - printf("found address %p again\n", ptrs[i]); -#endif - } - } - j++; - } - } - return rval; + while ( n_ptrs < sizeof(ptrs)/sizeof(*ptrs[0]) && (buf=strchr(buf,'[')) ) { + if ( 1 == sscanf(buf+1,"%p", &ptrs[n_ptrs]) ) + n_ptrs++; + buf++; + } + /* We should find an address close to epicsStackTraceRecurseGbl twice */ + for (i=0; i= (void*)epicsStackTraceRecurseGbl && ptrs[i] < (void*)epicsStackTraceRecurseGbl + WINDOW_SZ ) { + rval ++; + if ( test_debug ) + printf("found address %p again\n", ptrs[i]); + } + } + j++; + } + } + return rval; } MAIN(epicsStackTraceTest) @@ -153,63 +152,65 @@ int features, all_features; TestDataRec testData; int gblFound, lclFound, numFound; - testData.pos = 0; + if ( getenv("EPICS_STACK_TRACE_TEST_DEBUG") ) + test_debug = 1; - testPlan(4); + testData.pos = 0; - features = epicsStackTraceGetFeatures(); + testPlan(4); - all_features = EPICS_STACKTRACE_LCL_SYMBOLS - | EPICS_STACKTRACE_GBL_SYMBOLS - | EPICS_STACKTRACE_ADDRESSES; - - if ( ! testOk( (features & ~all_features) == 0, - "epicsStackTraceGetFeatures() obtains features") ) - testAbort("epicsStackTraceGetFeatures() not working as expected"); + features = epicsStackTraceGetFeatures(); - testData.pos = 0; + all_features = EPICS_STACKTRACE_LCL_SYMBOLS + | EPICS_STACKTRACE_GBL_SYMBOLS + | EPICS_STACKTRACE_ADDRESSES; + + if ( ! testOk( (features & ~all_features) == 0, + "epicsStackTraceGetFeatures() obtains features") ) + testAbort("epicsStackTraceGetFeatures() not working as expected"); - testDiag("calling a few nested routines and eventually dump a stack trace"); + testData.pos = 0; - eltc(0); - errlogAddListener( logClient, &testData ); - epicsStackTraceRecurseGbl(3); - errlogRemoveListeners( logClient, &testData ); - eltc(1); + testDiag("calling a few nested routines and eventually dump a stack trace"); - /* ensure there's a terminating NUL -- we have reserved space for it */ - testData.buf[testData.pos] = 0; + eltc(0); + errlogAddListener( logClient, &testData ); + epicsStackTraceRecurseGbl(3); + errlogRemoveListeners( logClient, &testData ); + eltc(1); - testDiag("now scan the result for what we expect"); + /* ensure there's a terminating NUL -- we have reserved space for it */ + testData.buf[testData.pos] = 0; - gblFound = findStringOcc( testData.buf, "epicsStackTraceRecurseGbl" ); - lclFound = findStringOcc( testData.buf, "epicsStackTraceRecurseLcl" ); - numFound = findNumOcc ( testData.buf ); - - if ( (features & EPICS_STACKTRACE_GBL_SYMBOLS) ) { - testOk( gblFound == 2, "dumping global symbols" ); - } else { - testOk( 1 , "no support for dumping global symbols on this platform"); - } + testDiag("now scan the result for what we expect"); - if ( (features & EPICS_STACKTRACE_LCL_SYMBOLS) ) { - testOk( lclFound == 2, "dumping local symbols" ); - } else { - testOk( 1 , "no support for dumping local symbols on this platform"); - } + gblFound = findStringOcc( testData.buf, "epicsStackTraceRecurseGbl" ); + lclFound = findStringOcc( testData.buf, "epicsStackTraceRecurseLcl" ); + numFound = findNumOcc ( testData.buf ); + + if ( (features & EPICS_STACKTRACE_GBL_SYMBOLS) ) { + testOk( gblFound == 2, "dumping global symbols" ); + } else { + testOk( 1 , "no support for dumping global symbols on this platform"); + } - if ( (features & EPICS_STACKTRACE_ADDRESSES) ) { - testOk( numFound > 0, "dumping addresses" ); - } else { - testOk( 1 , "no support for dumping addresses on this platform"); - } + if ( (features & EPICS_STACKTRACE_LCL_SYMBOLS) ) { + testOk( lclFound == 2, "dumping local symbols" ); + } else { + testOk( 1 , "no support for dumping local symbols on this platform"); + } + + if ( (features & EPICS_STACKTRACE_ADDRESSES) ) { + testOk( numFound > 0, "dumping addresses" ); + } else { + testOk( 1 , "no support for dumping addresses on this platform"); + } -#ifdef TEST_DEBUG - fputs(testData.buf, stdout); -#endif + if ( test_debug ) + fputs(testData.buf, stdout); - testDone(); + testDone(); - return 0; + return 0; } From fab9ef61476ba4c81d7e25201eede1dd33d6ce71 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Wed, 3 Sep 2014 13:23:23 -0700 Subject: [PATCH 15/41] - added test case for library symbols - replaced TABs by spaces --- src/libCom/test/epicsStackTraceTest.c | 44 +++++++++++++++++++++------ 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/src/libCom/test/epicsStackTraceTest.c b/src/libCom/test/epicsStackTraceTest.c index e9983b8e1..ab33d31aa 100644 --- a/src/libCom/test/epicsStackTraceTest.c +++ b/src/libCom/test/epicsStackTraceTest.c @@ -15,10 +15,10 @@ #include "errlog.h" #include "epicsUnitTest.h" #include "testMain.h" -#include "inttypes.h" #include #include +#include #define TST_BUFSZ 10000 @@ -103,12 +103,20 @@ findStringOcc(const char *buf, const char *what) { int rval; size_t l = strlen(what); +int ch; - for ( rval=0; (buf=strstr(buf, what)); buf+=l ) - rval++; + rval = 0; + while ( (buf = strstr(buf, what)) ) { + /* Is it just a prefix? */ + ch = buf[l]; + if ( ! isalnum(ch) && '_' != ch ) { + rval++; + } + buf += l; + } if ( test_debug ) - printf("found %i x %s\n", rval, what); + testDiag("found %i x %s\n", rval, what); return rval; } @@ -137,7 +145,7 @@ int rval = 0; if ( ptrs[i] >= (void*)epicsStackTraceRecurseGbl && ptrs[i] < (void*)epicsStackTraceRecurseGbl + WINDOW_SZ ) { rval ++; if ( test_debug ) - printf("found address %p again\n", ptrs[i]); + testDiag("found address %p again\n", ptrs[i]); } } j++; @@ -150,19 +158,21 @@ MAIN(epicsStackTraceTest) { int features, all_features; TestDataRec testData; -int gblFound, lclFound, numFound; +int gblFound, lclFound, numFound, dynFound; +char *nl, *p; if ( getenv("EPICS_STACK_TRACE_TEST_DEBUG") ) test_debug = 1; testData.pos = 0; - testPlan(4); + testPlan(5); features = epicsStackTraceGetFeatures(); all_features = EPICS_STACKTRACE_LCL_SYMBOLS | EPICS_STACKTRACE_GBL_SYMBOLS + | EPICS_STACKTRACE_DYN_SYMBOLS | EPICS_STACKTRACE_ADDRESSES; if ( ! testOk( (features & ~all_features) == 0, @@ -184,9 +194,17 @@ int gblFound, lclFound, numFound; testDiag("now scan the result for what we expect"); + dynFound = findStringOcc( testData.buf, "epicsStackTrace" ); gblFound = findStringOcc( testData.buf, "epicsStackTraceRecurseGbl" ); lclFound = findStringOcc( testData.buf, "epicsStackTraceRecurseLcl" ); numFound = findNumOcc ( testData.buf ); + + if ( (features & EPICS_STACKTRACE_DYN_SYMBOLS) ) { + testOk( dynFound == 1, "dumping symbol from library" ); + } else { + testOk( 1 , "no support for dumping library symbols on this platform"); + } + if ( (features & EPICS_STACKTRACE_GBL_SYMBOLS) ) { testOk( gblFound == 2, "dumping global symbols" ); @@ -207,8 +225,16 @@ int gblFound, lclFound, numFound; } - if ( test_debug ) - fputs(testData.buf, stdout); + if ( test_debug ) { + p = testData.buf; + while ( (nl = strchr(p,'\n')) ) { + *nl = 0; + testDiag("%s",p); + *nl = '\n'; + p = nl+1; + } + testDiag("%s", p); + } testDone(); From 68429f03f28481d5b059884b1779bbc26b7a336f Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 4 Sep 2014 10:58:27 -0700 Subject: [PATCH 16/41] - added EPICS_STACKTRACE_DYN_SYMBOL --- src/libCom/osi/epicsStackTrace.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/libCom/osi/epicsStackTrace.h b/src/libCom/osi/epicsStackTrace.h index 5aec62806..885e90abe 100644 --- a/src/libCom/osi/epicsStackTrace.h +++ b/src/libCom/osi/epicsStackTrace.h @@ -21,16 +21,19 @@ epicsShareFunc void epicsStackTrace(void); /* Inquire about functionality implemented on your system */ -/* StackTrace is able to lookup local symbols */ -#define EPICS_STACKTRACE_LCL_SYMBOLS (1<<0) +/* StackTrace provides numerical addresses */ +#define EPICS_STACKTRACE_ADDRESSES (1<<0) -/* StackTrace is able to lookup global symbols */ -#define EPICS_STACKTRACE_GBL_SYMBOLS (1<<1) +/* StackTrace is able to lookup dynamic symbols */ +#define EPICS_STACKTRACE_DYN_SYMBOLS (1<<1) -/* StackTrace provides numerical addresses */ -#define EPICS_STACKTRACE_ADDRESSES (1<<2) +/* StackTrace is able to lookup global symbols */ +#define EPICS_STACKTRACE_GBL_SYMBOLS (1<<2) -/* returns ORed bitset of supported features */ +/* StackTrace is able to lookup local symbols */ +#define EPICS_STACKTRACE_LCL_SYMBOLS (1<<3) + +/* returns ORed bitset of supported features */ epicsShareFunc int epicsStackTraceGetFeatures(void); #ifdef __cplusplus From fd9fed22628234e8ab5a83b4d072df9ed9929281 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 4 Sep 2014 10:59:39 -0700 Subject: [PATCH 17/41] - canonicalized printout formatting - added EPICS_STACKTRACE_DYN_SYMBOL - added USE_DLADDR branch (which is a 'super' of USE_ELF, i.e., the latter depends on the former) --- src/libCom/osi/execinfoStackTrace.c | 317 ++++++++++++++++++++++------ 1 file changed, 254 insertions(+), 63 deletions(-) diff --git a/src/libCom/osi/execinfoStackTrace.c b/src/libCom/osi/execinfoStackTrace.c index 95d32b3f1..0c8145465 100644 --- a/src/libCom/osi/execinfoStackTrace.c +++ b/src/libCom/osi/execinfoStackTrace.c @@ -7,6 +7,8 @@ * Author: Till Straumann , 2011, 2014 */ +#define _GNU_SOURCE + #include "epicsStackTrace.h" #include "epicsThread.h" #include "epicsMutex.h" @@ -16,7 +18,6 @@ #include #include #include -#include #define MAXDEPTH 100 @@ -27,7 +28,6 @@ * Hence, on linux we want to use dladdr() and lookup static * symbols in the ELF symbol table. */ -#define __USE_GNU #ifdef freebsd /* Some freebsd versions seem to export dladdr() only if __BSD_VISIBLE */ @@ -39,6 +39,8 @@ /* Check if we actually have the gnu/darwin extensions */ #ifdef RTLD_DEFAULT +#define USE_DLADDR + #if defined(__linux__) || defined(linux) #define USE_ELF #define USE_MMAP @@ -52,6 +54,9 @@ #include #include +/* How many chars to reserve (on avg) for a line of output */ +#define MAXSYMLEN 500 + #ifdef USE_MMAP #include #endif /* USE_MMAP */ @@ -62,6 +67,12 @@ #undef USE_ELF #endif /* RTLD_DEFAULT */ +/* Forward Declaration */ +#define NO_OFF ((unsigned long)-1L) + +static ssize_t +symDump(char *buf, size_t buf_sz, void *addr, const char *fnam, const char *snam, unsigned long off); + #ifdef USE_ELF /* Macros to handle elf32 vs. elf64 access to unions etc. */ @@ -118,27 +129,52 @@ typedef struct ESyms_ { uint8_t class; } *ESyms; +/* LOCKING NOTE: if the ELF symbol facility is ever expanded to be truly used + * in a multithreaded way then proper multiple-readers, single-writer locking + * should be implemented: + * - elfsLockWrite() must block until all readers have left + * - elfsLockRead() must block until writer has left. + * - elfsLockConvertWriteRead() atomically converts writer holding the + * writer's lock into a reader. + * Right now we just use a single, global lock (for the stack trace) since we + * only need to guard against multiple threads dumping stacks simultaneously and + * we do not lock the symbol table(s) at all. + */ + /* Linked list where we keep all our ESyms */ static ESyms elfs = 0; -static epicsThreadOnceId elfsInitId = EPICS_THREAD_ONCE_INIT; -static epicsMutexId elfsMtx; -static void elfsInit(void *unused) +static void +elfsLockWrite() { - elfsMtx = epicsMutexMustCreate(); + /* Only a single writer can hold this while no readers are active */ } -static void elfsLock(void) +static void +elfsUnlockWrite() { - epicsThreadOnce( &elfsInitId, elfsInit, 0 ); - epicsMutexLock( elfsMtx ); + /* Must wake up readers blocking in elfsLockRead() */ } -static void elfsUnlock(void) +static void +elfsLockConvertWriteRead() { - epicsMutexUnlock( elfsMtx ); + /* Must atomically convert a writer into a reader, i.e., unlock + * the writer's lock and atomically acquire the reader's lock + */ } +static void +elfsLockRead() +{ + /* Multiple readers can hold this while the writer is not active */ +} + +static void +elfsUnlockRead() +{ + /* Must wake up a (single) writer blockingĀ in elfsLockWrite */ +} static void freeMap(MMap m) @@ -433,20 +469,6 @@ bail: return es; } -#if 0 -/* IMPLEMENTATION IS INCORRECT: - * with only a single lock 'elfLookupAddr()' would - * have to hold that the entire time while accessing - * a symbol table. This is inefficient if there are - * multiple readers. A better implementation would - * use a 'multiple-readers/single-writer' type of lock - * to protect the symbol tables. - * - * ATM we simply don't support destroying the - * tables (after dumping a stack trace the process is - * likely to be terminated anyways). - */ - /* Destroy a cached ELF symbol table */ static void elfSymsDestroy(ESyms es) @@ -463,22 +485,36 @@ elfSymsFlush() { ESyms es; - elfsLock(); + elfsLockWrite(); while ( (es = elfs) ) { elfs = es->next; es->next = 0; /* paranoia */ elfSymsDestroy(es); } - elfsUnlock(); + elfsUnlockWrite(); } -#endif -static void -elfLookupAddr(void *addr) +static ESyms +elfSymsFind(const char *fname) +{ +ESyms es; + for ( es=elfs; es && strcmp(fname, es->fname); es = es->next ) + /* nothing else to do */; + return es; +} +#endif /* USE_ELF */ + +#ifdef USE_DLADDR + +static ssize_t +elfLookupAddr(void *addr, char *buf, size_t buf_sz) { Dl_info inf; -ESyms es; +ssize_t rval; + +#ifdef USE_ELF +ESyms es,nes; uintptr_t minoff,off; int i; Sym sym; @@ -486,38 +522,55 @@ Sym nearest; const char *strtab; uint8_t c; size_t idx; +#endif if ( ! dladdr(addr, &inf) || (!inf.dli_fname && !inf.dli_sname) ) { /* unable to lookup */ - errlogPrintf("[%p]\n", addr); - return; + return symDump(buf, buf_sz, addr, 0, 0, NO_OFF); } if ( inf.dli_sname ) { /* Have a symbol name - just use it and be done */ - errlogPrintf("%s(%s+0x%lu): [%p]\n", inf.dli_fname ? inf.dli_fname : "", inf.dli_sname, addr - inf.dli_saddr, addr); - return; + return symDump(buf, buf_sz, addr, inf.dli_fname, inf.dli_sname, (unsigned long)(addr - inf.dli_saddr)); } +#ifndef USE_ELF + + rval = symDump(buf, buf_sz, addr, inf.dli_fname, 0, NO_OFF); + +#else + /* No symbol info; try to access ELF file and ready symbol table from there */ - elfsLock(); + elfsLockRead(); /* See if we have loaded this file already */ - for ( es=elfs; es && strcmp(inf.dli_fname, es->fname); es = es->next ) - /* nothing else to do */; + es = elfSymsFind(inf.dli_fname); if ( !es ) { - if ( ! (es = elfRead(inf.dli_fname, (uintptr_t)inf.dli_fbase)) ) { - elfsUnlock(); - /* this path can only be taken if there is no memory for '*es' */ - return; - } - es->next = elfs; - elfs = es; - } + elfsUnlockRead(); - elfsUnlock(); + if ( ! (nes = elfRead(inf.dli_fname, (uintptr_t)inf.dli_fbase)) ) { + /* this path can only be taken if there is no memory for '*nes' */ + if ( buf && buf_sz > 0 ) + *buf = 0; + return 0; + } + + elfsLockWrite(); + + /* Has someone else intervened and already added this file while we were reading ? */ + es = elfSymsFind(inf.dli_fname); + + if ( es ) { + /* undo our work in the unlikely event... */ + elfSymsDestroy( nes ); + } else { + nes->next = elfs; + es = elfs = nes; + } + elfsLockConvertWriteRead(); + } nearest.raw = 0; minoff = (uintptr_t)-1LL; @@ -575,77 +628,215 @@ size_t idx; } 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); + rval = symDump(buf, buf_sz, addr, es->fname, strtab + idx, (unsigned long)minoff); } else { - errlogPrintf("%s[%p]\n", es->fname, addr); + rval = symDump(buf, buf_sz, addr, es->fname, 0, NO_OFF); } + + elfsUnlockRead(); + +#endif /* USE_ELF */ + + return rval; +} + +#endif /* USE_DLADDR */ + +static epicsThreadOnceId stackTraceInitId = EPICS_THREAD_ONCE_INIT; +static epicsMutexId stackTraceMtx; + +static void stackTraceInit(void *unused) +{ + stackTraceMtx = epicsMutexMustCreate(); +} + +static void stackTraceLock(void) +{ + epicsThreadOnce( &stackTraceInitId, stackTraceInit, 0 ); + epicsMutexLock( stackTraceMtx ); +} + +static void stackTraceUnlock(void) +{ + epicsMutexUnlock( stackTraceMtx ); +} + +static ssize_t +dump(char **buf, size_t *buf_sz, size_t *good, const char *fmt, ...) +{ +va_list ap; +ssize_t rval, put; + va_start(ap, fmt); + if ( *buf ) { + put = rval = vsnprintf(*buf, *buf_sz, fmt, ap); + if ( put > *buf_sz ) + put = *buf_sz; + *buf += put; + *buf_sz -= put; + } else { + rval = errlogVprintf(fmt, ap); + } + va_end(ap); + if ( rval > 0 ) + *good += rval; + return rval; +} + + +static ssize_t +symDump(char *buf, size_t buf_sz, void *addr, const char *fnam, const char *snam, unsigned long off) +{ +size_t rval = 0; + + dump( &buf, &buf_sz, &rval, "[%*p]", sizeof(addr)*2 + 2, addr); + if ( fnam ) { + dump( &buf, &buf_sz, &rval, ": %s", fnam ); + } + if ( snam ) { + dump( &buf, &buf_sz, &rval, "(%s", snam ); + if ( NO_OFF != off ) { + dump( &buf, &buf_sz, &rval, "+0x%lx", off); + } + dump( &buf, &buf_sz, &rval, ")" ); + } + dump( &buf, &buf_sz, &rval, "\n"); + + return rval; } -#endif epicsShareFunc void epicsStackTrace(void) { void **buf; -#ifndef USE_ELF +#ifndef USE_DLADDR char **bts; +ssize_t pos, siz; +char *ptr; #endif +char *btsl = 0; +size_t btsl_sz = sizeof(*btsl)*MAXSYMLEN; int i,n; - errlogPrintf("Dumping a stack trace:\n"); - - errlogFlush(); - - if ( ! (buf = malloc(sizeof(*buf) * MAXDEPTH)) ) { + if ( ! (buf = malloc(sizeof(*buf) * MAXDEPTH)) + || ! (btsl = malloc(btsl_sz)) + ) { + free(buf); errlogPrintf("epicsStackTrace(): not enough memory for backtrace\n"); return; } n = backtrace(buf, MAXDEPTH); + stackTraceLock(); + + errlogPrintf("Dumping a stack trace of thread '%s':\n", epicsThreadGetNameSelf()); + + errlogFlush(); + /* backtrace_symbols() only works for global symbols on linux. * If we have dladdr() and then we can actually lookup local * symbols, too. */ -#ifdef USE_ELF +#ifdef USE_DLADDR for ( i=0; i 0 ) + btsl[--pos] = 0; + siz -= pos; + if ( siz >= 3 ) { + strcat(btsl, ": "); + pos += 2; + siz -= 2; + } + strncat(btsl + pos, bts[i], siz); + /* wipe out the trailing address */ + if ( (ptr = strrchr(btsl, '[')) ) + *ptr = 0; + errlogPrintf("%s\n", btsl); } free(bts); } else { /* failed to create symbolic information; just print addresses */ for ( i=0; i Date: Fri, 5 Sep 2014 11:17:17 -0700 Subject: [PATCH 18/41] - call first epicsStackTraceRecurseGbl() through function pointer -- clang (darwin) had optimized it away. --- src/libCom/test/epicsStackTraceTest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/test/epicsStackTraceTest.c b/src/libCom/test/epicsStackTraceTest.c index ab33d31aa..9bc893c0f 100644 --- a/src/libCom/test/epicsStackTraceTest.c +++ b/src/libCom/test/epicsStackTraceTest.c @@ -185,7 +185,7 @@ char *nl, *p; eltc(0); errlogAddListener( logClient, &testData ); - epicsStackTraceRecurseGbl(3); + gfp(3); errlogRemoveListeners( logClient, &testData ); eltc(1); From 9dd130afb6085e90cb3933a112e04a1867183421 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Fri, 5 Sep 2014 15:29:32 -0700 Subject: [PATCH 19/41] - forget about backtrace_symbols() -- always use 'dladdr'. (The former is non-standard either and AFAIK always based on the latter.) Always using dladdr allows us to precisely control the printout formatting and keep it consistent. --- src/libCom/osi/execinfoStackTrace.c | 83 +++++------------------------ 1 file changed, 12 insertions(+), 71 deletions(-) diff --git a/src/libCom/osi/execinfoStackTrace.c b/src/libCom/osi/execinfoStackTrace.c index 0c8145465..c46e2925a 100644 --- a/src/libCom/osi/execinfoStackTrace.c +++ b/src/libCom/osi/execinfoStackTrace.c @@ -7,7 +7,11 @@ * Author: Till Straumann , 2011, 2014 */ +/* Make sure dladdr() is visible on linux/freebsd/darwin */ #define _GNU_SOURCE +/* Some freebsd versions seem to export dladdr() only if __BSD_VISIBLE */ +#define _BSD_VISIBLE +#define _DARWIN_C_SOURCE #include "epicsStackTrace.h" #include "epicsThread.h" @@ -19,28 +23,22 @@ #include #include +/* How many stack frames to capture */ #define MAXDEPTH 100 +/* How many chars to reserve for a line of output */ +#define MAXSYMLEN 500 + #define STACKTRACE_DEBUG 0 -/* Darwin and GNU have dladdr() but Darwin's backtrace_symbols() - * already prints local symbols, too, whereas linux' does not. +/* Darwin and GNU have dladdr() and Darwin's already finds local + * symbols, too, whereas linux' does not. * Hence, on linux we want to use dladdr() and lookup static * symbols in the ELF symbol table. */ -#ifdef freebsd -/* Some freebsd versions seem to export dladdr() only if __BSD_VISIBLE */ -#define __BSD_VISIBLE 1 -#endif - #include -/* Check if we actually have the gnu/darwin extensions */ -#ifdef RTLD_DEFAULT - -#define USE_DLADDR - #if defined(__linux__) || defined(linux) #define USE_ELF #define USE_MMAP @@ -54,19 +52,12 @@ #include #include -/* How many chars to reserve (on avg) for a line of output */ -#define MAXSYMLEN 500 - #ifdef USE_MMAP #include #endif /* USE_MMAP */ #endif /* USE_ELF */ -#else /* RTLD_DEFAULT */ -#undef USE_ELF -#endif /* RTLD_DEFAULT */ - /* Forward Declaration */ #define NO_OFF ((unsigned long)-1L) @@ -505,8 +496,6 @@ ESyms es; } #endif /* USE_ELF */ -#ifdef USE_DLADDR - static ssize_t elfLookupAddr(void *addr, char *buf, size_t buf_sz) { @@ -640,8 +629,6 @@ size_t idx; return rval; } -#endif /* USE_DLADDR */ - static epicsThreadOnceId stackTraceInitId = EPICS_THREAD_ONCE_INIT; static epicsMutexId stackTraceMtx; @@ -706,12 +693,7 @@ size_t rval = 0; epicsShareFunc void epicsStackTrace(void) { -void **buf; -#ifndef USE_DLADDR -char **bts; -ssize_t pos, siz; -char *ptr; -#endif +void **buf; char *btsl = 0; size_t btsl_sz = sizeof(*btsl)*MAXSYMLEN; int i,n; @@ -732,11 +714,6 @@ int i,n; errlogFlush(); - /* backtrace_symbols() only works for global symbols on linux. - * If we have dladdr() and then we can actually lookup local - * symbols, too. - */ -#ifdef USE_DLADDR for ( i=0; i 0 ) - btsl[--pos] = 0; - siz -= pos; - if ( siz >= 3 ) { - strcat(btsl, ": "); - pos += 2; - siz -= 2; - } - strncat(btsl + pos, bts[i], siz); - /* wipe out the trailing address */ - if ( (ptr = strrchr(btsl, '[')) ) - *ptr = 0; - errlogPrintf("%s\n", btsl); - } - free(bts); - } else { - /* failed to create symbolic information; just print addresses */ - for ( i=0; i Date: Mon, 8 Sep 2014 08:10:16 -0700 Subject: [PATCH 20/41] - use unistd's _POSIX_MAPPED_FILES to determine if a system has mmap. --- src/libCom/osi/execinfoStackTrace.c | 52 +++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/src/libCom/osi/execinfoStackTrace.c b/src/libCom/osi/execinfoStackTrace.c index c46e2925a..129bf553a 100644 --- a/src/libCom/osi/execinfoStackTrace.c +++ b/src/libCom/osi/execinfoStackTrace.c @@ -29,7 +29,7 @@ #define MAXSYMLEN 500 -#define STACKTRACE_DEBUG 0 +#define STACKTRACE_DEBUG 2 /* Darwin and GNU have dladdr() and Darwin's already finds local * symbols, too, whereas linux' does not. @@ -41,10 +41,8 @@ #if defined(__linux__) || defined(linux) #define USE_ELF -#define USE_MMAP #elif defined(freebsd) #define USE_ELF -#define USE_MMAP #endif #ifdef USE_ELF @@ -52,9 +50,9 @@ #include #include -#ifdef USE_MMAP +#ifdef _POSIX_MAPPED_FILES #include -#endif /* USE_MMAP */ +#endif #endif /* USE_ELF */ @@ -120,6 +118,37 @@ typedef struct ESyms_ { uint8_t class; } *ESyms; +/* Elf file access -- can either be with mmap or by sequential read */ + +#ifdef _POSIX_MAPPED_FILES +static MMap +getscn_mmap(int fd, uint8_t c, Shdr *shdr_p); +#endif + +static MMap +getscn_read(int fd, uint8_t c, Shdr *shdr_p); + +static MMap (*getscn)(int fd, uint8_t c, Shdr *shdr_p) = +#ifdef _POSIX_MAPPED_FILES + getscn_mmap +#else + getscn_read +#endif + ; + +int +epicsElfConfigAccess(int use_mmap) +{ +#ifndef _POSIX_MAPPED_FILES + if ( use_mmap ) + return -1; /* not supported on this system */ + /* else no need to change default */ +#else + getscn = use_mmap ? getscn_mmap : getscn_read; +#endif + return 0; +} + /* LOCKING NOTE: if the ELF symbol facility is ever expanded to be truly used * in a multithreaded way then proper multiple-readers, single-writer locking * should be implemented: @@ -194,8 +223,7 @@ void *ptr=buf; return ptr-buf; } -#ifdef USE_MMAP - +#ifdef _POSIX_MAPPED_FILES /* Destructor for data that is mmap()ed */ static void freeMapMmap(MMap m) @@ -206,7 +234,7 @@ freeMapMmap(MMap m) /* Obtain section data with mmap() */ static MMap -getscn(int fd, uint8_t c, Shdr *shdr_p) +getscn_mmap(int fd, uint8_t c, Shdr *shdr_p) { size_t n; MMap rval = 0; @@ -239,8 +267,7 @@ bail: freeMap(rval); return 0; } - -#else /* USE_MMAP */ +#endif /* Destructor for data that is read into a malloc()ed buffer */ static void @@ -251,7 +278,7 @@ freeMapMalloc(MMap m) /* Read section data into a malloc()ed buffer */ static MMap -getscn(int fd, uint8_t c, Shdr *shdr_p) +getscn_read(int fd, uint8_t c, Shdr *shdr_p) { size_t n; MMap rval = 0; @@ -294,7 +321,6 @@ bail: freeMap(rval); return 0; } -#endif /* USE_MMAP */ /* Release resources but keep filename so that * a file w/o symbol table is not read over and over again. @@ -748,7 +774,7 @@ epicsShareFunc int epicsStackTraceGetFeatures(void) errlogPrintf("no"); #endif errlogPrintf(", MMAP: "); -#ifdef USE_MMAP +#ifdef _POSIX_MAPPED_FILES errlogPrintf("yes"); #else errlogPrintf("no"); From e349b3ab94067160792fa08ff5ad0a1e04cf9c75 Mon Sep 17 00:00:00 2001 From: strauman Date: Mon, 8 Sep 2014 19:41:06 -0700 Subject: [PATCH 21/41] - first stab at breaking stack trace facility into separate files --- src/libCom/osi/Makefile | 9 +- src/libCom/osi/epicsStackTrace.c | 137 ++++++++ src/libCom/osi/epicsStackTracePvt.h | 61 ++++ src/libCom/osi/os/Darwin/osdFindAddr.c | 45 +++ src/libCom/osi/os/Darwin/osdStackTrace.c | 20 -- src/libCom/osi/os/Linux/osdStackTrace.c | 20 -- src/libCom/osi/os/default/osdBackTrace.c | 15 + .../{osdStackTrace.c => osdFindAddr.c} | 6 +- src/libCom/osi/os/posix/osdBackTrace.c | 17 + .../posix/osdFindAddr.c} | 317 +++++------------- 10 files changed, 361 insertions(+), 286 deletions(-) create mode 100644 src/libCom/osi/epicsStackTrace.c create mode 100644 src/libCom/osi/epicsStackTracePvt.h create mode 100644 src/libCom/osi/os/Darwin/osdFindAddr.c delete mode 100644 src/libCom/osi/os/Darwin/osdStackTrace.c delete mode 100644 src/libCom/osi/os/Linux/osdStackTrace.c create mode 100644 src/libCom/osi/os/default/osdBackTrace.c rename src/libCom/osi/os/default/{osdStackTrace.c => osdFindAddr.c} (77%) create mode 100644 src/libCom/osi/os/posix/osdBackTrace.c rename src/libCom/osi/{execinfoStackTrace.c => os/posix/osdFindAddr.c} (76%) diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index 38fdf71c0..781497a1a 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -143,9 +143,6 @@ Com_SRCS_WIN32 += setThreadName.cpp Com_SRCS_WIN32 += forceBadAllocException.cpp #Stack trace support -Com_SRCS += osdStackTrace.c -Com_SRCS_Linux += execinfoStackTrace.c -Com_SRCS_Darwin += execinfoStackTrace.c -#we could use execinfoStackTrace.c on freebsd, too, but AFAIK -#you need libexecinfo.a and execinfo.h. I don't know if that -#is routinely available so we don't use it for now. +Com_SRCS += epicsStackTrace.c +Com_SRCS += osdBackTrace.c +Com_SRCS += osdFindAddr.c diff --git a/src/libCom/osi/epicsStackTrace.c b/src/libCom/osi/epicsStackTrace.c new file mode 100644 index 000000000..b0e02fa8a --- /dev/null +++ b/src/libCom/osi/epicsStackTrace.c @@ -0,0 +1,137 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011, 2014 + */ + +#include +#include + +#include "epicsStackTrace.h" +#include "epicsStackTracePvt.h" +#include "epicsThread.h" +#include "epicsMutex.h" +#include "errlog.h" + +/* How many stack frames to capture */ +#define MAXDEPTH 100 + +/* Max. formatted line length */ +#define MAXLINEL 300 + +#define NO_OFF ((unsigned long)-1L) + +static ssize_t +symDump(char *buf, size_t buf_sz, void *addr, epicsSymbol *sym_p); + +static epicsThreadOnceId stackTraceInitId = EPICS_THREAD_ONCE_INIT; +static epicsMutexId stackTraceMtx; + +static void stackTraceInit(void *unused) +{ + stackTraceMtx = epicsMutexMustCreate(); +} + +static void stackTraceLock(void) +{ + epicsThreadOnce( &stackTraceInitId, stackTraceInit, 0 ); + epicsMutexLock( stackTraceMtx ); +} + +static void stackTraceUnlock(void) +{ + epicsMutexUnlock( stackTraceMtx ); +} + +static ssize_t +dump(char **buf, size_t *buf_sz, size_t *good, const char *fmt, ...) +{ +va_list ap; +ssize_t rval, put; + va_start(ap, fmt); + if ( *buf ) { + put = rval = vsnprintf(*buf, *buf_sz, fmt, ap); + if ( put > *buf_sz ) + put = *buf_sz; + *buf += put; + *buf_sz -= put; + } else { + rval = errlogVprintf(fmt, ap); + } + va_end(ap); + if ( rval > 0 ) + *good += rval; + return rval; +} + +static ssize_t +symDump(char *buf, size_t buf_sz, void *addr, epicsSymbol *sym_p) +{ +size_t rval = 0; + + dump( &buf, &buf_sz, &rval, "[%*p]", sizeof(addr)*2 + 2, addr); + if ( sym_p ) { + if ( sym_p->f_nam ) { + dump( &buf, &buf_sz, &rval, ": %s", sym_p->f_nam ); + } + if ( sym_p->s_nam ) { + dump( &buf, &buf_sz, &rval, "(%s+0x%lx)", sym_p->s_nam, (unsigned long)(addr - sym_p->s_val)); + } + } + dump( &buf, &buf_sz, &rval, "\n"); + if ( ! buf ) + errlogFlush(); + + return rval; +} + +epicsShareFunc void epicsStackTrace(void) +{ +void **buf; +char *btsl = 0; +size_t btsl_sz = sizeof(*btsl)*MAXLINEL; +int i,n; +epicsSymbol sym; + + if ( 0 == epicsStackTraceGetFeatures() ) { + /* unsupported on this platform */ + return; + } + + if ( ! (buf = malloc(sizeof(*buf) * MAXDEPTH)) + || ! (btsl = malloc(btsl_sz)) + ) { + free(buf); + errlogPrintf("epicsStackTrace(): not enough memory for backtrace\n"); + return; + } + + n = epicsBackTrace(buf, MAXDEPTH); + + if ( n > 0 ) { + + stackTraceLock(); + + errlogPrintf("Dumping a stack trace of thread '%s':\n", epicsThreadGetNameSelf()); + + errlogFlush(); + + for ( i=0; i, 2011, 2014 + */ + +#ifndef INC_epicsStackTracePvt_H +#define INC_epicsStackTracePvt_H + +#include "shareLib.h" + +typedef struct epicsSymbol { + const char *f_nam; /* file where the symbol is defined */ + const char *s_nam; /* symbol name */ + void *s_val; /* symbol value */ +} epicsSymbol; + +#ifdef __cplusplus +extern "C" { +#endif + +/* Take a snapshot of the stack into 'buf' (limited to buf_sz entries) + * RETURNS: actual number of entries in 'buf' + */ +epicsShareFunc int epicsBackTrace(void **buf, int buf_sz); + +/* Find symbol closest to 'addr'. + * + * If successful the routine fills in the members of *sym_p but + * note that 'f_nam' and/or 's_nam' may be NULL if the address + * cannot be resolved. + * + * RETURNS: 0 on success, nonzero on failure (not finding an address + * is not considered an error). + * + * NOTE: epicsSymbolTableLock() must be held while the string + * pointers returned by epicsFindAddr are in use. + * + * I.e., + * + * epicsSymTblLock(); + * + * epicsFindAddr( addr, &sym ); + * + * do_something( &sym ); + * + * epicsSymTblUnlock(); + * + * epicsSymTblLock() may be implemented by the OSD code such that + * multiple readers may hold the lock. + */ +epicsShareFunc int epicsFindAddr(void *addr, epicsSymbol *sym_p); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libCom/osi/os/Darwin/osdFindAddr.c b/src/libCom/osi/os/Darwin/osdFindAddr.c new file mode 100644 index 000000000..306279d2e --- /dev/null +++ b/src/libCom/osi/os/Darwin/osdFindAddr.c @@ -0,0 +1,45 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011, 2014 + */ + +/* Make sure dladdr() is visible */ +#define _DARWIN_C_SOURCE + +#include + +#include "epicsStackTrace.h" +#include "epicsStackTracePvt.h" + + +/* Darwin's finds local symbols, too :-) */ + +epicsShareFunc int epicsFindAddr(void *addr, epicsSymbol *sym_p) +{ +Dl_info inf; + + if ( ! dladdr(addr, &inf) || (!inf.dli_fname && !inf.dli_sname) ) { + sym_p->f_nam = 0; + sym_p->s_nam = 0; + /* unable to lookup */ + return 0; + } + + sym_p->f_nam = inf.dli_fname; + sym_p->s_nam = inf.dli_sname; + sym_p->s_val = inf.dli_saddr; + + return 0; +} + +epicsShareFunc int epicsStackTraceGetFeatures(void) +{ + return EPICS_STACKTRACE_LCL_SYMBOLS + | EPICS_STACKTRACE_GBL_SYMBOLS + | EPICS_STACKTRACE_DYN_SYMBOLS + | EPICS_STACKTRACE_ADDRESSES; +} diff --git a/src/libCom/osi/os/Darwin/osdStackTrace.c b/src/libCom/osi/os/Darwin/osdStackTrace.c deleted file mode 100644 index 3f25a0591..000000000 --- a/src/libCom/osi/os/Darwin/osdStackTrace.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright: Stanford University / SLAC National Laboratory. - * - * EPICS BASE is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - * - * Author: Till Straumann , 2011 - */ - -/* THIS FILE IS INTENTIONALLY EMPTY - * - * The presence of this file prevents the build - * system from using the no-op implementation of - * epicsStackTrace() in default/osdStackTrace.c. - * - * This OS uses a generic implementation which - * may be used by various OSes. The source file - * of this implementation is listed in the - * Makefile. - */ diff --git a/src/libCom/osi/os/Linux/osdStackTrace.c b/src/libCom/osi/os/Linux/osdStackTrace.c deleted file mode 100644 index 3f25a0591..000000000 --- a/src/libCom/osi/os/Linux/osdStackTrace.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright: Stanford University / SLAC National Laboratory. - * - * EPICS BASE is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - * - * Author: Till Straumann , 2011 - */ - -/* THIS FILE IS INTENTIONALLY EMPTY - * - * The presence of this file prevents the build - * system from using the no-op implementation of - * epicsStackTrace() in default/osdStackTrace.c. - * - * This OS uses a generic implementation which - * may be used by various OSes. The source file - * of this implementation is listed in the - * Makefile. - */ diff --git a/src/libCom/osi/os/default/osdBackTrace.c b/src/libCom/osi/os/default/osdBackTrace.c new file mode 100644 index 000000000..c8bccd61f --- /dev/null +++ b/src/libCom/osi/os/default/osdBackTrace.c @@ -0,0 +1,15 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + +#include "epicsStackTracePvt.h" + +epicsShareFunc int epicsBackTrace(void **buf, int buf_sz) +{ + return -1; +} diff --git a/src/libCom/osi/os/default/osdStackTrace.c b/src/libCom/osi/os/default/osdFindAddr.c similarity index 77% rename from src/libCom/osi/os/default/osdStackTrace.c rename to src/libCom/osi/os/default/osdFindAddr.c index d56711267..d3d69cdec 100644 --- a/src/libCom/osi/os/default/osdStackTrace.c +++ b/src/libCom/osi/os/default/osdFindAddr.c @@ -7,15 +7,15 @@ * Author: Till Straumann , 2011 */ +#include "epicsStackTracePvt.h" #include "epicsStackTrace.h" -#include "errlog.h" -epicsShareFunc void epicsStackTrace(void) +epicsShareFunc int epicsFindAddr(void *addr, epicsSymbol *sym_p) { + return -1; } epicsShareFunc int epicsStackTraceGetFeatures(void) { return 0; } - diff --git a/src/libCom/osi/os/posix/osdBackTrace.c b/src/libCom/osi/os/posix/osdBackTrace.c new file mode 100644 index 000000000..806082a73 --- /dev/null +++ b/src/libCom/osi/os/posix/osdBackTrace.c @@ -0,0 +1,17 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + +#include + +#include "epicsStackTracePvt.h" + +epicsShareFunc int epicsBackTrace(void **buf, int buf_sz) +{ + return backtrace(buf, buf_sz); +} diff --git a/src/libCom/osi/execinfoStackTrace.c b/src/libCom/osi/os/posix/osdFindAddr.c similarity index 76% rename from src/libCom/osi/execinfoStackTrace.c rename to src/libCom/osi/os/posix/osdFindAddr.c index 129bf553a..7395b5c37 100644 --- a/src/libCom/osi/execinfoStackTrace.c +++ b/src/libCom/osi/os/posix/osdFindAddr.c @@ -7,45 +7,16 @@ * Author: Till Straumann , 2011, 2014 */ -/* Make sure dladdr() is visible on linux/freebsd/darwin */ +/* Make sure dladdr() is visible on linux/solaris */ #define _GNU_SOURCE -/* Some freebsd versions seem to export dladdr() only if __BSD_VISIBLE */ -#define _BSD_VISIBLE -#define _DARWIN_C_SOURCE +/* For dladdr under solaris */ +#define __EXTENSIONS__ -#include "epicsStackTrace.h" -#include "epicsThread.h" -#include "epicsMutex.h" -#include -#include +#include +#include #include #include #include -#include - -/* How many stack frames to capture */ -#define MAXDEPTH 100 -/* How many chars to reserve for a line of output */ -#define MAXSYMLEN 500 - - -#define STACKTRACE_DEBUG 2 - -/* Darwin and GNU have dladdr() and Darwin's already finds local - * symbols, too, whereas linux' does not. - * Hence, on linux we want to use dladdr() and lookup static - * symbols in the ELF symbol table. - */ - -#include - -#if defined(__linux__) || defined(linux) -#define USE_ELF -#elif defined(freebsd) -#define USE_ELF -#endif - -#ifdef USE_ELF #include #include #include @@ -54,15 +25,20 @@ #include #endif -#endif /* USE_ELF */ +#include "epicsStackTrace.h" +#include "epicsStackTracePvt.h" -/* Forward Declaration */ -#define NO_OFF ((unsigned long)-1L) +#include "epicsThread.h" +#include "epicsMutex.h" +#include -static ssize_t -symDump(char *buf, size_t buf_sz, void *addr, const char *fnam, const char *snam, unsigned long off); +#define FIND_ADDR_DEBUG 0 -#ifdef USE_ELF +/* Darwin and GNU have dladdr() and Darwin's already finds local + * symbols, too, whereas linux' does not. + * Hence, on linux we want to use dladdr() and lookup static + * symbols in the ELF symbol table. + */ /* Macros to handle elf32 vs. elf64 access to unions etc. */ @@ -118,37 +94,6 @@ typedef struct ESyms_ { uint8_t class; } *ESyms; -/* Elf file access -- can either be with mmap or by sequential read */ - -#ifdef _POSIX_MAPPED_FILES -static MMap -getscn_mmap(int fd, uint8_t c, Shdr *shdr_p); -#endif - -static MMap -getscn_read(int fd, uint8_t c, Shdr *shdr_p); - -static MMap (*getscn)(int fd, uint8_t c, Shdr *shdr_p) = -#ifdef _POSIX_MAPPED_FILES - getscn_mmap -#else - getscn_read -#endif - ; - -int -epicsElfConfigAccess(int use_mmap) -{ -#ifndef _POSIX_MAPPED_FILES - if ( use_mmap ) - return -1; /* not supported on this system */ - /* else no need to change default */ -#else - getscn = use_mmap ? getscn_mmap : getscn_read; -#endif - return 0; -} - /* LOCKING NOTE: if the ELF symbol facility is ever expanded to be truly used * in a multithreaded way then proper multiple-readers, single-writer locking * should be implemented: @@ -214,7 +159,7 @@ do_read(int fd, void *buf, size_t sz) size_t got; void *ptr=buf; while ( sz > 0 ) { - if ( (got=read(fd,ptr,sz)) < 0 ) { + if ( (got=read(fd,ptr,sz)) <= 0 ) { return got; } ptr+=got; @@ -223,6 +168,8 @@ void *ptr=buf; return ptr-buf; } +/* Elf file access -- can either be with mmap or by sequential read */ + #ifdef _POSIX_MAPPED_FILES /* Destructor for data that is mmap()ed */ static void @@ -322,6 +269,27 @@ bail: return 0; } +static MMap (*getscn)(int fd, uint8_t c, Shdr *shdr_p) = +#ifdef _POSIX_MAPPED_FILES + getscn_mmap +#else + getscn_read +#endif + ; + +int +epicsElfConfigAccess(int use_mmap) +{ +#ifndef _POSIX_MAPPED_FILES + if ( use_mmap ) + return -1; /* not supported on this system */ + /* else no need to change default */ +#else + getscn = use_mmap ? getscn_mmap : getscn_read; +#endif + return 0; +} + /* Release resources but keep filename so that * a file w/o symbol table is not read over and over again. */ @@ -420,6 +388,24 @@ const char *cp; break; } + if ( i>=FLD(c,ehdr,e_shnum) ) { + /* no SYMTAB -- try dynamic symbols */ + + if ( (off_t)-1 == lseek(es->fd, FLD(c,ehdr,e_shoff), SEEK_SET) ) { + errlogPrintf("elfRead() -- unable to seek to shoff: %s\n", strerror(errno)); + goto bail; + } + + for ( i = 0; ifd, &shdr, n) ) { + errlogPrintf("elfRead() -- unable to read section header: %s\n", strerror(errno)); + goto bail; + } + if ( SHT_DYNSYM == FLD(c,shdr,sh_type) ) + break; + } + } + if ( i>=FLD(c,ehdr,e_shnum) ) { errlogPrintf("elfRead() -- no symbol table found\n"); goto bail; @@ -475,7 +461,7 @@ const char *cp; es->addr = fbase; break; default: - errlogPrintf("elfLookupAddr(): Unexpected ELF object file type %u\n", FLD(c,ehdr,e_type)); + errlogPrintf("dlLookupAddr(): Unexpected ELF object file type %u\n", FLD(c,ehdr,e_type)); goto bail; } @@ -497,8 +483,8 @@ elfSymsDestroy(ESyms es) } /* Destroy all cached ELF symbol tables */ -static void -elfSymsFlush() +void +epicsSymTblFlush() { ESyms es; @@ -520,15 +506,11 @@ ESyms es; /* nothing else to do */; return es; } -#endif /* USE_ELF */ -static ssize_t -elfLookupAddr(void *addr, char *buf, size_t buf_sz) +int +epicsFindAddr(void *addr, epicsSymbol *sym_p) { Dl_info inf; -ssize_t rval; - -#ifdef USE_ELF ESyms es,nes; uintptr_t minoff,off; int i; @@ -537,23 +519,24 @@ Sym nearest; const char *strtab; uint8_t c; size_t idx; -#endif if ( ! dladdr(addr, &inf) || (!inf.dli_fname && !inf.dli_sname) ) { + sym_p->f_nam = 0; + sym_p->s_nam = 0; /* unable to lookup */ - return symDump(buf, buf_sz, addr, 0, 0, NO_OFF); + return 0; } - if ( inf.dli_sname ) { + sym_p->f_nam = inf.dli_fname; + + /* If the symbol is in the main executable then solaris' dladdr returns bogus info */ +#ifndef __sun + if ( (sym_p->s_nam = inf.dli_sname) ) { + sym_p->s_val = inf.dli_saddr; /* Have a symbol name - just use it and be done */ - return symDump(buf, buf_sz, addr, inf.dli_fname, inf.dli_sname, (unsigned long)(addr - inf.dli_saddr)); + return 0; } - -#ifndef USE_ELF - - rval = symDump(buf, buf_sz, addr, inf.dli_fname, 0, NO_OFF); - -#else +#endif /* No symbol info; try to access ELF file and ready symbol table from there */ @@ -567,8 +550,6 @@ size_t idx; if ( ! (nes = elfRead(inf.dli_fname, (uintptr_t)inf.dli_fbase)) ) { /* this path can only be taken if there is no memory for '*nes' */ - if ( buf && buf_sz > 0 ) - *buf = 0; return 0; } @@ -599,7 +580,7 @@ size_t idx; * very often then it would be worthwhile constructing a sorted list of * symbol addresses but for the stack trace we don't care... */ -#if (STACKTRACE_DEBUG & 1) +#if (FIND_ADDR_DEBUG & 1) printf("Looking for %p\n", addr); #endif @@ -610,7 +591,7 @@ size_t idx; /* don't bother about undefined symbols */ if ( 0 == sym.e32[i].st_shndx ) continue; -#if (STACKTRACE_DEBUG & 1) +#if (FIND_ADDR_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 ) { @@ -628,7 +609,7 @@ size_t idx; /* don't bother about undefined symbols */ if ( 0 == sym.e64[i].st_shndx ) continue; -#if (STACKTRACE_DEBUG & 1) +#if (FIND_ADDR_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 ) { @@ -643,145 +624,17 @@ size_t idx; } if ( nearest.raw && ( (idx = ARR(c,nearest,0,st_name)) < es->strMap->max ) ) { - rval = symDump(buf, buf_sz, addr, es->fname, strtab + idx, (unsigned long)minoff); - } else { - rval = symDump(buf, buf_sz, addr, es->fname, 0, NO_OFF); + sym_p->s_nam = strtab + idx; + sym_p->s_val = (void*) ARR(c, nearest, 0, st_value) + es->addr; } elfsUnlockRead(); -#endif /* USE_ELF */ - - return rval; + return 0; } -static epicsThreadOnceId stackTraceInitId = EPICS_THREAD_ONCE_INIT; -static epicsMutexId stackTraceMtx; - -static void stackTraceInit(void *unused) -{ - stackTraceMtx = epicsMutexMustCreate(); -} - -static void stackTraceLock(void) -{ - epicsThreadOnce( &stackTraceInitId, stackTraceInit, 0 ); - epicsMutexLock( stackTraceMtx ); -} - -static void stackTraceUnlock(void) -{ - epicsMutexUnlock( stackTraceMtx ); -} - -static ssize_t -dump(char **buf, size_t *buf_sz, size_t *good, const char *fmt, ...) -{ -va_list ap; -ssize_t rval, put; - va_start(ap, fmt); - if ( *buf ) { - put = rval = vsnprintf(*buf, *buf_sz, fmt, ap); - if ( put > *buf_sz ) - put = *buf_sz; - *buf += put; - *buf_sz -= put; - } else { - rval = errlogVprintf(fmt, ap); - } - va_end(ap); - if ( rval > 0 ) - *good += rval; - return rval; -} - - -static ssize_t -symDump(char *buf, size_t buf_sz, void *addr, const char *fnam, const char *snam, unsigned long off) -{ -size_t rval = 0; - - dump( &buf, &buf_sz, &rval, "[%*p]", sizeof(addr)*2 + 2, addr); - if ( fnam ) { - dump( &buf, &buf_sz, &rval, ": %s", fnam ); - } - if ( snam ) { - dump( &buf, &buf_sz, &rval, "(%s", snam ); - if ( NO_OFF != off ) { - dump( &buf, &buf_sz, &rval, "+0x%lx", off); - } - dump( &buf, &buf_sz, &rval, ")" ); - } - dump( &buf, &buf_sz, &rval, "\n"); - - return rval; -} - -epicsShareFunc void epicsStackTrace(void) -{ -void **buf; -char *btsl = 0; -size_t btsl_sz = sizeof(*btsl)*MAXSYMLEN; -int i,n; - - if ( ! (buf = malloc(sizeof(*buf) * MAXDEPTH)) - || ! (btsl = malloc(btsl_sz)) - ) { - free(buf); - errlogPrintf("epicsStackTrace(): not enough memory for backtrace\n"); - return; - } - - n = backtrace(buf, MAXDEPTH); - - stackTraceLock(); - - errlogPrintf("Dumping a stack trace of thread '%s':\n", epicsThreadGetNameSelf()); - - errlogFlush(); - - for ( i=0; i Date: Mon, 8 Sep 2014 22:28:41 -0700 Subject: [PATCH 22/41] - (hopefully) correct usage of sharedLib.h... --- src/libCom/osi/os/Darwin/osdFindAddr.c | 4 ++-- src/libCom/osi/os/default/osdBackTrace.c | 3 ++- src/libCom/osi/os/default/osdFindAddr.c | 5 +++-- src/libCom/osi/os/posix/osdBackTrace.c | 3 ++- src/libCom/osi/os/posix/osdFindAddr.c | 8 +++++--- 5 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/libCom/osi/os/Darwin/osdFindAddr.c b/src/libCom/osi/os/Darwin/osdFindAddr.c index 306279d2e..d2f5a4465 100644 --- a/src/libCom/osi/os/Darwin/osdFindAddr.c +++ b/src/libCom/osi/os/Darwin/osdFindAddr.c @@ -12,13 +12,13 @@ #include +#define epicsExportSharedSymbols #include "epicsStackTrace.h" #include "epicsStackTracePvt.h" - /* Darwin's finds local symbols, too :-) */ -epicsShareFunc int epicsFindAddr(void *addr, epicsSymbol *sym_p) +int epicsFindAddr(void *addr, epicsSymbol *sym_p) { Dl_info inf; diff --git a/src/libCom/osi/os/default/osdBackTrace.c b/src/libCom/osi/os/default/osdBackTrace.c index c8bccd61f..c77572351 100644 --- a/src/libCom/osi/os/default/osdBackTrace.c +++ b/src/libCom/osi/os/default/osdBackTrace.c @@ -7,9 +7,10 @@ * Author: Till Straumann , 2011 */ +#define epicsExportSharedSymbols #include "epicsStackTracePvt.h" -epicsShareFunc int epicsBackTrace(void **buf, int buf_sz) +int epicsBackTrace(void **buf, int buf_sz) { return -1; } diff --git a/src/libCom/osi/os/default/osdFindAddr.c b/src/libCom/osi/os/default/osdFindAddr.c index d3d69cdec..4cda3977d 100644 --- a/src/libCom/osi/os/default/osdFindAddr.c +++ b/src/libCom/osi/os/default/osdFindAddr.c @@ -7,15 +7,16 @@ * Author: Till Straumann , 2011 */ +#define epicsExportSharedSymbols #include "epicsStackTracePvt.h" #include "epicsStackTrace.h" -epicsShareFunc int epicsFindAddr(void *addr, epicsSymbol *sym_p) +int epicsFindAddr(void *addr, epicsSymbol *sym_p) { return -1; } -epicsShareFunc int epicsStackTraceGetFeatures(void) +int epicsStackTraceGetFeatures(void) { return 0; } diff --git a/src/libCom/osi/os/posix/osdBackTrace.c b/src/libCom/osi/os/posix/osdBackTrace.c index 806082a73..41a15a585 100644 --- a/src/libCom/osi/os/posix/osdBackTrace.c +++ b/src/libCom/osi/os/posix/osdBackTrace.c @@ -9,9 +9,10 @@ #include +#define epicsExportSharedSymbols #include "epicsStackTracePvt.h" -epicsShareFunc int epicsBackTrace(void **buf, int buf_sz) +int epicsBackTrace(void **buf, int buf_sz) { return backtrace(buf, buf_sz); } diff --git a/src/libCom/osi/os/posix/osdFindAddr.c b/src/libCom/osi/os/posix/osdFindAddr.c index 7395b5c37..830603aef 100644 --- a/src/libCom/osi/os/posix/osdFindAddr.c +++ b/src/libCom/osi/os/posix/osdFindAddr.c @@ -25,13 +25,15 @@ #include #endif -#include "epicsStackTrace.h" -#include "epicsStackTracePvt.h" #include "epicsThread.h" #include "epicsMutex.h" #include +#define epicsExportSharedSymbols +#include "epicsStackTrace.h" +#include "epicsStackTracePvt.h" + #define FIND_ADDR_DEBUG 0 /* Darwin and GNU have dladdr() and Darwin's already finds local @@ -633,7 +635,7 @@ size_t idx; return 0; } -epicsShareFunc int epicsStackTraceGetFeatures(void) +int epicsStackTraceGetFeatures(void) { /* We are a bit conservative here. The actual * situation depends on how we are linked (something From 954ba6602782e7c9208a35b3aac27deaa93afe59 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Mon, 8 Sep 2014 22:29:46 -0700 Subject: [PATCH 23/41] - fixed illegal void* pointer arithmetic by casting to char* - removed more unused stuff --- src/libCom/osi/epicsStackTrace.c | 36 ++++++++++++-------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/src/libCom/osi/epicsStackTrace.c b/src/libCom/osi/epicsStackTrace.c index b0e02fa8a..5480d842a 100644 --- a/src/libCom/osi/epicsStackTrace.c +++ b/src/libCom/osi/epicsStackTrace.c @@ -10,23 +10,17 @@ #include #include -#include "epicsStackTrace.h" #include "epicsStackTracePvt.h" #include "epicsThread.h" #include "epicsMutex.h" #include "errlog.h" +#define epicsExportSharedSymbols +#include "epicsStackTrace.h" + /* How many stack frames to capture */ #define MAXDEPTH 100 -/* Max. formatted line length */ -#define MAXLINEL 300 - -#define NO_OFF ((unsigned long)-1L) - -static ssize_t -symDump(char *buf, size_t buf_sz, void *addr, epicsSymbol *sym_p); - static epicsThreadOnceId stackTraceInitId = EPICS_THREAD_ONCE_INIT; static epicsMutexId stackTraceMtx; @@ -46,11 +40,11 @@ static void stackTraceUnlock(void) epicsMutexUnlock( stackTraceMtx ); } -static ssize_t -dump(char **buf, size_t *buf_sz, size_t *good, const char *fmt, ...) +static int +dump(char **buf, int *buf_sz, int *good, const char *fmt, ...) { va_list ap; -ssize_t rval, put; +int rval, put; va_start(ap, fmt); if ( *buf ) { put = rval = vsnprintf(*buf, *buf_sz, fmt, ap); @@ -67,10 +61,10 @@ ssize_t rval, put; return rval; } -static ssize_t -symDump(char *buf, size_t buf_sz, void *addr, epicsSymbol *sym_p) +static int +symDump(char *buf, int buf_sz, void *addr, epicsSymbol *sym_p) { -size_t rval = 0; +int rval = 0; dump( &buf, &buf_sz, &rval, "[%*p]", sizeof(addr)*2 + 2, addr); if ( sym_p ) { @@ -78,7 +72,8 @@ size_t rval = 0; dump( &buf, &buf_sz, &rval, ": %s", sym_p->f_nam ); } if ( sym_p->s_nam ) { - dump( &buf, &buf_sz, &rval, "(%s+0x%lx)", sym_p->s_nam, (unsigned long)(addr - sym_p->s_val)); + /* windows didn't grok the void* pointer arithmetic */ + dump( &buf, &buf_sz, &rval, "(%s+0x%lx)", sym_p->s_nam, (unsigned long)((char*)addr - (char*)sym_p->s_val)); } } dump( &buf, &buf_sz, &rval, "\n"); @@ -88,11 +83,9 @@ size_t rval = 0; return rval; } -epicsShareFunc void epicsStackTrace(void) +void epicsStackTrace(void) { void **buf; -char *btsl = 0; -size_t btsl_sz = sizeof(*btsl)*MAXLINEL; int i,n; epicsSymbol sym; @@ -101,9 +94,7 @@ epicsSymbol sym; return; } - if ( ! (buf = malloc(sizeof(*buf) * MAXDEPTH)) - || ! (btsl = malloc(btsl_sz)) - ) { + if ( ! (buf = malloc(sizeof(*buf) * MAXDEPTH))) { free(buf); errlogPrintf("epicsStackTrace(): not enough memory for backtrace\n"); return; @@ -132,6 +123,5 @@ epicsSymbol sym; } - free(btsl); free(buf); } From 8931954d28cd73e672909438a3c8fc3e2b4fe8c2 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Mon, 8 Sep 2014 22:30:34 -0700 Subject: [PATCH 24/41] - fixed illegal void* pointer arithmetic (by casting to char*) --- src/libCom/test/epicsStackTraceTest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libCom/test/epicsStackTraceTest.c b/src/libCom/test/epicsStackTraceTest.c index 9bc893c0f..c42206b11 100644 --- a/src/libCom/test/epicsStackTraceTest.c +++ b/src/libCom/test/epicsStackTraceTest.c @@ -129,7 +129,7 @@ int n_ptrs = 0; int i,j; int rval = 0; - while ( n_ptrs < sizeof(ptrs)/sizeof(*ptrs[0]) && (buf=strchr(buf,'[')) ) { + while ( n_ptrs < sizeof(ptrs)/sizeof(ptrs[0]) && (buf=strchr(buf,'[')) ) { if ( 1 == sscanf(buf+1,"%p", &ptrs[n_ptrs]) ) n_ptrs++; buf++; @@ -142,7 +142,7 @@ int rval = 0; j = i; while ( j < n_ptrs ) { if ( j != i && ptrs[j] == ptrs[i] ) { - if ( ptrs[i] >= (void*)epicsStackTraceRecurseGbl && ptrs[i] < (void*)epicsStackTraceRecurseGbl + WINDOW_SZ ) { + if ( (char*)ptrs[i] >= (char*)epicsStackTraceRecurseGbl && (char*)ptrs[i] < (char*)epicsStackTraceRecurseGbl + WINDOW_SZ ) { rval ++; if ( test_debug ) testDiag("found address %p again\n", ptrs[i]); From 8477dec61fd9b1b24f22cc486509d4bc900455bf Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Mon, 8 Sep 2014 22:31:11 -0700 Subject: [PATCH 25/41] - added windows versions of osdBackTrace.c, osdFindAddr.c; the latter does not implement addr->symbol conversion yet. --- src/libCom/osi/os/WIN32/osdBackTrace.c | 24 ++++++++++++++++++++ src/libCom/osi/os/WIN32/osdFindAddr.c | 31 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 src/libCom/osi/os/WIN32/osdBackTrace.c create mode 100644 src/libCom/osi/os/WIN32/osdFindAddr.c diff --git a/src/libCom/osi/os/WIN32/osdBackTrace.c b/src/libCom/osi/os/WIN32/osdBackTrace.c new file mode 100644 index 000000000..4afd8a4f1 --- /dev/null +++ b/src/libCom/osi/os/WIN32/osdBackTrace.c @@ -0,0 +1,24 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + +#include +#include + +#define epicsExportSharedSymbols +#include "epicsStackTracePvt.h" + +int epicsBackTrace(void **buf, int buf_sz) +{ + /* Docs say that (for some windows versions) the sum of + * skipped + captured frames must be less than 63 + */ + if ( buf_sz >= 63 ) + buf_sz = 62; + return CaptureStackBackTrace(0, buf_sz, buf, 0); +} diff --git a/src/libCom/osi/os/WIN32/osdFindAddr.c b/src/libCom/osi/os/WIN32/osdFindAddr.c new file mode 100644 index 000000000..a39654188 --- /dev/null +++ b/src/libCom/osi/os/WIN32/osdFindAddr.c @@ -0,0 +1,31 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + +#define epicsExportSharedSymbols +#include "epicsStackTracePvt.h" +#include "epicsStackTrace.h" + +int epicsFindAddr(void *addr, epicsSymbol *sym_p) +{ + return -1; +} + +int epicsStackTraceGetFeatures(void) +{ +void *test[10]; + + /* If frame-pointer optimization is on then CaptureStackBackTrace + * does not work. Make sure all EPICS is built with -Oy- + */ + if ( 0 == epicsBackTrace(test, sizeof(test)/sizeof(test[0])) ) + return 0; + + /* address->symbol conversion not implemented (yet) */ + return EPICS_STACKTRACE_ADDRESSES; +} From 0b76aa2de18caa4ac7cb43914847590e85551413 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Mon, 8 Sep 2014 22:31:47 -0700 Subject: [PATCH 26/41] - turn off frame-pointer optimization (otherwise stack trace capture does not work). --- configure/os/CONFIG.win32-x86.win32-x86 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure/os/CONFIG.win32-x86.win32-x86 b/configure/os/CONFIG.win32-x86.win32-x86 index 02b5c0143..4424ac5a6 100644 --- a/configure/os/CONFIG.win32-x86.win32-x86 +++ b/configure/os/CONFIG.win32-x86.win32-x86 @@ -43,7 +43,7 @@ WARN_CFLAGS_NO = -W1 # -MD use MSVCRT (run-time as DLL, multi-thread support) # -GL whole program optimization # -Zi generate program database for debugging information -OPT_CFLAGS_YES = -Ox -GL +OPT_CFLAGS_YES = -Ox -GL -Oy- # # -Zi generate program database for debugging information @@ -107,7 +107,7 @@ WARN_CXXFLAGS_NO = -W1 # -Ox maximum optimizations # -GL whole program optimization # -Zi generate program database for debugging information -OPT_CXXFLAGS_YES = -Ox -GL +OPT_CXXFLAGS_YES = -Ox -GL -Oy- # # -Zi generate program database for debugging information From 278a8dac056248bdcc65bc2b5b43a9ee78487222 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Mon, 8 Sep 2014 23:07:51 -0700 Subject: [PATCH 27/41] - solaris implementation of epicsBackTrace() via walkcontext() --- src/libCom/osi/os/solaris/osdBackTrace.c | 42 ++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/libCom/osi/os/solaris/osdBackTrace.c diff --git a/src/libCom/osi/os/solaris/osdBackTrace.c b/src/libCom/osi/os/solaris/osdBackTrace.c new file mode 100644 index 000000000..b1f4ce609 --- /dev/null +++ b/src/libCom/osi/os/solaris/osdBackTrace.c @@ -0,0 +1,42 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + +#include + +#define epicsExportSharedSymbols +#include "epicsStackTracePvt.h" + +struct wlk { + void **buf; + int max; + int cur; +}; + + +static int +walker(uintptr_t addr, int sig, void *arg) +{ +struct wlk *w_p = arg; + if ( w_p->cur < w_p->max ) + w_p->buf[w_p->cur++] = (void*)addr; + return 0; +} + +int epicsBackTrace(void **buf, int buf_sz) +{ +ucontext_t u; +struct wlk d; + d.buf = buf; + d.max = buf_sz; + d.cur = 0; + if ( getcontext(&u) ) + return -1; + walkcontext( &u, walker, &d ); + return d.cur; +} From 252af56144f4fa22a14d4babd8fe0ad1598fe18f Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Mon, 8 Sep 2014 23:08:33 -0700 Subject: [PATCH 28/41] - renamed symbol that clashed on solaris --- src/libCom/test/epicsStackTraceTest.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libCom/test/epicsStackTraceTest.c b/src/libCom/test/epicsStackTraceTest.c index c42206b11..9ad91adb7 100644 --- a/src/libCom/test/epicsStackTraceTest.c +++ b/src/libCom/test/epicsStackTraceTest.c @@ -57,7 +57,7 @@ void nopFn(int lvl) RecFn volatile lfp = epicsStackTraceRecurseLcl; RecFn volatile gfp = epicsStackTraceRecurseGbl; -RecFn volatile nop = nopFn; +RecFn volatile nfp = nopFn; static void epicsStackTraceRecurseLcl(int lvl) @@ -70,7 +70,7 @@ epicsStackTraceRecurseLcl(int lvl) /* call something so that the call through gfp() doesn't * get optimized into a jump (tail-call optimization) */ - nop(0); + nfp(0); } void epicsStackTraceRecurseGbl(int lvl) @@ -83,7 +83,7 @@ void epicsStackTraceRecurseGbl(int lvl) /* call something so that the call through gfp() doesn't * get optimized into a jump (tail-call optimization) */ - nop(0); + nfp(0); } static void logClient(void *ptr, const char *msg) From 51f5a2fc99427ae11d75470c088cf3d6833ae63a Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Mon, 8 Sep 2014 23:09:18 -0700 Subject: [PATCH 29/41] - fixed illegal void* pointer arithmetic by casting to char* --- src/libCom/osi/os/posix/osdFindAddr.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libCom/osi/os/posix/osdFindAddr.c b/src/libCom/osi/os/posix/osdFindAddr.c index 830603aef..252a1dc88 100644 --- a/src/libCom/osi/os/posix/osdFindAddr.c +++ b/src/libCom/osi/os/posix/osdFindAddr.c @@ -9,8 +9,10 @@ /* Make sure dladdr() is visible on linux/solaris */ #define _GNU_SOURCE -/* For dladdr under solaris */ +/* get dladdr under solaris */ +#ifndef __EXTENSIONS__ #define __EXTENSIONS__ +#endif #include #include @@ -159,7 +161,7 @@ static size_t do_read(int fd, void *buf, size_t sz) { size_t got; -void *ptr=buf; +char *ptr=buf; while ( sz > 0 ) { if ( (got=read(fd,ptr,sz)) <= 0 ) { return got; @@ -167,7 +169,7 @@ void *ptr=buf; ptr+=got; sz -=got; } - return ptr-buf; + return ptr-(char*)buf; } /* Elf file access -- can either be with mmap or by sequential read */ @@ -446,7 +448,7 @@ const char *cp; } /* Make sure there is a terminating NUL - unfortunately, memrchr is not portable */ - cp = es->strMap->addr + es->strMap->off; + cp = (char*)es->strMap->addr + es->strMap->off; for ( idx = es->strMap->max - 1; i >= 0; i-- ) { if ( !cp[i] ) break; @@ -575,8 +577,8 @@ size_t idx; if ( es->nsyms ) { c = es->class; - sym.raw = es->symMap->addr + es->symMap->off; - strtab = es->strMap->addr + es->strMap->off; + sym.raw = (char*)es->symMap->addr + es->symMap->off; + strtab = (char*)es->strMap->addr + es->strMap->off; /* Do a brute-force search through the symbol table; if this is executed * very often then it would be worthwhile constructing a sorted list of @@ -627,7 +629,7 @@ size_t idx; if ( nearest.raw && ( (idx = ARR(c,nearest,0,st_name)) < es->strMap->max ) ) { sym_p->s_nam = strtab + idx; - sym_p->s_val = (void*) ARR(c, nearest, 0, st_value) + es->addr; + sym_p->s_val = (char*) ARR(c, nearest, 0, st_value) + es->addr; } elfsUnlockRead(); From 68901663760f6f0b45acae2719fccf04b60ff8e7 Mon Sep 17 00:00:00 2001 From: strauman Date: Mon, 8 Sep 2014 23:28:30 -0700 Subject: [PATCH 30/41] - renamed: src/libCom/osi/os/posix/osdBackTrace.c => src/libCom/osi/os/posix/osdExecinfoBackTrace.c src/libCom/osi/os/posix/osdFindAddr.c => src/libCom/osi/os/posix/osdElfFindAddr.c not all 'posix' platforms can use the above versions (since the used APIs are not really POSIX) but a subset can. The platforms which can use either version #include it from 'their' osdBackTrace.c/osdFindAddr.c. --- src/libCom/osi/os/Darwin/osdBackTrace.c | 10 ++++++++++ src/libCom/osi/os/Linux/osdBackTrace.c | 10 ++++++++++ src/libCom/osi/os/Linux/osdFindAddr.c | 10 ++++++++++ .../osi/os/posix/{osdFindAddr.c => osdElfFindAddr.c} | 0 .../posix/{osdBackTrace.c => osdExecinfoBackTrace.c} | 0 src/libCom/osi/os/solaris/osdFindAddr.c | 10 ++++++++++ 6 files changed, 40 insertions(+) create mode 100644 src/libCom/osi/os/Darwin/osdBackTrace.c create mode 100644 src/libCom/osi/os/Linux/osdBackTrace.c create mode 100644 src/libCom/osi/os/Linux/osdFindAddr.c rename src/libCom/osi/os/posix/{osdFindAddr.c => osdElfFindAddr.c} (100%) rename src/libCom/osi/os/posix/{osdBackTrace.c => osdExecinfoBackTrace.c} (100%) create mode 100644 src/libCom/osi/os/solaris/osdFindAddr.c diff --git a/src/libCom/osi/os/Darwin/osdBackTrace.c b/src/libCom/osi/os/Darwin/osdBackTrace.c new file mode 100644 index 000000000..a230e0780 --- /dev/null +++ b/src/libCom/osi/os/Darwin/osdBackTrace.c @@ -0,0 +1,10 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + +#include "osdExecinfoBackTrace.c" diff --git a/src/libCom/osi/os/Linux/osdBackTrace.c b/src/libCom/osi/os/Linux/osdBackTrace.c new file mode 100644 index 000000000..a230e0780 --- /dev/null +++ b/src/libCom/osi/os/Linux/osdBackTrace.c @@ -0,0 +1,10 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + +#include "osdExecinfoBackTrace.c" diff --git a/src/libCom/osi/os/Linux/osdFindAddr.c b/src/libCom/osi/os/Linux/osdFindAddr.c new file mode 100644 index 000000000..6b2b7c2ab --- /dev/null +++ b/src/libCom/osi/os/Linux/osdFindAddr.c @@ -0,0 +1,10 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + +#include "osdElfFindAddr.c" diff --git a/src/libCom/osi/os/posix/osdFindAddr.c b/src/libCom/osi/os/posix/osdElfFindAddr.c similarity index 100% rename from src/libCom/osi/os/posix/osdFindAddr.c rename to src/libCom/osi/os/posix/osdElfFindAddr.c diff --git a/src/libCom/osi/os/posix/osdBackTrace.c b/src/libCom/osi/os/posix/osdExecinfoBackTrace.c similarity index 100% rename from src/libCom/osi/os/posix/osdBackTrace.c rename to src/libCom/osi/os/posix/osdExecinfoBackTrace.c diff --git a/src/libCom/osi/os/solaris/osdFindAddr.c b/src/libCom/osi/os/solaris/osdFindAddr.c new file mode 100644 index 000000000..6b2b7c2ab --- /dev/null +++ b/src/libCom/osi/os/solaris/osdFindAddr.c @@ -0,0 +1,10 @@ +/* + * Copyright: Stanford University / SLAC National Laboratory. + * + * EPICS BASE is distributed subject to a Software License Agreement found + * in file LICENSE that is included with this distribution. + * + * Author: Till Straumann , 2011 + */ + +#include "osdElfFindAddr.c" From 438863ebd943ae989c969703d09f7cb9213efbac Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Wed, 10 Sep 2014 12:00:08 -0700 Subject: [PATCH 31/41] - updated copyright info --- src/libCom/osi/os/Darwin/osdBackTrace.c | 2 +- src/libCom/osi/os/Linux/osdBackTrace.c | 2 +- src/libCom/osi/os/Linux/osdFindAddr.c | 2 +- src/libCom/osi/os/WIN32/osdBackTrace.c | 3 +-- src/libCom/osi/os/default/osdBackTrace.c | 2 +- src/libCom/osi/os/posix/osdExecinfoBackTrace.c | 2 +- src/libCom/osi/os/solaris/osdBackTrace.c | 2 +- src/libCom/osi/os/solaris/osdFindAddr.c | 2 +- 8 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/libCom/osi/os/Darwin/osdBackTrace.c b/src/libCom/osi/os/Darwin/osdBackTrace.c index a230e0780..19be7fb8d 100644 --- a/src/libCom/osi/os/Darwin/osdBackTrace.c +++ b/src/libCom/osi/os/Darwin/osdBackTrace.c @@ -4,7 +4,7 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. * - * Author: Till Straumann , 2011 + * Author: Till Straumann , 2011, 2014 */ #include "osdExecinfoBackTrace.c" diff --git a/src/libCom/osi/os/Linux/osdBackTrace.c b/src/libCom/osi/os/Linux/osdBackTrace.c index a230e0780..19be7fb8d 100644 --- a/src/libCom/osi/os/Linux/osdBackTrace.c +++ b/src/libCom/osi/os/Linux/osdBackTrace.c @@ -4,7 +4,7 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. * - * Author: Till Straumann , 2011 + * Author: Till Straumann , 2011, 2014 */ #include "osdExecinfoBackTrace.c" diff --git a/src/libCom/osi/os/Linux/osdFindAddr.c b/src/libCom/osi/os/Linux/osdFindAddr.c index 6b2b7c2ab..84d17d96f 100644 --- a/src/libCom/osi/os/Linux/osdFindAddr.c +++ b/src/libCom/osi/os/Linux/osdFindAddr.c @@ -4,7 +4,7 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. * - * Author: Till Straumann , 2011 + * Author: Till Straumann , 2011, 2014 */ #include "osdElfFindAddr.c" diff --git a/src/libCom/osi/os/WIN32/osdBackTrace.c b/src/libCom/osi/os/WIN32/osdBackTrace.c index 4afd8a4f1..e1b7cbcc7 100644 --- a/src/libCom/osi/os/WIN32/osdBackTrace.c +++ b/src/libCom/osi/os/WIN32/osdBackTrace.c @@ -4,11 +4,10 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. * - * Author: Till Straumann , 2011 + * Author: Till Straumann , 2014 */ #include -#include #define epicsExportSharedSymbols #include "epicsStackTracePvt.h" diff --git a/src/libCom/osi/os/default/osdBackTrace.c b/src/libCom/osi/os/default/osdBackTrace.c index c77572351..e1f96c033 100644 --- a/src/libCom/osi/os/default/osdBackTrace.c +++ b/src/libCom/osi/os/default/osdBackTrace.c @@ -4,7 +4,7 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. * - * Author: Till Straumann , 2011 + * Author: Till Straumann , 2011, 2014 */ #define epicsExportSharedSymbols diff --git a/src/libCom/osi/os/posix/osdExecinfoBackTrace.c b/src/libCom/osi/os/posix/osdExecinfoBackTrace.c index 41a15a585..ae13d28fc 100644 --- a/src/libCom/osi/os/posix/osdExecinfoBackTrace.c +++ b/src/libCom/osi/os/posix/osdExecinfoBackTrace.c @@ -4,7 +4,7 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. * - * Author: Till Straumann , 2011 + * Author: Till Straumann , 2011, 2014 */ #include diff --git a/src/libCom/osi/os/solaris/osdBackTrace.c b/src/libCom/osi/os/solaris/osdBackTrace.c index b1f4ce609..fcee38ce6 100644 --- a/src/libCom/osi/os/solaris/osdBackTrace.c +++ b/src/libCom/osi/os/solaris/osdBackTrace.c @@ -4,7 +4,7 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. * - * Author: Till Straumann , 2011 + * Author: Till Straumann , 2014 */ #include diff --git a/src/libCom/osi/os/solaris/osdFindAddr.c b/src/libCom/osi/os/solaris/osdFindAddr.c index 6b2b7c2ab..84d17d96f 100644 --- a/src/libCom/osi/os/solaris/osdFindAddr.c +++ b/src/libCom/osi/os/solaris/osdFindAddr.c @@ -4,7 +4,7 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. * - * Author: Till Straumann , 2011 + * Author: Till Straumann , 2011, 2014 */ #include "osdElfFindAddr.c" From fad25a3b11eae9fbec7bbe09cdf097578aa46449 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Wed, 10 Sep 2014 12:00:51 -0700 Subject: [PATCH 32/41] - cleanup - reduced epicsStackTraceGetFeatures to epicsFindAddrGetFeatures --- src/libCom/osi/os/posix/osdElfFindAddr.c | 152 +++++++++++------------ 1 file changed, 71 insertions(+), 81 deletions(-) diff --git a/src/libCom/osi/os/posix/osdElfFindAddr.c b/src/libCom/osi/os/posix/osdElfFindAddr.c index 252a1dc88..45f7400df 100644 --- a/src/libCom/osi/os/posix/osdElfFindAddr.c +++ b/src/libCom/osi/os/posix/osdElfFindAddr.c @@ -27,9 +27,8 @@ #include #endif - -#include "epicsThread.h" #include "epicsMutex.h" +#include "epicsThread.h" #include #define epicsExportSharedSymbols @@ -38,10 +37,12 @@ #define FIND_ADDR_DEBUG 0 -/* Darwin and GNU have dladdr() and Darwin's already finds local - * symbols, too, whereas linux' does not. - * Hence, on linux we want to use dladdr() and lookup static - * symbols in the ELF symbol table. +/* + * On some systems (linux, solaris) dladdr doesn't find local symbols + * or symbols in the main executable. + * Hence, we want to use dladdr() to find the file name + * where a symbol is defined and if not more information is available + * then proceed to lookup symbols in the ELF symbol tables. */ /* Macros to handle elf32 vs. elf64 access to unions etc. */ @@ -100,49 +101,31 @@ typedef struct ESyms_ { /* LOCKING NOTE: if the ELF symbol facility is ever expanded to be truly used * in a multithreaded way then proper multiple-readers, single-writer locking - * should be implemented: - * - elfsLockWrite() must block until all readers have left - * - elfsLockRead() must block until writer has left. - * - elfsLockConvertWriteRead() atomically converts writer holding the - * writer's lock into a reader. - * Right now we just use a single, global lock (for the stack trace) since we - * only need to guard against multiple threads dumping stacks simultaneously and - * we do not lock the symbol table(s) at all. + * should be implemented. */ /* Linked list where we keep all our ESyms */ static ESyms elfs = 0; +static epicsMutexId listMtx; +static epicsThreadOnceId listMtxInitId = EPICS_THREAD_ONCE_INIT; + +static void listMtxInit(void *unused) +{ + listMtx = epicsMutexMustCreate(); +} + static void elfsLockWrite() { - /* Only a single writer can hold this while no readers are active */ + epicsThreadOnce(&listMtxInitId, listMtxInit, 0); + epicsMutexMustLock(listMtx); } static void elfsUnlockWrite() { - /* Must wake up readers blocking in elfsLockRead() */ -} - -static void -elfsLockConvertWriteRead() -{ - /* Must atomically convert a writer into a reader, i.e., unlock - * the writer's lock and atomically acquire the reader's lock - */ -} - -static void -elfsLockRead() -{ - /* Multiple readers can hold this while the writer is not active */ -} - -static void -elfsUnlockRead() -{ - /* Must wake up a (single) writer blockingĀ in elfsLockWrite */ + epicsMutexUnlock(listMtx); } static void @@ -218,6 +201,11 @@ bail: freeMap(rval); return 0; } +#else +static MMap getscn_mmap(int fd, uint8_t c, Shrd *shdr_p) +{ + return 0; +} #endif /* Destructor for data that is read into a malloc()ed buffer */ @@ -273,25 +261,15 @@ bail: return 0; } -static MMap (*getscn)(int fd, uint8_t c, Shdr *shdr_p) = -#ifdef _POSIX_MAPPED_FILES - getscn_mmap -#else - getscn_read -#endif - ; - -int -epicsElfConfigAccess(int use_mmap) +static MMap +getscn(int fd, uint8_t c, Shdr *shdr_p) { -#ifndef _POSIX_MAPPED_FILES - if ( use_mmap ) - return -1; /* not supported on this system */ - /* else no need to change default */ -#else - getscn = use_mmap ? getscn_mmap : getscn_read; -#endif - return 0; +MMap rval = getscn_mmap(fd, c, shdr_p); + + if ( ! rval ) + rval = getscn_read(fd, c, shdr_p); + + return rval; } /* Release resources but keep filename so that @@ -486,22 +464,35 @@ elfSymsDestroy(ESyms es) } } -/* Destroy all cached ELF symbol tables */ +/* Destroy all cached ELF symbol tables + * + * However - w/o proper locking for read access + * this must not be used. Otherwise, readers + * will hold stale pointers... + * + * We leave the commented code here to show + * how the tables can be torn down. + void -epicsSymTblFlush() +elfSymTblFlush() { ESyms es; elfsLockWrite(); while ( (es = elfs) ) { elfs = es->next; - es->next = 0; /* paranoia */ + es->next = 0; + elfsUnlockWrite(); elfSymsDestroy(es); + elfsLockWrite(); } - elfsUnlockWrite(); - + elfsUnlockWrite(); } +*/ + + +/* This routine must be called with the write-lock held */ static ESyms elfSymsFind(const char *fname) { @@ -515,7 +506,7 @@ int epicsFindAddr(void *addr, epicsSymbol *sym_p) { Dl_info inf; -ESyms es,nes; +ESyms es,nes = 0; uintptr_t minoff,off; int i; Sym sym; @@ -544,13 +535,14 @@ size_t idx; /* No symbol info; try to access ELF file and ready symbol table from there */ - elfsLockRead(); + elfsLockWrite(); /* See if we have loaded this file already */ es = elfSymsFind(inf.dli_fname); if ( !es ) { - elfsUnlockRead(); + + elfsUnlockWrite(); if ( ! (nes = elfRead(inf.dli_fname, (uintptr_t)inf.dli_fbase)) ) { /* this path can only be taken if there is no memory for '*nes' */ @@ -563,15 +555,20 @@ size_t idx; es = elfSymsFind(inf.dli_fname); if ( es ) { - /* undo our work in the unlikely event... */ - elfSymsDestroy( nes ); + /* will undo our work in the unlikely event... */ } else { nes->next = elfs; - es = elfs = nes; + es = elfs = nes; + nes = 0; } - elfsLockConvertWriteRead(); } + elfsUnlockWrite(); + + /* Undo our work in the unlikely event that it was redundant */ + if ( nes ) + elfSymsDestroy( nes ); + nearest.raw = 0; minoff = (uintptr_t)-1LL; @@ -632,25 +629,18 @@ size_t idx; sym_p->s_val = (char*) ARR(c, nearest, 0, st_value) + es->addr; } - elfsUnlockRead(); - return 0; } -int epicsStackTraceGetFeatures(void) +int epicsFindAddrGetFeatures(void) { - /* We are a bit conservative here. The actual - * situation depends on how we are linked (something - * we don't have under control at compilation time) - * Linux' dladdr finds global symbols - * (not from dynamic libraries) when statically linked but - * not when dynamically linked. - * OTOH: for a stripped executable it is unlikely that - * even the ELF reader is able to help much... - */ - + /* The static information given here may not be correct; + * it also depends on + * - compilation (frame pointer optimization) + * - linkage (static vs. dynamic) + * - stripping + */ return EPICS_STACKTRACE_LCL_SYMBOLS | EPICS_STACKTRACE_GBL_SYMBOLS - | EPICS_STACKTRACE_DYN_SYMBOLS - | EPICS_STACKTRACE_ADDRESSES; + | EPICS_STACKTRACE_DYN_SYMBOLS; } From cc04994d1242b3658728a11dac11f6a18e458699 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Wed, 10 Sep 2014 12:01:50 -0700 Subject: [PATCH 33/41] - updated copyright info - let epicsFindAddr clear out returned symbol info - provide epicsFindAddrGetFeatures instead of epicsStackTraceGetFeatures --- src/libCom/osi/os/default/osdFindAddr.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libCom/osi/os/default/osdFindAddr.c b/src/libCom/osi/os/default/osdFindAddr.c index 4cda3977d..87322840d 100644 --- a/src/libCom/osi/os/default/osdFindAddr.c +++ b/src/libCom/osi/os/default/osdFindAddr.c @@ -4,7 +4,7 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. * - * Author: Till Straumann , 2011 + * Author: Till Straumann , 2011, 2014 */ #define epicsExportSharedSymbols @@ -13,10 +13,13 @@ int epicsFindAddr(void *addr, epicsSymbol *sym_p) { + sym_p->f_nam = 0; + sym_p->s_nam = 0; + sym_p->s_val = 0; return -1; } -int epicsStackTraceGetFeatures(void) +int epicsFindAddrGetFeatures(void) { return 0; } From a2339b921988b39e893d97cbc906c83f528e3dc5 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Wed, 10 Sep 2014 12:03:04 -0700 Subject: [PATCH 34/41] - WIN32 can now use default osdFindAddr (until symbol lookup is implemented) --- src/libCom/osi/os/WIN32/osdFindAddr.c | 31 --------------------------- 1 file changed, 31 deletions(-) delete mode 100644 src/libCom/osi/os/WIN32/osdFindAddr.c diff --git a/src/libCom/osi/os/WIN32/osdFindAddr.c b/src/libCom/osi/os/WIN32/osdFindAddr.c deleted file mode 100644 index a39654188..000000000 --- a/src/libCom/osi/os/WIN32/osdFindAddr.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright: Stanford University / SLAC National Laboratory. - * - * EPICS BASE is distributed subject to a Software License Agreement found - * in file LICENSE that is included with this distribution. - * - * Author: Till Straumann , 2011 - */ - -#define epicsExportSharedSymbols -#include "epicsStackTracePvt.h" -#include "epicsStackTrace.h" - -int epicsFindAddr(void *addr, epicsSymbol *sym_p) -{ - return -1; -} - -int epicsStackTraceGetFeatures(void) -{ -void *test[10]; - - /* If frame-pointer optimization is on then CaptureStackBackTrace - * does not work. Make sure all EPICS is built with -Oy- - */ - if ( 0 == epicsBackTrace(test, sizeof(test)/sizeof(test[0])) ) - return 0; - - /* address->symbol conversion not implemented (yet) */ - return EPICS_STACKTRACE_ADDRESSES; -} From 0252dd19056d407d58dc9681b0c0ea506a20796b Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Wed, 10 Sep 2014 12:03:50 -0700 Subject: [PATCH 35/41] - simplified code - provide epicsFindAddrGetFeatures() instead of epicsStackTraceGetFeatures() --- src/libCom/osi/os/Darwin/osdFindAddr.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/libCom/osi/os/Darwin/osdFindAddr.c b/src/libCom/osi/os/Darwin/osdFindAddr.c index d2f5a4465..8c77aadf3 100644 --- a/src/libCom/osi/os/Darwin/osdFindAddr.c +++ b/src/libCom/osi/os/Darwin/osdFindAddr.c @@ -22,24 +22,22 @@ int epicsFindAddr(void *addr, epicsSymbol *sym_p) { Dl_info inf; - if ( ! dladdr(addr, &inf) || (!inf.dli_fname && !inf.dli_sname) ) { + if ( ! dladdr(addr, &inf) ) { sym_p->f_nam = 0; sym_p->s_nam = 0; - /* unable to lookup */ - return 0; - } - - sym_p->f_nam = inf.dli_fname; - sym_p->s_nam = inf.dli_sname; - sym_p->s_val = inf.dli_saddr; + sym_p->s_val = 0; + } else { + sym_p->f_nam = inf.dli_fname; + sym_p->s_nam = inf.dli_sname; + sym_p->s_val = inf.dli_saddr; + } return 0; } -epicsShareFunc int epicsStackTraceGetFeatures(void) +int epicsFindAddrGetFeatures(void) { return EPICS_STACKTRACE_LCL_SYMBOLS | EPICS_STACKTRACE_GBL_SYMBOLS - | EPICS_STACKTRACE_DYN_SYMBOLS - | EPICS_STACKTRACE_ADDRESSES; + | EPICS_STACKTRACE_DYN_SYMBOLS; } From f1bb53230744ece7f871d09f733255e5799fecd8 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Wed, 10 Sep 2014 12:04:36 -0700 Subject: [PATCH 36/41] - simplified some code - epicsStackTrace.c provides generic epicsStackTraceGetFeatures() testing the 'epicsBackTrace()' functionality. Call out to epicsFindAddrGetFeatures() to inquire about symbol lookup support. --- src/libCom/osi/epicsStackTrace.c | 61 ++++++++++++++--------------- src/libCom/osi/epicsStackTracePvt.h | 19 ++------- 2 files changed, 32 insertions(+), 48 deletions(-) diff --git a/src/libCom/osi/epicsStackTrace.c b/src/libCom/osi/epicsStackTrace.c index 5480d842a..3bb0cf953 100644 --- a/src/libCom/osi/epicsStackTrace.c +++ b/src/libCom/osi/epicsStackTrace.c @@ -7,7 +7,6 @@ * Author: Till Straumann , 2011, 2014 */ -#include #include #include "epicsStackTracePvt.h" @@ -41,44 +40,23 @@ static void stackTraceUnlock(void) } static int -dump(char **buf, int *buf_sz, int *good, const char *fmt, ...) -{ -va_list ap; -int rval, put; - va_start(ap, fmt); - if ( *buf ) { - put = rval = vsnprintf(*buf, *buf_sz, fmt, ap); - if ( put > *buf_sz ) - put = *buf_sz; - *buf += put; - *buf_sz -= put; - } else { - rval = errlogVprintf(fmt, ap); - } - va_end(ap); - if ( rval > 0 ) - *good += rval; - return rval; -} - -static int -symDump(char *buf, int buf_sz, void *addr, epicsSymbol *sym_p) +dumpInfo(void *addr, epicsSymbol *sym_p) { int rval = 0; - dump( &buf, &buf_sz, &rval, "[%*p]", sizeof(addr)*2 + 2, addr); + rval += errlogPrintf("[%*p]", (int)(sizeof(addr)*2 + 2), addr); if ( sym_p ) { if ( sym_p->f_nam ) { - dump( &buf, &buf_sz, &rval, ": %s", sym_p->f_nam ); + rval += errlogPrintf(": %s", sym_p->f_nam); } if ( sym_p->s_nam ) { - /* windows didn't grok the void* pointer arithmetic */ - dump( &buf, &buf_sz, &rval, "(%s+0x%lx)", sym_p->s_nam, (unsigned long)((char*)addr - (char*)sym_p->s_val)); + rval += errlogPrintf("(%s+0x%lx)", sym_p->s_nam, (unsigned long)((char*)addr - (char*)sym_p->s_val)); + } else { + rval += errlogPrintf("()"); } } - dump( &buf, &buf_sz, &rval, "\n"); - if ( ! buf ) - errlogFlush(); + rval += errlogPrintf("\n"); + errlogFlush(); return rval; } @@ -112,9 +90,9 @@ epicsSymbol sym; for ( i=0; i Date: Thu, 18 Sep 2014 12:18:48 -0700 Subject: [PATCH 37/41] - made osdBackTrace/osdFindAddr c++ sources to be more flexible for implementations. Fixed compiler warnings (c++ more picky than cc). --- src/libCom/osi/Makefile | 4 +-- .../{osdBackTrace.c => osdBackTrace.cpp} | 2 +- .../Darwin/{osdFindAddr.c => osdFindAddr.cpp} | 0 .../{osdBackTrace.c => osdBackTrace.cpp} | 2 +- .../Linux/{osdFindAddr.c => osdFindAddr.cpp} | 2 +- .../{osdBackTrace.c => osdBackTrace.cpp} | 0 .../{osdBackTrace.c => osdBackTrace.cpp} | 0 .../{osdFindAddr.c => osdFindAddr.cpp} | 0 .../{osdElfFindAddr.c => osdElfFindAddr.cpp} | 31 ++++++++++--------- ...foBackTrace.c => osdExecinfoBackTrace.cpp} | 0 .../{osdBackTrace.c => osdBackTrace.cpp} | 0 .../{osdFindAddr.c => osdFindAddr.cpp} | 2 +- 12 files changed, 23 insertions(+), 20 deletions(-) rename src/libCom/osi/os/Darwin/{osdBackTrace.c => osdBackTrace.cpp} (88%) rename src/libCom/osi/os/Darwin/{osdFindAddr.c => osdFindAddr.cpp} (100%) rename src/libCom/osi/os/Linux/{osdBackTrace.c => osdBackTrace.cpp} (88%) rename src/libCom/osi/os/Linux/{osdFindAddr.c => osdFindAddr.cpp} (90%) rename src/libCom/osi/os/WIN32/{osdBackTrace.c => osdBackTrace.cpp} (100%) rename src/libCom/osi/os/default/{osdBackTrace.c => osdBackTrace.cpp} (100%) rename src/libCom/osi/os/default/{osdFindAddr.c => osdFindAddr.cpp} (100%) rename src/libCom/osi/os/posix/{osdElfFindAddr.c => osdElfFindAddr.cpp} (97%) rename src/libCom/osi/os/posix/{osdExecinfoBackTrace.c => osdExecinfoBackTrace.cpp} (100%) rename src/libCom/osi/os/solaris/{osdBackTrace.c => osdBackTrace.cpp} (100%) rename src/libCom/osi/os/solaris/{osdFindAddr.c => osdFindAddr.cpp} (90%) diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index 781497a1a..13d625f8d 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -144,5 +144,5 @@ Com_SRCS_WIN32 += forceBadAllocException.cpp #Stack trace support Com_SRCS += epicsStackTrace.c -Com_SRCS += osdBackTrace.c -Com_SRCS += osdFindAddr.c +Com_SRCS += osdBackTrace.cpp +Com_SRCS += osdFindAddr.cpp diff --git a/src/libCom/osi/os/Darwin/osdBackTrace.c b/src/libCom/osi/os/Darwin/osdBackTrace.cpp similarity index 88% rename from src/libCom/osi/os/Darwin/osdBackTrace.c rename to src/libCom/osi/os/Darwin/osdBackTrace.cpp index 19be7fb8d..4595fee3a 100644 --- a/src/libCom/osi/os/Darwin/osdBackTrace.c +++ b/src/libCom/osi/os/Darwin/osdBackTrace.cpp @@ -7,4 +7,4 @@ * Author: Till Straumann , 2011, 2014 */ -#include "osdExecinfoBackTrace.c" +#include "osdExecinfoBackTrace.cpp" diff --git a/src/libCom/osi/os/Darwin/osdFindAddr.c b/src/libCom/osi/os/Darwin/osdFindAddr.cpp similarity index 100% rename from src/libCom/osi/os/Darwin/osdFindAddr.c rename to src/libCom/osi/os/Darwin/osdFindAddr.cpp diff --git a/src/libCom/osi/os/Linux/osdBackTrace.c b/src/libCom/osi/os/Linux/osdBackTrace.cpp similarity index 88% rename from src/libCom/osi/os/Linux/osdBackTrace.c rename to src/libCom/osi/os/Linux/osdBackTrace.cpp index 19be7fb8d..4595fee3a 100644 --- a/src/libCom/osi/os/Linux/osdBackTrace.c +++ b/src/libCom/osi/os/Linux/osdBackTrace.cpp @@ -7,4 +7,4 @@ * Author: Till Straumann , 2011, 2014 */ -#include "osdExecinfoBackTrace.c" +#include "osdExecinfoBackTrace.cpp" diff --git a/src/libCom/osi/os/Linux/osdFindAddr.c b/src/libCom/osi/os/Linux/osdFindAddr.cpp similarity index 90% rename from src/libCom/osi/os/Linux/osdFindAddr.c rename to src/libCom/osi/os/Linux/osdFindAddr.cpp index 84d17d96f..1f5d2e32e 100644 --- a/src/libCom/osi/os/Linux/osdFindAddr.c +++ b/src/libCom/osi/os/Linux/osdFindAddr.cpp @@ -7,4 +7,4 @@ * Author: Till Straumann , 2011, 2014 */ -#include "osdElfFindAddr.c" +#include "osdElfFindAddr.cpp" diff --git a/src/libCom/osi/os/WIN32/osdBackTrace.c b/src/libCom/osi/os/WIN32/osdBackTrace.cpp similarity index 100% rename from src/libCom/osi/os/WIN32/osdBackTrace.c rename to src/libCom/osi/os/WIN32/osdBackTrace.cpp diff --git a/src/libCom/osi/os/default/osdBackTrace.c b/src/libCom/osi/os/default/osdBackTrace.cpp similarity index 100% rename from src/libCom/osi/os/default/osdBackTrace.c rename to src/libCom/osi/os/default/osdBackTrace.cpp diff --git a/src/libCom/osi/os/default/osdFindAddr.c b/src/libCom/osi/os/default/osdFindAddr.cpp similarity index 100% rename from src/libCom/osi/os/default/osdFindAddr.c rename to src/libCom/osi/os/default/osdFindAddr.cpp diff --git a/src/libCom/osi/os/posix/osdElfFindAddr.c b/src/libCom/osi/os/posix/osdElfFindAddr.cpp similarity index 97% rename from src/libCom/osi/os/posix/osdElfFindAddr.c rename to src/libCom/osi/os/posix/osdElfFindAddr.cpp index 45f7400df..518b55a51 100644 --- a/src/libCom/osi/os/posix/osdElfFindAddr.c +++ b/src/libCom/osi/os/posix/osdElfFindAddr.cpp @@ -8,7 +8,9 @@ */ /* Make sure dladdr() is visible on linux/solaris */ +#ifndef _GNU_SOURCE #define _GNU_SOURCE +#endif /* get dladdr under solaris */ #ifndef __EXTENSIONS__ #define __EXTENSIONS__ @@ -96,7 +98,7 @@ typedef struct ESyms_ { MMap symMap; MMap strMap; size_t nsyms; - uint8_t class; + uint8_t eclss; } *ESyms; /* LOCKING NOTE: if the ELF symbol facility is ever expanded to be truly used @@ -140,11 +142,11 @@ freeMap(MMap m) /* Helper to read exactly 'sz' bytes into 'buf' * RETURNS: # chars read or negative value on error. */ -static size_t -do_read(int fd, void *buf, size_t sz) +static ssize_t +do_read(int fd, void *buf, ssize_t sz) { -size_t got; -char *ptr=buf; +ssize_t got; +char *ptr=(char*)buf; while ( sz > 0 ) { if ( (got=read(fd,ptr,sz)) <= 0 ) { return got; @@ -179,7 +181,7 @@ size_t pgsz = sysconf(_SC_PAGESIZE); goto bail; } - if ( ! (rval = malloc(sizeof(*rval))) ) { + if ( ! (rval = (MMap) malloc(sizeof(*rval))) ) { errlogPrintf("elfRead - getscn() -- no memory for section map\n"); goto bail; } @@ -219,7 +221,7 @@ freeMapMalloc(MMap m) static MMap getscn_read(int fd, uint8_t c, Shdr *shdr_p) { -size_t n; +ssize_t n; MMap rval = 0; if ( 0 == (n=FLD(c,(*shdr_p),sh_size)) ) { @@ -227,7 +229,7 @@ MMap rval = 0; goto bail; } - if ( ! (rval = malloc(sizeof(*rval))) ) { + if ( ! (rval = (MMap) malloc(sizeof(*rval))) ) { errlogPrintf("elfRead - getscn() -- no memory for section map\n"); goto bail; } @@ -293,15 +295,16 @@ elfSymsRelease(ESyms es) static ESyms elfRead(const char *fname, uintptr_t fbase) { -int i,n; +int i; Ehdr ehdr; Shdr shdr; uint8_t c; ESyms es; -ssize_t idx; +ssize_t idx,n; const char *cp; +struct stat stat_b; - if ( !(es = malloc(sizeof(*es))) ) { + if ( !(es = (ESyms) malloc(sizeof(*es))) ) { /* no memory -- give up */ return 0; } @@ -333,7 +336,7 @@ const char *cp; goto bail; } - switch ( (es->class = c = ehdr.e32.e_ident[EI_CLASS]) ) { + switch ( (es->eclss = c = ehdr.e32.e_ident[EI_CLASS]) ) { default: errlogPrintf("bad ELF class\n"); goto bail; @@ -508,7 +511,7 @@ epicsFindAddr(void *addr, epicsSymbol *sym_p) Dl_info inf; ESyms es,nes = 0; uintptr_t minoff,off; -int i; +size_t i; Sym sym; Sym nearest; const char *strtab; @@ -573,7 +576,7 @@ size_t idx; minoff = (uintptr_t)-1LL; if ( es->nsyms ) { - c = es->class; + c = es->eclss; sym.raw = (char*)es->symMap->addr + es->symMap->off; strtab = (char*)es->strMap->addr + es->strMap->off; diff --git a/src/libCom/osi/os/posix/osdExecinfoBackTrace.c b/src/libCom/osi/os/posix/osdExecinfoBackTrace.cpp similarity index 100% rename from src/libCom/osi/os/posix/osdExecinfoBackTrace.c rename to src/libCom/osi/os/posix/osdExecinfoBackTrace.cpp diff --git a/src/libCom/osi/os/solaris/osdBackTrace.c b/src/libCom/osi/os/solaris/osdBackTrace.cpp similarity index 100% rename from src/libCom/osi/os/solaris/osdBackTrace.c rename to src/libCom/osi/os/solaris/osdBackTrace.cpp diff --git a/src/libCom/osi/os/solaris/osdFindAddr.c b/src/libCom/osi/os/solaris/osdFindAddr.cpp similarity index 90% rename from src/libCom/osi/os/solaris/osdFindAddr.c rename to src/libCom/osi/os/solaris/osdFindAddr.cpp index 84d17d96f..1f5d2e32e 100644 --- a/src/libCom/osi/os/solaris/osdFindAddr.c +++ b/src/libCom/osi/os/solaris/osdFindAddr.cpp @@ -7,4 +7,4 @@ * Author: Till Straumann , 2011, 2014 */ -#include "osdElfFindAddr.c" +#include "osdElfFindAddr.cpp" From bbfb69ed8d4f7adb7b37dad752c58edba5e62c36 Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 18 Sep 2014 12:19:47 -0700 Subject: [PATCH 38/41] - implemented suggestion by Michael Davidsaver: when reading ELF files check modifification time against program start time and warn if the file was modified more recently since it could be out of date. --- src/libCom/osi/os/posix/osdElfFindAddr.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/libCom/osi/os/posix/osdElfFindAddr.cpp b/src/libCom/osi/os/posix/osdElfFindAddr.cpp index 518b55a51..4f7d38f0d 100644 --- a/src/libCom/osi/os/posix/osdElfFindAddr.cpp +++ b/src/libCom/osi/os/posix/osdElfFindAddr.cpp @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #ifdef _POSIX_MAPPED_FILES #include @@ -112,6 +115,18 @@ static ESyms elfs = 0; static epicsMutexId listMtx; static epicsThreadOnceId listMtxInitId = EPICS_THREAD_ONCE_INIT; +static time_t getStartTime() +{ +struct timespec ts; + + if ( clock_gettime(CLOCK_REALTIME, &ts) ) + return (time_t)0; + + return ts.tv_sec; +} + +static time_t prog_start_time = getStartTime(); + static void listMtxInit(void *unused) { listMtx = epicsMutexMustCreate(); @@ -350,6 +365,12 @@ struct stat stat_b; } n -= EI_NIDENT; + if ( 0 == fstat(es->fd, &stat_b) ) { + if ( stat_b.st_mtime > prog_start_time ) { + errlogPrintf("elfRead() -- WARNING: '%s' was modified after program start -- symbol information may be inaccurate or invalid\n", fname); + } + } + /* read rest */ if ( n != do_read(es->fd, ehdr.e32.e_ident + EI_NIDENT, n) ) { errlogPrintf("elfRead() -- unable to read ELF ehdr: %s\n", strerror(errno)); From d925772857a8f384402b69d112f78c54b081a83c Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 18 Sep 2014 14:05:32 -0700 Subject: [PATCH 39/41] - fixed c++ warnings --- src/libCom/osi/os/solaris/osdBackTrace.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libCom/osi/os/solaris/osdBackTrace.cpp b/src/libCom/osi/os/solaris/osdBackTrace.cpp index fcee38ce6..55d5e3648 100644 --- a/src/libCom/osi/os/solaris/osdBackTrace.cpp +++ b/src/libCom/osi/os/solaris/osdBackTrace.cpp @@ -19,15 +19,19 @@ struct wlk { }; +extern "C" { + static int walker(uintptr_t addr, int sig, void *arg) { -struct wlk *w_p = arg; +struct wlk *w_p = (struct wlk *)arg; if ( w_p->cur < w_p->max ) w_p->buf[w_p->cur++] = (void*)addr; return 0; } +} + int epicsBackTrace(void **buf, int buf_sz) { ucontext_t u; From f278ba656bc0059d16866ecafb6eae5f6976128f Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Thu, 18 Sep 2014 14:06:04 -0700 Subject: [PATCH 40/41] - fixed c++ warnings --- src/libCom/osi/os/posix/osdElfFindAddr.cpp | 24 +++++++++++++--------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/libCom/osi/os/posix/osdElfFindAddr.cpp b/src/libCom/osi/os/posix/osdElfFindAddr.cpp index 4f7d38f0d..69f136ee0 100644 --- a/src/libCom/osi/os/posix/osdElfFindAddr.cpp +++ b/src/libCom/osi/os/posix/osdElfFindAddr.cpp @@ -127,11 +127,15 @@ struct timespec ts; static time_t prog_start_time = getStartTime(); +extern "C" { + static void listMtxInit(void *unused) { listMtx = epicsMutexMustCreate(); } +} + static void elfsLockWrite() { @@ -187,11 +191,11 @@ freeMapMmap(MMap m) static MMap getscn_mmap(int fd, uint8_t c, Shdr *shdr_p) { -size_t n; +off_t n; MMap rval = 0; size_t pgsz = sysconf(_SC_PAGESIZE); - if ( 0 == (n=FLD(c,(*shdr_p),sh_size)) ) { + if ( 0 == (n = (off_t)FLD(c,(*shdr_p),sh_size)) ) { errlogPrintf("elfRead - getscn() -- no section data\n"); goto bail; } @@ -203,11 +207,11 @@ size_t pgsz = sysconf(_SC_PAGESIZE); rval->freeMap = freeMapMmap; - rval->off = FLD(c,(*shdr_p),sh_offset) & (pgsz-1); + rval->off = (off_t) (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))) ) { + if ( MAP_FAILED == (rval->addr = mmap(0, rval->len, PROT_READ, MAP_SHARED, fd, (off_t) (FLD(c,(*shdr_p),sh_offset) & ~(pgsz-1)))) ) { errlogPrintf("elfRead - getscn() -- mapping section contents: %s\n", strerror(errno)); goto bail; } @@ -239,7 +243,7 @@ getscn_read(int fd, uint8_t c, Shdr *shdr_p) ssize_t n; MMap rval = 0; - if ( 0 == (n=FLD(c,(*shdr_p),sh_size)) ) { + if ( 0 == (n = (ssize_t) FLD(c,(*shdr_p),sh_size)) ) { errlogPrintf("elfRead - getscn() -- no section data\n"); goto bail; } @@ -261,7 +265,7 @@ MMap rval = 0; 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) ) { + if ( (off_t)-1 == lseek(fd, (off_t) FLD(c,(*shdr_p),sh_offset), SEEK_SET) ) { errlogPrintf("elfRead - getscn() -- seeking to sh_offset: %s\n", strerror(errno)); goto bail; } @@ -378,7 +382,7 @@ struct stat stat_b; } /* seek to section header table */ - if ( (off_t)-1 == lseek(es->fd, FLD(c,ehdr,e_shoff), SEEK_SET) ) { + if ( (off_t)-1 == lseek(es->fd, (off_t) FLD(c,ehdr,e_shoff), SEEK_SET) ) { errlogPrintf("elfRead() -- unable to seek to shoff: %s\n", strerror(errno)); goto bail; } @@ -397,7 +401,7 @@ struct stat stat_b; if ( i>=FLD(c,ehdr,e_shnum) ) { /* no SYMTAB -- try dynamic symbols */ - if ( (off_t)-1 == lseek(es->fd, FLD(c,ehdr,e_shoff), SEEK_SET) ) { + if ( (off_t)-1 == lseek(es->fd, (off_t) FLD(c,ehdr,e_shoff), SEEK_SET) ) { errlogPrintf("elfRead() -- unable to seek to shoff: %s\n", strerror(errno)); goto bail; } @@ -417,7 +421,7 @@ struct stat stat_b; goto bail; } - if ( 0 == (n=FLD(c,shdr,sh_size)) ) { + if ( 0 == (n = (ssize_t) FLD(c,shdr,sh_size)) ) { errlogPrintf("elfRead() -- no symbol table data\n"); goto bail; } @@ -434,7 +438,7 @@ struct stat stat_b; n = ELFCLASS32 == c ? sizeof(shdr.e32) : sizeof(shdr.e64); /* seek to section header table */ - if ( (off_t)-1 == lseek(es->fd, FLD(c,ehdr,e_shoff) + n * FLD(c,shdr,sh_link), SEEK_SET) ) { + if ( (off_t)-1 == lseek(es->fd, (off_t) (FLD(c,ehdr,e_shoff) + n * FLD(c,shdr,sh_link)), SEEK_SET) ) { errlogPrintf("elfRead() -- unable to lseek to ELF e_shoff: %s\n", strerror(errno)); goto bail; } From a018720511971fdd5638ce9837d547f4cdccb7ae Mon Sep 17 00:00:00 2001 From: Till Straumann Date: Fri, 19 Sep 2014 10:17:28 -0700 Subject: [PATCH 41/41] - use time() instead of clock_gettime(); - when comparing modification to program start time use >= instead of > --- src/libCom/osi/os/posix/osdElfFindAddr.cpp | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/libCom/osi/os/posix/osdElfFindAddr.cpp b/src/libCom/osi/os/posix/osdElfFindAddr.cpp index 69f136ee0..217101824 100644 --- a/src/libCom/osi/os/posix/osdElfFindAddr.cpp +++ b/src/libCom/osi/os/posix/osdElfFindAddr.cpp @@ -115,17 +115,7 @@ static ESyms elfs = 0; static epicsMutexId listMtx; static epicsThreadOnceId listMtxInitId = EPICS_THREAD_ONCE_INIT; -static time_t getStartTime() -{ -struct timespec ts; - - if ( clock_gettime(CLOCK_REALTIME, &ts) ) - return (time_t)0; - - return ts.tv_sec; -} - -static time_t prog_start_time = getStartTime(); +static time_t prog_start_time = time(0); extern "C" { @@ -370,7 +360,7 @@ struct stat stat_b; n -= EI_NIDENT; if ( 0 == fstat(es->fd, &stat_b) ) { - if ( stat_b.st_mtime > prog_start_time ) { + if ( stat_b.st_mtime >= prog_start_time ) { errlogPrintf("elfRead() -- WARNING: '%s' was modified after program start -- symbol information may be inaccurate or invalid\n", fname); } }