/* dbug - resolve symbols and print stack traces * Copyright (c) 2004 Michael B. Allen * * The MIT License * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include #include #if defined(_GNU_SOURCE) && defined(__i386__) #include #include #include "mba/path.h" #include "mba/text.h" int dbug_stacktrace(void **buf, int off, int n) { int i; void *_buf[16]; if (n < 1 || n > 15) { n = 15; } off++; n = backtrace(_buf, n + off); for (i = off; i < n; i++) { buf[i - off] = _buf[i]; } return i - off; } /* Put 'fname\0sname\0' into buf and return pointer to sname * Put '\0hexval\0' into buf and return pointer to hexval if * sym cannot be resolved */ unsigned char * dbug_resolve_symbol(void *sym, unsigned char *buf, unsigned char *blim) { Dl_info info; const char *name; if (dladdr(sym, &info) == 0) { *buf++ = '\0'; /* no filename */ dsnprintf(buf, blim - buf, "%p", sym); return buf; } name = info.dli_fname; name = path_name((unsigned char *)name, (unsigned char *)name + 255, '/'); buf += str_copy(name, name + 255, buf, blim, -1) + 1; name = info.dli_sname; str_copy(name, name + 255, buf, blim, -1); return buf; } int dbug_sprint_stacktrace(unsigned char *str, unsigned char *slim, void **syms, int sn, const unsigned char *msg) { unsigned char *start = str; const unsigned char *pad = ": \n", *in = pad + 1, *nl = pad + 3; int si = 0; while (si < sn) { unsigned char buf[1024], *blim = buf + 1024, *sname; sname = dbug_resolve_symbol(syms[si++], buf, blim); *(sname - 1) = ':'; str += str_copy(buf, blim, str, slim, -1); if (si == 1 && msg) { str += str_copy(pad, pad + 3, str, slim, 2); str += str_copy(msg, msg + 1024, str, slim, -1); } str += str_copy(nl, nl + 2, str, slim, 1); if (si == sn) { break; } str += str_copy(in, in + 3, str, slim, 2); } return str - start; } int dbug_fprint_stacktrace(FILE *stream, int off, int n, const char *msg) { void *syms[16]; unsigned char str[1024]; n = dbug_stacktrace(syms, off, n + 1); if (n && (n = dbug_sprint_stacktrace(str, str + 1024, syms + 1, n - 1, msg)) == -1) { return -1; } fwrite(str, 1, n, stream); fflush(stream); return 0; } #else /* backtraces not supported - emit stub implementation */ int dbug_stacktrace(void **buf, int off, int n) { (void)buf; (void)off; (void)n; return 0; } unsigned char * dbug_resolve_symbol(void *sym, unsigned char *buf, unsigned char *blim) { (void)sym; (void)buf; (void)blim; return NULL; } int dbug_sprint_stacktrace(unsigned char *str, unsigned char *slim, void **syms, int sn, const unsigned char *msg) { (void)str; (void)slim; (void)syms; (void)sn; (void)msg; return 0; } int dbug_fprint_stacktrace(FILE *stream, int off, int n, const char *msg) { (void)stream; (void)off; (void)n; (void)msg; return 0; } #endif