annotate doodle/core/backtrace.d @ 45:01bbf3f6f966

Cleanups
author daveb
date Mon, 02 Aug 2010 14:44:12 +0930
parents 2b9329ed0f0e
children dfa1e219eafe
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
44
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
1 module doodle.core.backtrace;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
2
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
3 //
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
4 // Provides support for a readable backtrace on a program crash.
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
5 //
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
6 // Everything is private - you build this into a library and
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
7 // link to the library, and bingo (via static this).
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
8 //
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
9 // It works by registering a stacktrace handler with the runtime,
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
10 // which, unlike the default one, provides demangled symbols
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
11 // rather than just a list of addresses.
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
12 //
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
13
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
14 private {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
15 import core.sys.posix.unistd;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
16 import core.sys.posix.fcntl;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
17 import core.sys.posix.sys.stat;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
18 import core.sys.posix.sys.mman;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
19
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
20 import core.stdc.string;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
21 import core.stdc.signal;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
22
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
23 import core.runtime;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
24
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
25 import std.stdio;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
26 import std.string;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
27 import std.demangle;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
28 import std.algorithm;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
29
45
01bbf3f6f966 Cleanups
daveb
parents: 44
diff changeset
30 immutable int EI_NIDENT = 16;
44
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
31
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
32 immutable int SHT_SYMTAB = 2;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
33 immutable int SHT_STRTAB = 3;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
34
45
01bbf3f6f966 Cleanups
daveb
parents: 44
diff changeset
35 immutable int STT_FUNC = 2;
44
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
36
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
37 alias ushort Elf32_Half;
45
01bbf3f6f966 Cleanups
daveb
parents: 44
diff changeset
38 alias uint Elf32_Word;
01bbf3f6f966 Cleanups
daveb
parents: 44
diff changeset
39 alias uint Elf32_Addr;
01bbf3f6f966 Cleanups
daveb
parents: 44
diff changeset
40 alias uint Elf32_Off;
44
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
41 alias ushort Elf32_Section;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
42
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
43 struct Elf32_Ehdr {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
44 ubyte[EI_NIDENT] e_ident; /* Magic number and other info */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
45 Elf32_Half e_type; /* Object file type */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
46 Elf32_Half e_machine; /* Architecture */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
47 Elf32_Word e_version; /* Object file version */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
48 Elf32_Addr e_entry; /* Entry point virtual address */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
49 Elf32_Off e_phoff; /* Program header table file offset */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
50 Elf32_Off e_shoff; /* Section header table file offset */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
51 Elf32_Word e_flags; /* Processor-specific flags */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
52 Elf32_Half e_ehsize; /* ELF header size in bytes */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
53 Elf32_Half e_phentsize; /* Program header table entry size */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
54 Elf32_Half e_phnum; /* Program header table entry count */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
55 Elf32_Half e_shentsize; /* Section header table entry size */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
56 Elf32_Half e_shnum; /* Section header table entry count */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
57 Elf32_Half e_shstrndx; /* Section header string table index */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
58 };
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
59
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
60 struct Elf32_Shdr {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
61 Elf32_Word sh_name; /* Section name (string tbl index) */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
62 Elf32_Word sh_type; /* Section type */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
63 Elf32_Word sh_flags; /* Section flags */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
64 Elf32_Addr sh_addr; /* Section virtual addr at execution */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
65 Elf32_Off sh_offset; /* Section file offset */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
66 Elf32_Word sh_size; /* Section size in bytes */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
67 Elf32_Word sh_link; /* Link to another section */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
68 Elf32_Word sh_info; /* Additional section information */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
69 Elf32_Word sh_addralign; /* Section alignment */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
70 Elf32_Word sh_entsize; /* Entry size if section holds table */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
71 };
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
72
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
73 struct Elf32_Sym {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
74 Elf32_Word st_name; /* Symbol name (string tbl index) */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
75 Elf32_Addr st_value; /* Symbol value */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
76 Elf32_Word st_size; /* Symbol size */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
77 ubyte st_info; /* Symbol type and binding */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
78 ubyte st_other; /* Symbol visibility */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
79 Elf32_Section st_shndx; /* Section index */
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
80 };
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
81
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
82 extern (C) int backtrace(void**, size_t);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
83
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
84 struct Symbol {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
85 this(void * a, size_t s, char * n) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
86 address = a;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
87 size = s;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
88 name = n;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
89 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
90 void * address;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
91 size_t size;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
92 char * name;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
93 void * end_address() { return address + size; }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
94 };
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
95
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
96 // Newton-Raphson
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
97 Symbol nr_lookup(Symbol[] symbols, void * addr, int depth = 0) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
98 if (symbols.length == 0 ||
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
99 addr < symbols[0].address ||
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
100 addr >= symbols[$-1].end_address)
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
101 {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
102 throw new Exception("Symbol not found");
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
103 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
104 else if (symbols.length == 1) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
105 return symbols[0];
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
106 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
107 else {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
108 void * begin_addr = symbols[0].address;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
109 void * end_addr = symbols[$-1].end_address;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
110
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
111 int i = ((addr - begin_addr) * symbols.length) / (end_addr - begin_addr);
45
01bbf3f6f966 Cleanups
daveb
parents: 44
diff changeset
112 if (!(depth % 2) && i < symbols.length - 1) { ++i; } // Some wiggle to force convergence
44
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
113
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
114 if (addr < symbols[i].address) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
115 return nr_lookup(symbols[0..i], addr, depth + 1);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
116 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
117 else {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
118 return nr_lookup(symbols[i..$], addr, depth + 1);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
119 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
120 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
121 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
122
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
123 int generate(void*[] addresses, scope int delegate(ref char[]) dg) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
124 static char[] get_exe() {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
125 char buf[1024];
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
126 ssize_t s = readlink("/proc/self/exe", buf.ptr, buf.length);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
127 if (s == -1) { throw new Exception(""); }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
128 return buf[0..s];
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
129 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
130
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
131 int fd = open(toStringz(get_exe()), O_RDONLY);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
132 if (fd == -1) { throw new Exception(""); }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
133 scope(exit) close(fd);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
134
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
135 stat_t st;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
136 if (fstat(fd, &st) == -1) { throw new Exception(""); }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
137
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
138 void * contents = mmap(null, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
139 if (!contents) { throw new Exception(""); }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
140 scope(exit) munmap(contents, st.st_size);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
141
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
142 Elf32_Ehdr * elf_hdr = cast(Elf32_Ehdr *)(contents);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
143
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
144 Elf32_Shdr * sec_hdr = cast(Elf32_Shdr *)(contents + elf_hdr.e_shoff);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
145
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
146 int symtab_idx = 0;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
147 for (int i = 0; i < elf_hdr.e_shnum; ++i) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
148 if (sec_hdr[i].sh_type == SHT_SYMTAB) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
149 symtab_idx = i;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
150 break;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
151 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
152 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
153 if (symtab_idx == 0) { throw new Exception(""); }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
154
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
155 int strtab_idx = sec_hdr[symtab_idx].sh_link;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
156 if (strtab_idx == 0) { throw new Exception(""); } // No associated string table
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
157
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
158 if (sec_hdr[strtab_idx].sh_type != SHT_STRTAB) { throw new Exception(""); } // invalid string table
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
159
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
160 Elf32_Sym * sym_ent = cast(Elf32_Sym *)(contents + sec_hdr[symtab_idx].sh_offset);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
161 char * strtab = cast(char *)(contents + sec_hdr[strtab_idx].sh_offset);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
162 int num_syms = sec_hdr[symtab_idx].sh_size / sec_hdr[symtab_idx].sh_entsize;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
163
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
164 if (num_syms == 0) { throw new Exception(""); } // No symbols
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
165
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
166 Symbol symbols[];
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
167
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
168 for (int i = 0; i < num_syms; ++i) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
169 if ((sym_ent[i].st_info & 0xf) != STT_FUNC) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
170 continue;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
171 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
172
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
173 if (sym_ent[i].st_shndx == 0) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
174 continue;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
175 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
176
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
177 void * address = cast(void *)(sym_ent[i].st_value); // inclusive
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
178 size_t size = sym_ent[i].st_size;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
179 char * name = strtab + sym_ent[i].st_name;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
180
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
181 symbols ~= Symbol(address, size, name);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
182 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
183
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
184 sort!("a.address < b.address")(symbols);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
185
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
186 int ret;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
187 foreach (address; addresses) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
188 string str = format("[0x%0.8x] ", address);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
189 try {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
190 Symbol symbol = nr_lookup(symbols, address);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
191 char[] s1 = symbol.name[0..strlen(symbol.name)];
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
192 str ~= format("%s", demangle(s1.idup));
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
193 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
194 catch (Exception e) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
195 str ~= "<unknown>";
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
196 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
197 char[] cstr = str.dup;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
198 ret = dg(cstr);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
199 if (ret) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
200 break;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
201 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
202 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
203
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
204 return ret;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
205 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
206
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
207
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
208 // signal handler for otherwise-fatal thread-specific signals
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
209 extern (C) void arghh(int sig) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
210 string name() {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
211 switch (sig) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
212 case SIGSEGV: return "SIGSEGV";
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
213 case SIGFPE: return "SIGFPE";
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
214 case SIGILL: return "SIGILL";
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
215 case SIGABRT: return "SIGABRT";
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
216 default: return "";
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
217 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
218 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
219
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
220 throw new Error(format("Got signal %s %s", sig, name));
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
221 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
222
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
223 shared static this() {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
224 // set up shared signal handlers for fatal thread-specific signals
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
225 //writeln("setting up shared signal handlers for ABRT, FPE, ILL, SEGV");
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
226 signal(SIGABRT, &arghh);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
227 signal(SIGFPE, &arghh);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
228 signal(SIGILL, &arghh);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
229 signal(SIGSEGV, &arghh);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
230 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
231
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
232 static this() {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
233 // register our trace handler for each thread
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
234 //writeln("installing our traceHandler");
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
235 Runtime.traceHandler = &traceHandler;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
236 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
237
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
238 // Captures backtrace info at the point of construction, stripping
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
239 // off the bits that concern itself and the ininteresting early stuff.
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
240 // Also provides opApply to traverse a nice text representation of the backtrace.
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
241 class TraceInfo : Throwable.TraceInfo {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
242 void*[256] callstack;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
243 int numframes;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
244
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
245 this() {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
246 numframes = backtrace(callstack.ptr, callstack.length);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
247 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
248
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
249 override string toString() const {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
250 return "Why does dmd require an override of this?";
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
251 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
252
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
253 override int opApply(scope int delegate(ref char[]) dg) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
254 return generate(callstack[4..numframes-5], dg);
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
255 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
256 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
257
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
258 Throwable.TraceInfo traceHandler(void * ptr = null) {
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
259 return new TraceInfo;
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
260 }
2b9329ed0f0e Added backtrace support
"David Bryant <bagnose@gmail.com>"
parents:
diff changeset
261 }