Annotation of embedaddon/strongswan/src/libstrongswan/utils/backtrace.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2006-2013 Martin Willi
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: * Copyright (C) 2013 revosec AG
! 5: *
! 6: * This program is free software; you can redistribute it and/or modify it
! 7: * under the terms of the GNU General Public License as published by the
! 8: * Free Software Foundation; either version 2 of the License, or (at your
! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 10: *
! 11: * This program is distributed in the hope that it will be useful, but
! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 14: * for more details.
! 15: */
! 16:
! 17: #define _GNU_SOURCE
! 18:
! 19: #ifdef HAVE_BACKTRACE
! 20: # include <execinfo.h>
! 21: #endif /* HAVE_BACKTRACE */
! 22: #ifdef HAVE_DBGHELP
! 23: # include <winsock2.h>
! 24: # include <windows.h>
! 25: # include <dbghelp.h>
! 26: #endif /* HAVE_DBGHELP */
! 27: #include <string.h>
! 28:
! 29: #include "backtrace.h"
! 30:
! 31: #include <utils/debug.h>
! 32:
! 33: #ifdef WIN32
! 34: # include <psapi.h>
! 35: /* missing in MinGW */
! 36: #ifdef WIN64
! 37: #ifndef GetModuleInformation
! 38: WINBOOL K32GetModuleInformation(HANDLE hProcess, HMODULE hModule,
! 39: LPMODULEINFO lpmodinfo, DWORD cb);
! 40: #define GetModuleInformation K32GetModuleInformation
! 41: #endif /* !GetModuleInformation */
! 42: #ifndef GetModuleFileNameEx
! 43: DWORD K32GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule,
! 44: LPTSTR lpFilename, DWORD nSize);
! 45: #define GetModuleFileNameEx K32GetModuleFileNameExA
! 46: #endif /* !GetModuleFileNameEx */
! 47: #endif /* WIN64 */
! 48: #endif
! 49:
! 50: typedef struct private_backtrace_t private_backtrace_t;
! 51:
! 52: /**
! 53: * Private data of an backtrace_t object.
! 54: */
! 55: struct private_backtrace_t {
! 56:
! 57: /**
! 58: * Public backtrace_t interface.
! 59: */
! 60: backtrace_t public;
! 61:
! 62: /**
! 63: * Number of stacks frames obtained in stack_frames
! 64: */
! 65: int frame_count;
! 66:
! 67: /**
! 68: * Recorded stack frames.
! 69: */
! 70: void *frames[];
! 71: };
! 72:
! 73: /**
! 74: * Forward declaration of method getter
! 75: */
! 76: static backtrace_t get_methods();
! 77:
! 78: /**
! 79: * Write a format string with arguments to a FILE line, if it is NULL to DBG
! 80: */
! 81: static void println(FILE *file, char *format, ...)
! 82: {
! 83: char buf[512];
! 84: va_list args;
! 85:
! 86: va_start(args, format);
! 87: if (file)
! 88: {
! 89: vfprintf(file, format, args);
! 90: fputs("\n", file);
! 91: }
! 92: else
! 93: {
! 94: vsnprintf(buf, sizeof(buf), format, args);
! 95: DBG1(DBG_LIB, "%s", buf);
! 96: }
! 97: va_end(args);
! 98: }
! 99:
! 100: /**
! 101: * Same as tty_escape_get(), but for a potentially NULL FILE*
! 102: */
! 103: static inline char* esc(FILE *file, tty_escape_t escape)
! 104: {
! 105: if (file)
! 106: {
! 107: return tty_escape_get(fileno(file), escape);
! 108: }
! 109: return "";
! 110: }
! 111:
! 112: #ifdef HAVE_DBGHELP
! 113:
! 114: #include <dbghelp.h>
! 115: #include <threading/mutex.h>
! 116:
! 117: /**
! 118: * Mutex to access non-thread-safe dbghelp functions
! 119: */
! 120: static mutex_t *dbghelp_mutex;
! 121:
! 122: void backtrace_init()
! 123: {
! 124: SymSetOptions(SYMOPT_LOAD_LINES);
! 125: SymInitialize(GetCurrentProcess(), NULL, TRUE);
! 126: dbghelp_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
! 127: }
! 128:
! 129: void backtrace_deinit()
! 130: {
! 131: dbghelp_mutex->destroy(dbghelp_mutex);
! 132: SymCleanup(GetCurrentProcess());
! 133: }
! 134:
! 135: #elif defined(HAVE_DLADDR) || defined(HAVE_BFD_H)
! 136:
! 137: #ifdef HAVE_DLADDR
! 138: #include <dlfcn.h>
! 139: #endif
! 140:
! 141: #ifdef HAVE_BFD_H
! 142:
! 143: #include <bfd.h>
! 144: #include <collections/hashtable.h>
! 145: #include <threading/mutex.h>
! 146:
! 147: /**
! 148: * Hashtable-cached bfd handle
! 149: */
! 150: typedef struct {
! 151: /** binary file name on disk */
! 152: char *filename;
! 153: /** bfd handle */
! 154: bfd *abfd;
! 155: /** loaded symbols */
! 156: asymbol **syms;
! 157: } bfd_entry_t;
! 158:
! 159: /**
! 160: * Destroy a bfd_entry
! 161: */
! 162: static void bfd_entry_destroy(bfd_entry_t *this)
! 163: {
! 164: free(this->filename);
! 165: free(this->syms);
! 166: bfd_close(this->abfd);
! 167: free(this);
! 168: }
! 169:
! 170: /**
! 171: * Data to pass to find_addr()
! 172: */
! 173: typedef struct {
! 174: /** used bfd entry */
! 175: bfd_entry_t *entry;
! 176: /** backtrace address */
! 177: bfd_vma vma;
! 178: /** stream to log to */
! 179: FILE *file;
! 180: /** TRUE if complete */
! 181: bool found;
! 182: } bfd_find_data_t;
! 183:
! 184: /**
! 185: * bfd entry cache
! 186: */
! 187: static hashtable_t *bfds;
! 188:
! 189: static mutex_t *bfd_mutex;
! 190:
! 191: /**
! 192: * Hashtable hash function
! 193: */
! 194: static u_int bfd_hash(char *key)
! 195: {
! 196: return chunk_hash(chunk_create(key, strlen(key)));
! 197: }
! 198:
! 199: /**
! 200: * Hashtable equals function
! 201: */
! 202: static bool bfd_equals(char *a, char *b)
! 203: {
! 204: return streq(a, b);
! 205: }
! 206:
! 207: /**
! 208: * See header.
! 209: */
! 210: void backtrace_init()
! 211: {
! 212: bfd_init();
! 213: bfds = hashtable_create((hashtable_hash_t)bfd_hash,
! 214: (hashtable_equals_t)bfd_equals, 8);
! 215: bfd_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
! 216: }
! 217:
! 218: /**
! 219: * See header.
! 220: */
! 221: void backtrace_deinit()
! 222: {
! 223: enumerator_t *enumerator;
! 224: bfd_entry_t *entry;
! 225: char *key;
! 226:
! 227: enumerator = bfds->create_enumerator(bfds);
! 228: while (enumerator->enumerate(enumerator, &key, &entry))
! 229: {
! 230: bfds->remove_at(bfds, enumerator);
! 231: bfd_entry_destroy(entry);
! 232: }
! 233: enumerator->destroy(enumerator);
! 234:
! 235: bfds->destroy(bfds);
! 236: bfd_mutex->destroy(bfd_mutex);
! 237: }
! 238:
! 239: /**
! 240: * Find and print information to an address
! 241: */
! 242: static void find_addr(bfd *abfd, asection *section, bfd_find_data_t *data)
! 243: {
! 244: bfd_size_type size;
! 245: bfd_vma vma;
! 246: const char *source;
! 247: const char *function;
! 248: char fbuf[512] = "", sbuf[512] = "";
! 249: u_int line;
! 250:
! 251: if (!data->found || (bfd_get_section_flags(abfd, section) & SEC_ALLOC) != 0)
! 252: {
! 253: vma = bfd_get_section_vma(abfd, section);
! 254: if (data->vma >= vma)
! 255: {
! 256: size = bfd_get_section_size(section);
! 257: if (data->vma < vma + size)
! 258: {
! 259: data->found = bfd_find_nearest_line(abfd, section,
! 260: data->entry->syms, data->vma - vma,
! 261: &source, &function, &line);
! 262: if (data->found)
! 263: {
! 264: if (source || function)
! 265: {
! 266: if (function)
! 267: {
! 268: snprintf(fbuf, sizeof(fbuf), "%s%s() ",
! 269: esc(data->file, TTY_FG_BLUE), function);
! 270: }
! 271: if (source)
! 272: {
! 273: snprintf(sbuf, sizeof(sbuf), "%s@ %s:%d",
! 274: esc(data->file, TTY_FG_GREEN), source, line);
! 275: }
! 276: println(data->file, " -> %s%s%s", fbuf, sbuf,
! 277: esc(data->file, TTY_FG_DEF));
! 278: }
! 279: }
! 280: }
! 281: }
! 282: }
! 283: }
! 284:
! 285: /**
! 286: * Find a cached bfd entry, create'n'cache if not found
! 287: */
! 288: static bfd_entry_t *get_bfd_entry(char *filename)
! 289: {
! 290: bool dynamic = FALSE, ok = FALSE;
! 291: bfd_entry_t *entry;
! 292: long size;
! 293:
! 294: /* check cache */
! 295: entry = bfds->get(bfds, filename);
! 296: if (entry)
! 297: {
! 298: return entry;
! 299: }
! 300:
! 301: INIT(entry,
! 302: .abfd = bfd_openr(filename, NULL),
! 303: );
! 304:
! 305: if (!entry->abfd)
! 306: {
! 307: free(entry);
! 308: return NULL;
! 309: }
! 310: #ifdef BFD_DECOMPRESS
! 311: entry->abfd->flags |= BFD_DECOMPRESS;
! 312: #endif
! 313: if (bfd_check_format(entry->abfd, bfd_archive) == 0 &&
! 314: bfd_check_format_matches(entry->abfd, bfd_object, NULL))
! 315: {
! 316: if (bfd_get_file_flags(entry->abfd) & HAS_SYMS)
! 317: {
! 318: size = bfd_get_symtab_upper_bound(entry->abfd);
! 319: if (size == 0)
! 320: {
! 321: size = bfd_get_dynamic_symtab_upper_bound(entry->abfd);
! 322: dynamic = TRUE;
! 323: }
! 324: if (size >= 0)
! 325: {
! 326: entry->syms = malloc(size);
! 327: if (dynamic)
! 328: {
! 329: ok = bfd_canonicalize_dynamic_symtab(entry->abfd,
! 330: entry->syms) >= 0;
! 331: }
! 332: else
! 333: {
! 334: ok = bfd_canonicalize_symtab(entry->abfd,
! 335: entry->syms) >= 0;
! 336: }
! 337: }
! 338: }
! 339: }
! 340: if (ok)
! 341: {
! 342: entry->filename = strdup(filename);
! 343: bfds->put(bfds, entry->filename, entry);
! 344: return entry;
! 345: }
! 346: bfd_entry_destroy(entry);
! 347: return NULL;
! 348: }
! 349:
! 350: /**
! 351: * Print the source file with line number to file, libbfd variant
! 352: */
! 353: static void print_sourceline(FILE *file, char *filename, void *ptr, void *base)
! 354: {
! 355: bfd_entry_t *entry;
! 356: bfd_find_data_t data = {
! 357: .file = file,
! 358: .vma = (uintptr_t)ptr,
! 359: };
! 360: bool old = FALSE;
! 361:
! 362: bfd_mutex->lock(bfd_mutex);
! 363: if (lib && lib->leak_detective)
! 364: {
! 365: old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
! 366: }
! 367: entry = get_bfd_entry(filename);
! 368: if (entry)
! 369: {
! 370: data.entry = entry;
! 371: bfd_map_over_sections(entry->abfd, (void*)find_addr, &data);
! 372: }
! 373: if (lib && lib->leak_detective)
! 374: {
! 375: lib->leak_detective->set_state(lib->leak_detective, old);
! 376: }
! 377: bfd_mutex->unlock(bfd_mutex);
! 378: }
! 379:
! 380: #else /* !HAVE_BFD_H */
! 381:
! 382: void backtrace_init() {}
! 383: void backtrace_deinit() {}
! 384:
! 385: /**
! 386: * Print the source file with line number to file, slow addr2line variant
! 387: */
! 388: static void print_sourceline(FILE *file, char *filename, void *ptr, void* base)
! 389: {
! 390: char buf[1024];
! 391: FILE *output;
! 392: int c, i = 0;
! 393:
! 394: #ifdef __APPLE__
! 395: snprintf(buf, sizeof(buf), "atos -o %s -l %p %p 2>&1 | tail -n1",
! 396: filename, base, ptr);
! 397: #else /* !__APPLE__ */
! 398: snprintf(buf, sizeof(buf), "addr2line -e %s %p", filename, ptr);
! 399: #endif /* __APPLE__ */
! 400:
! 401: output = popen(buf, "r");
! 402: if (output)
! 403: {
! 404: while (i < sizeof(buf))
! 405: {
! 406: c = getc(output);
! 407: if (c == '\n' || c == EOF)
! 408: {
! 409: buf[i++] = 0;
! 410: break;
! 411: }
! 412: buf[i++] = c;
! 413: }
! 414: pclose(output);
! 415:
! 416: println(file, " -> %s%s%s", esc(file, TTY_FG_GREEN), buf,
! 417: esc(file, TTY_FG_DEF));
! 418: }
! 419: }
! 420:
! 421: #endif /* HAVE_BFD_H */
! 422:
! 423: #else /* !HAVE_DLADDR && !HAVE_DBGHELP */
! 424:
! 425: void backtrace_init() {}
! 426: void backtrace_deinit() {}
! 427:
! 428: #endif /* HAVE_DLADDR */
! 429:
! 430: METHOD(backtrace_t, log_, void,
! 431: private_backtrace_t *this, FILE *file, bool detailed)
! 432: {
! 433: #if defined(HAVE_BACKTRACE) || defined(HAVE_LIBUNWIND_H) || defined(WIN32)
! 434: size_t i;
! 435: char **strings = NULL;
! 436:
! 437: println(file, " dumping %d stack frame addresses:", this->frame_count);
! 438: for (i = 0; i < this->frame_count; i++)
! 439: {
! 440: #ifdef HAVE_DLADDR
! 441: Dl_info info;
! 442:
! 443: if (dladdr(this->frames[i], &info))
! 444: {
! 445: void *ptr = this->frames[i];
! 446:
! 447: if (strstr(info.dli_fname, ".so"))
! 448: {
! 449: ptr = (void*)(this->frames[i] - info.dli_fbase);
! 450: }
! 451: if (info.dli_sname)
! 452: {
! 453: println(file, " %s%s%s @ %p (%s%s%s+0x%tx) [%p]",
! 454: esc(file, TTY_FG_YELLOW), info.dli_fname,
! 455: esc(file, TTY_FG_DEF), info.dli_fbase,
! 456: esc(file, TTY_FG_RED), info.dli_sname,
! 457: esc(file, TTY_FG_DEF), this->frames[i] - info.dli_saddr,
! 458: this->frames[i]);
! 459: }
! 460: else
! 461: {
! 462: println(file, " %s%s%s @ %p [%p]",
! 463: esc(file, TTY_FG_YELLOW), info.dli_fname,
! 464: esc(file, TTY_FG_DEF), info.dli_fbase, this->frames[i]);
! 465: }
! 466: if (detailed && info.dli_fname[0])
! 467: {
! 468: print_sourceline(file, (char*)info.dli_fname,
! 469: ptr, info.dli_fbase);
! 470: }
! 471: }
! 472: else
! 473: #elif defined(HAVE_DBGHELP)
! 474: struct {
! 475: SYMBOL_INFO hdr;
! 476: char buf[128];
! 477: } symbol;
! 478: char filename[MAX_PATH];
! 479: HINSTANCE module;
! 480: HANDLE process;
! 481: DWORD64 displace, frame;
! 482:
! 483: process = GetCurrentProcess();
! 484: frame = (uintptr_t)this->frames[i];
! 485:
! 486: memset(&symbol, 0, sizeof(symbol));
! 487: symbol.hdr.SizeOfStruct = sizeof(symbol.hdr);
! 488: symbol.hdr.MaxNameLen = sizeof(symbol.buf) - 1;
! 489:
! 490: dbghelp_mutex->lock(dbghelp_mutex);
! 491:
! 492: module = (HINSTANCE)SymGetModuleBase64(process, frame);
! 493:
! 494: if (module && GetModuleFileName(module, filename, sizeof(filename)))
! 495: {
! 496: if (SymFromAddr(process, frame, &displace, &symbol.hdr))
! 497: {
! 498: println(file, " %s%s%s @ %p (%s%s%s+0x%tx) [%p]",
! 499: esc(file, TTY_FG_YELLOW), filename,
! 500: esc(file, TTY_FG_DEF), (void*)module,
! 501: esc(file, TTY_FG_RED), symbol.hdr.Name,
! 502: esc(file, TTY_FG_DEF), displace,
! 503: this->frames[i]);
! 504: }
! 505: else
! 506: {
! 507: println(file, " %s%s%s @ %p [%p]",
! 508: esc(file, TTY_FG_YELLOW), filename,
! 509: esc(file, TTY_FG_DEF), (void*)module, this->frames[i]);
! 510: }
! 511: if (detailed)
! 512: {
! 513: IMAGEHLP_LINE64 line;
! 514: DWORD off;
! 515:
! 516: memset(&line, 0, sizeof(line));
! 517: line.SizeOfStruct = sizeof(line);
! 518:
! 519: if (SymGetLineFromAddr64(process, frame, &off, &line))
! 520: {
! 521:
! 522: println(file, " -> %s%s:%u%s", esc(file, TTY_FG_GREEN),
! 523: line.FileName, line.LineNumber,
! 524: esc(file, TTY_FG_DEF));
! 525: }
! 526: }
! 527: }
! 528: else
! 529: #elif defined(WIN32)
! 530: HMODULE module;
! 531: MODULEINFO info;
! 532: char filename[MAX_PATH];
! 533:
! 534: if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
! 535: this->frames[i], &module) &&
! 536: GetModuleInformation(GetCurrentProcess(), module,
! 537: &info, sizeof(info)) &&
! 538: GetModuleFileNameEx(GetCurrentProcess(), module,
! 539: filename, sizeof(filename)))
! 540: {
! 541: println(file, " %s%s%s @ %p [%p]",
! 542: esc(file, TTY_FG_YELLOW), filename,
! 543: esc(file, TTY_FG_DEF), info.lpBaseOfDll, this->frames[i]);
! 544: #ifdef HAVE_BFD_H
! 545: print_sourceline(file, filename, this->frames[i], info.lpBaseOfDll);
! 546: #endif /* HAVE_BFD_H */
! 547: }
! 548: else
! 549: #endif /* HAVE_DLADDR/HAVE_DBGHELP */
! 550: {
! 551: #ifdef HAVE_BACKTRACE
! 552: if (!strings)
! 553: {
! 554: strings = backtrace_symbols(this->frames, this->frame_count);
! 555: }
! 556: if (strings)
! 557: {
! 558: println(file, " %s", strings[i]);
! 559: }
! 560: else
! 561: #endif /* HAVE_BACKTRACE */
! 562: {
! 563: println(file, " %p", this->frames[i]);
! 564: }
! 565: }
! 566: #ifdef HAVE_DBGHELP
! 567: dbghelp_mutex->unlock(dbghelp_mutex);
! 568: #endif
! 569: }
! 570: free(strings);
! 571: #else /* !HAVE_BACKTRACE && !HAVE_LIBUNWIND_H */
! 572: println(file, "no support for capturing backtraces");
! 573: #endif /* HAVE_BACKTRACE/HAVE_LIBUNWIND_H */
! 574: }
! 575:
! 576: METHOD(backtrace_t, contains_function, bool,
! 577: private_backtrace_t *this, char *function[], int count)
! 578: {
! 579: #ifdef HAVE_DLADDR
! 580: int i, j;
! 581:
! 582: for (i = 0; i< this->frame_count; i++)
! 583: {
! 584: Dl_info info;
! 585:
! 586: if (dladdr(this->frames[i], &info) && info.dli_sname)
! 587: {
! 588: for (j = 0; j < count; j++)
! 589: {
! 590: if (streq(info.dli_sname, function[j]))
! 591: {
! 592: return TRUE;
! 593: }
! 594: }
! 595: }
! 596: }
! 597: #elif defined(HAVE_DBGHELP)
! 598: int i, j;
! 599: HANDLE process;
! 600:
! 601: process = GetCurrentProcess();
! 602:
! 603: dbghelp_mutex->lock(dbghelp_mutex);
! 604:
! 605: for (i = 0; i < this->frame_count; i++)
! 606: {
! 607: struct {
! 608: SYMBOL_INFO hdr;
! 609: char buf[128];
! 610: } symbol;
! 611:
! 612: memset(&symbol, 0, sizeof(symbol));
! 613: symbol.hdr.SizeOfStruct = sizeof(symbol.hdr);
! 614: symbol.hdr.MaxNameLen = sizeof(symbol.buf) - 1;
! 615:
! 616: if (SymFromAddr(process, (DWORD64)this->frames[i], NULL, &symbol.hdr))
! 617: {
! 618: for (j = 0; j < count; j++)
! 619: {
! 620: if (streq(symbol.hdr.Name, function[j]))
! 621: {
! 622: dbghelp_mutex->unlock(dbghelp_mutex);
! 623: return TRUE;
! 624: }
! 625: }
! 626: }
! 627: }
! 628:
! 629: dbghelp_mutex->unlock(dbghelp_mutex);
! 630: #endif /* HAVE_DLADDR/HAVE_DBGHELP */
! 631: return FALSE;
! 632: }
! 633:
! 634: METHOD(backtrace_t, equals, bool,
! 635: private_backtrace_t *this, backtrace_t *other_public)
! 636: {
! 637: private_backtrace_t *other = (private_backtrace_t*)other_public;
! 638: int i;
! 639:
! 640: if (this == other)
! 641: {
! 642: return TRUE;
! 643: }
! 644: if (this->frame_count != other->frame_count)
! 645: {
! 646: return FALSE;
! 647: }
! 648: for (i = 0; i < this->frame_count; i++)
! 649: {
! 650: if (this->frames[i] != other->frames[i])
! 651: {
! 652: return FALSE;
! 653: }
! 654: }
! 655: return TRUE;
! 656: }
! 657:
! 658: /**
! 659: * Frame enumerator
! 660: */
! 661: typedef struct {
! 662: /** implements enumerator_t */
! 663: enumerator_t public;
! 664: /** reference to backtrace */
! 665: private_backtrace_t *bt;
! 666: /** current position */
! 667: int i;
! 668: } frame_enumerator_t;
! 669:
! 670: METHOD(enumerator_t, frame_enumerate, bool,
! 671: frame_enumerator_t *this, va_list args)
! 672: {
! 673: void **addr;
! 674:
! 675: VA_ARGS_VGET(args, addr);
! 676:
! 677: if (this->i < this->bt->frame_count)
! 678: {
! 679: *addr = this->bt->frames[this->i++];
! 680: return TRUE;
! 681: }
! 682: return FALSE;
! 683: }
! 684:
! 685: METHOD(backtrace_t, create_frame_enumerator, enumerator_t*,
! 686: private_backtrace_t *this)
! 687: {
! 688: frame_enumerator_t *enumerator;
! 689:
! 690: INIT(enumerator,
! 691: .public = {
! 692: .enumerate = enumerator_enumerate_default,
! 693: .venumerate = _frame_enumerate,
! 694: .destroy = (void*)free,
! 695: },
! 696: .bt = this,
! 697: );
! 698: return &enumerator->public;
! 699: }
! 700:
! 701: METHOD(backtrace_t, clone_, backtrace_t*,
! 702: private_backtrace_t *this)
! 703: {
! 704: private_backtrace_t *clone;
! 705:
! 706: clone = malloc(sizeof(private_backtrace_t) +
! 707: this->frame_count * sizeof(void*));
! 708: memcpy(clone->frames, this->frames, this->frame_count * sizeof(void*));
! 709: clone->frame_count = this->frame_count;
! 710:
! 711: clone->public = get_methods();
! 712:
! 713: return &clone->public;
! 714: }
! 715:
! 716: METHOD(backtrace_t, destroy, void,
! 717: private_backtrace_t *this)
! 718: {
! 719: free(this);
! 720: }
! 721:
! 722: #ifdef HAVE_LIBUNWIND_H
! 723: #define UNW_LOCAL_ONLY
! 724: #include <libunwind.h>
! 725:
! 726: /**
! 727: * libunwind variant for glibc backtrace()
! 728: */
! 729: static inline int backtrace_unwind(void **frames, int count)
! 730: {
! 731: unw_context_t context;
! 732: unw_cursor_t cursor;
! 733: unw_word_t ip;
! 734: int depth = 0;
! 735:
! 736: unw_getcontext(&context);
! 737: unw_init_local(&cursor, &context);
! 738: do
! 739: {
! 740: unw_get_reg(&cursor, UNW_REG_IP, &ip);
! 741: frames[depth++] = (void*)ip;
! 742: }
! 743: while (depth < count && unw_step(&cursor) > 0);
! 744:
! 745: return depth;
! 746: }
! 747: #endif /* HAVE_UNWIND */
! 748:
! 749: #ifdef HAVE_DBGHELP
! 750:
! 751: /**
! 752: * Windows dbghelp variant for glibc backtrace()
! 753: */
! 754: static inline int backtrace_win(void **frames, int count)
! 755: {
! 756: STACKFRAME frame;
! 757: HANDLE process, thread;
! 758: DWORD machine;
! 759: CONTEXT context;
! 760: int got = 0;
! 761:
! 762: memset(&frame, 0, sizeof(frame));
! 763: memset(&context, 0, sizeof(context));
! 764:
! 765: process = GetCurrentProcess();
! 766: thread = GetCurrentThread();
! 767:
! 768: #ifdef __x86_64
! 769: machine = IMAGE_FILE_MACHINE_AMD64;
! 770:
! 771: frame.AddrPC.Offset = context.Rip;
! 772: frame.AddrPC.Mode = AddrModeFlat;
! 773: frame.AddrStack.Offset = context.Rsp;
! 774: frame.AddrStack.Mode = AddrModeFlat;
! 775: frame.AddrFrame.Offset = context.Rbp;
! 776: frame.AddrFrame.Mode = AddrModeFlat;
! 777: #else /* x86 */
! 778: machine = IMAGE_FILE_MACHINE_I386;
! 779:
! 780: frame.AddrPC.Offset = context.Eip;
! 781: frame.AddrPC.Mode = AddrModeFlat;
! 782: frame.AddrStack.Offset = context.Esp;
! 783: frame.AddrStack.Mode = AddrModeFlat;
! 784: frame.AddrFrame.Offset = context.Ebp;
! 785: frame.AddrFrame.Mode = AddrModeFlat;
! 786: #endif /* x86_64/x86 */
! 787:
! 788: dbghelp_mutex->lock(dbghelp_mutex);
! 789:
! 790: RtlCaptureContext(&context);
! 791:
! 792: while (got < count)
! 793: {
! 794: if (!StackWalk64(machine, process, thread, &frame, &context,
! 795: NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))
! 796: {
! 797: break;
! 798: }
! 799: frames[got++] = (void*)frame.AddrPC.Offset;
! 800: }
! 801:
! 802: dbghelp_mutex->unlock(dbghelp_mutex);
! 803:
! 804: return got;
! 805: }
! 806:
! 807: #endif /* HAVE_DBGHELP */
! 808:
! 809: /**
! 810: * Get implementation methods of backtrace_t
! 811: */
! 812: static backtrace_t get_methods()
! 813: {
! 814: return (backtrace_t) {
! 815: .log = _log_,
! 816: .contains_function = _contains_function,
! 817: .equals = _equals,
! 818: .clone = _clone_,
! 819: .create_frame_enumerator = _create_frame_enumerator,
! 820: .destroy = _destroy,
! 821: };
! 822: }
! 823:
! 824: /**
! 825: * See header
! 826: */
! 827: backtrace_t *backtrace_create(int skip)
! 828: {
! 829: private_backtrace_t *this;
! 830: void *frames[50];
! 831: int frame_count = 0;
! 832:
! 833: #ifdef HAVE_LIBUNWIND_H
! 834: frame_count = backtrace_unwind(frames, countof(frames));
! 835: #elif defined(HAVE_BACKTRACE)
! 836: frame_count = backtrace(frames, countof(frames));
! 837: #elif defined(HAVE_DBGHELP)
! 838: frame_count = backtrace_win(frames, countof(frames));
! 839: #elif defined(WIN32)
! 840: frame_count = CaptureStackBackTrace(skip, countof(frames), frames, NULL);
! 841: skip = 0;
! 842: #endif
! 843: frame_count = max(frame_count - skip, 0);
! 844: this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*));
! 845: memcpy(this->frames, frames + skip, frame_count * sizeof(void*));
! 846: this->frame_count = frame_count;
! 847:
! 848: this->public = get_methods();
! 849:
! 850: return &this->public;
! 851: }
! 852:
! 853: /**
! 854: * See header
! 855: */
! 856: void backtrace_dump(char *label, FILE *file, bool detailed)
! 857: {
! 858: backtrace_t *backtrace;
! 859:
! 860: backtrace = backtrace_create(2);
! 861:
! 862: if (label)
! 863: {
! 864: println(file, "Debug backtrace: %s", label);
! 865: }
! 866: backtrace->log(backtrace, file, detailed);
! 867: backtrace->destroy(backtrace);
! 868: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>