Mercurial > projects > doodle
changeset 50:dfa1e219eafe
New version of backtrace based on the one in druntime.
Note, you must have -L--export-dynamic in dmd.conf for symbols
to be resolved.
author | daveb |
---|---|
date | Wed, 04 Aug 2010 16:36:07 +0930 |
parents | 1b4c9ba58673 |
children | 0eaf39fda206 |
files | doodle/core/backtrace.d |
diffstat | 1 files changed, 58 insertions(+), 217 deletions(-) [+] |
line wrap: on
line diff
--- a/doodle/core/backtrace.d Tue Aug 03 17:37:21 2010 +0930 +++ b/doodle/core/backtrace.d Wed Aug 04 16:36:07 2010 +0930 @@ -12,201 +12,19 @@ // private { - import core.sys.posix.unistd; - import core.sys.posix.fcntl; - import core.sys.posix.sys.stat; - import core.sys.posix.sys.mman; - - import core.stdc.string; - import core.stdc.signal; - - import core.runtime; - - import std.stdio; - import std.string; - import std.demangle; - import std.algorithm; - - immutable int EI_NIDENT = 16; - - immutable int SHT_SYMTAB = 2; - immutable int SHT_STRTAB = 3; - - immutable int STT_FUNC = 2; - - alias ushort Elf32_Half; - alias uint Elf32_Word; - alias uint Elf32_Addr; - alias uint Elf32_Off; - alias ushort Elf32_Section; - - struct Elf32_Ehdr { - ubyte[EI_NIDENT] e_ident; /* Magic number and other info */ - Elf32_Half e_type; /* Object file type */ - Elf32_Half e_machine; /* Architecture */ - Elf32_Word e_version; /* Object file version */ - Elf32_Addr e_entry; /* Entry point virtual address */ - Elf32_Off e_phoff; /* Program header table file offset */ - Elf32_Off e_shoff; /* Section header table file offset */ - Elf32_Word e_flags; /* Processor-specific flags */ - Elf32_Half e_ehsize; /* ELF header size in bytes */ - Elf32_Half e_phentsize; /* Program header table entry size */ - Elf32_Half e_phnum; /* Program header table entry count */ - Elf32_Half e_shentsize; /* Section header table entry size */ - Elf32_Half e_shnum; /* Section header table entry count */ - Elf32_Half e_shstrndx; /* Section header string table index */ - }; - - struct Elf32_Shdr { - Elf32_Word sh_name; /* Section name (string tbl index) */ - Elf32_Word sh_type; /* Section type */ - Elf32_Word sh_flags; /* Section flags */ - Elf32_Addr sh_addr; /* Section virtual addr at execution */ - Elf32_Off sh_offset; /* Section file offset */ - Elf32_Word sh_size; /* Section size in bytes */ - Elf32_Word sh_link; /* Link to another section */ - Elf32_Word sh_info; /* Additional section information */ - Elf32_Word sh_addralign; /* Section alignment */ - Elf32_Word sh_entsize; /* Entry size if section holds table */ - }; - - struct Elf32_Sym { - Elf32_Word st_name; /* Symbol name (string tbl index) */ - Elf32_Addr st_value; /* Symbol value */ - Elf32_Word st_size; /* Symbol size */ - ubyte st_info; /* Symbol type and binding */ - ubyte st_other; /* Symbol visibility */ - Elf32_Section st_shndx; /* Section index */ - }; - - extern (C) int backtrace(void**, size_t); - - struct Symbol { - this(void * a, size_t s, char * n) { - address = a; - size = s; - name = n; - } - void * address; - size_t size; - char * name; - void * end_address() { return address + size; } - }; - - // Newton-Raphson - Symbol nr_lookup(Symbol[] symbols, void * addr, int depth = 0) { - if (symbols.length == 0 || - addr < symbols[0].address || - addr >= symbols[$-1].end_address) - { - throw new Exception("Symbol not found"); - } - else if (symbols.length == 1) { - return symbols[0]; - } - else { - void * begin_addr = symbols[0].address; - void * end_addr = symbols[$-1].end_address; - int i = ((addr - begin_addr) * symbols.length) / (end_addr - begin_addr); - if (!(depth % 2) && i < symbols.length - 1) { ++i; } // Some wiggle to force convergence - - if (addr < symbols[i].address) { - return nr_lookup(symbols[0..i], addr, depth + 1); - } - else { - return nr_lookup(symbols[i..$], addr, depth + 1); - } - } - } - - int generate(void*[] addresses, scope int delegate(ref char[]) dg) { - static char[] get_exe() { - char buf[1024]; - ssize_t s = readlink("/proc/self/exe", buf.ptr, buf.length); - if (s == -1) { throw new Exception(""); } - return buf[0..s]; - } - - int fd = open(toStringz(get_exe()), O_RDONLY); - if (fd == -1) { throw new Exception(""); } - scope(exit) close(fd); - - stat_t st; - if (fstat(fd, &st) == -1) { throw new Exception(""); } - - void * contents = mmap(null, st.st_size, PROT_READ, MAP_SHARED, fd, 0); - if (!contents) { throw new Exception(""); } - scope(exit) munmap(contents, st.st_size); - - Elf32_Ehdr * elf_hdr = cast(Elf32_Ehdr *)(contents); - - Elf32_Shdr * sec_hdr = cast(Elf32_Shdr *)(contents + elf_hdr.e_shoff); - - int symtab_idx = 0; - for (int i = 0; i < elf_hdr.e_shnum; ++i) { - if (sec_hdr[i].sh_type == SHT_SYMTAB) { - symtab_idx = i; - break; - } - } - if (symtab_idx == 0) { throw new Exception(""); } - - int strtab_idx = sec_hdr[symtab_idx].sh_link; - if (strtab_idx == 0) { throw new Exception(""); } // No associated string table + import core.stdc.signal; + import core.stdc.stdlib : free; + import core.stdc.string : strlen; + import core.runtime; + import std.demangle; + import std.string; - if (sec_hdr[strtab_idx].sh_type != SHT_STRTAB) { throw new Exception(""); } // invalid string table - - Elf32_Sym * sym_ent = cast(Elf32_Sym *)(contents + sec_hdr[symtab_idx].sh_offset); - char * strtab = cast(char *)(contents + sec_hdr[strtab_idx].sh_offset); - int num_syms = sec_hdr[symtab_idx].sh_size / sec_hdr[symtab_idx].sh_entsize; - - if (num_syms == 0) { throw new Exception(""); } // No symbols - - Symbol symbols[]; - - for (int i = 0; i < num_syms; ++i) { - if ((sym_ent[i].st_info & 0xf) != STT_FUNC) { - continue; - } - - if (sym_ent[i].st_shndx == 0) { - continue; - } - - void * address = cast(void *)(sym_ent[i].st_value); // inclusive - size_t size = sym_ent[i].st_size; - char * name = strtab + sym_ent[i].st_name; - - symbols ~= Symbol(address, size, name); - } - - sort!("a.address < b.address")(symbols); - - int ret; - foreach (address; addresses) { - string str = format("[0x%0.8x] ", address); - try { - Symbol symbol = nr_lookup(symbols, address); - char[] s1 = symbol.name[0..strlen(symbol.name)]; - str ~= format("%s", demangle(s1.idup)); - } - catch (Exception e) { - str ~= "<unknown>"; - } - char[] cstr = str.dup; - ret = dg(cstr); - if (ret) { - break; - } - } - - return ret; - } - + extern (C) int backtrace(void**, size_t); + extern (C) char** backtrace_symbols(void**, int); // signal handler for otherwise-fatal thread-specific signals - extern (C) void arghh(int sig) { + extern (C) void signal_handler(int sig) { string name() { switch (sig) { case SIGSEGV: return "SIGSEGV"; @@ -222,40 +40,63 @@ shared static this() { // set up shared signal handlers for fatal thread-specific signals - //writeln("setting up shared signal handlers for ABRT, FPE, ILL, SEGV"); - signal(SIGABRT, &arghh); - signal(SIGFPE, &arghh); - signal(SIGILL, &arghh); - signal(SIGSEGV, &arghh); + signal(SIGABRT, &signal_handler); + signal(SIGFPE, &signal_handler); + signal(SIGILL, &signal_handler); + signal(SIGSEGV, &signal_handler); } static this() { // register our trace handler for each thread - //writeln("installing our traceHandler"); Runtime.traceHandler = &traceHandler; } - // Captures backtrace info at the point of construction, stripping - // off the bits that concern itself and the ininteresting early stuff. - // Also provides opApply to traverse a nice text representation of the backtrace. - class TraceInfo : Throwable.TraceInfo { - void*[256] callstack; - int numframes; - - this() { - numframes = backtrace(callstack.ptr, callstack.length); - } - - override string toString() const { - return "Why does dmd require an override of this?"; - } - - override int opApply(scope int delegate(ref char[]) dg) { - return generate(callstack[4..numframes-5], dg); - } - } - Throwable.TraceInfo traceHandler(void * ptr = null) { return new TraceInfo; } + + class TraceInfo : Throwable.TraceInfo { + this() { + immutable MAXFRAMES = 128; + void*[MAXFRAMES] callstack; + + numframes = backtrace(callstack.ptr, MAXFRAMES); + framelist = backtrace_symbols(callstack.ptr, numframes); + } + + ~this() { + free(framelist); + } + + override string toString() const { return null; } // Why does toString require overriding? + + override int opApply(scope int delegate(ref char[]) dg) { + // NOTE: The first 5 frames with the current implementation are + // inside core.runtime and the object code, so eliminate + // these for readability. + immutable FIRSTFRAME = 5; + int ret = 0; + + for(int i = FIRSTFRAME; i < numframes; ++i) { + char[] text = framelist[i][0 .. strlen(framelist[i])]; + + int a = text.lastIndexOf('('); + int b = text.lastIndexOf('+'); + + if (a != -1 && b != -1) { + ++a; + text = format("%s%s%s", text[0..a], demangle(text[a..b].idup), text[b..$]).dup; + } + + ret = dg(text); + if (ret) + break; + } + return ret; + } + + private: + int numframes; + char** framelist; + } }