1 module d.rt.dwarf;
2 
3 import d.rt.unwind;
4 
5 alias uintptr_t = size_t;
6 
7 enum Format {
8 	Absptr = 0x00,
9 	Uleb128 = 0x01,
10 	Udata2 = 0x02, // unsigned 2-byte
11 	Udata4 = 0x03,
12 	Udata8 = 0x04,
13 	Sleb128 = 0x09,
14 	Sdata2 = 0x0a,
15 	Sdata4 = 0x0b,
16 	Sdata8 = 0x0c,
17 }
18 
19 enum Base {
20 	Absptr = 0x00,
21 	Pcrel = 0x10, // relative to program counter
22 	Textrel = 0x20, // relative to .text
23 	Datarel = 0x30, // relative to .got or .eh_frame_hdr
24 	Funcrel = 0x40, // relative to beginning of function
25 	Aligned = 0x50, // is an aligned void*
26 }
27 
28 struct Encoding {
29 	private ubyte encoding;
30 
31 	enum Omit = 0xff;
32 	enum Indirect = 0x80;
33 
34 	this(ubyte encoding) {
35 		this.encoding = encoding;
36 	}
37 
38 	Format getFormat() {
39 		return cast(Format) (encoding & 0x0f);
40 	}
41 
42 	Base getBase() {
43 		return cast(Base) (encoding & 0x70);
44 	}
45 
46 	bool isIndirect() {
47 		return !!(encoding & Indirect);
48 	}
49 
50 	bool isOmit() {
51 		return encoding == Omit;
52 	}
53 
54 	uint getSize() {
55 		if (isOmit()) {
56 			return 0;
57 		}
58 
59 		switch (encoding & 0x07) {
60 			case Format.Absptr:
61 				// XXX: remove cast when VRP is in.
62 				return cast(uint) size_t.sizeof;
63 
64 			case Format.Udata2:
65 				return 2;
66 
67 			case Format.Udata4:
68 				return 4;
69 
70 			case Format.Udata8:
71 				return 8;
72 
73 			default:
74 				assert(0);
75 		}
76 	}
77 }
78 
79 uintptr_t read_uleb128(ref const(ubyte)* p) {
80 	uintptr_t result = 0;
81 	uint shift = 0;
82 	ubyte b;
83 
84 	do {
85 		b = *p++;
86 		result |= (cast(uintptr_t) (b & 0x7f) << shift);
87 		shift += 7;
88 	} while (b & 0x80);
89 
90 	return result;
91 }
92 
93 ptrdiff_t read_sleb128(ref const(ubyte)* p) {
94 	uint shift = 0;
95 	ubyte b;
96 	ptrdiff_t result = 0;
97 
98 	do {
99 		b = *p++;
100 		result |= (cast(long) (b & 0x7f) << shift);
101 		shift += 7;
102 	} while (b & 0x80);
103 
104 	// Sign-extend if the value is negative.
105 	if (shift < 8 * result.sizeof && (b & 0x40) != 0) {
106 		result |= -(1L << shift);
107 	}
108 
109 	return result;
110 }
111 
112 ubyte read_ubyte(ref const(ubyte)* p) {
113 	return *p++;
114 }
115 
116 uintptr_t read_encoded(ref const(ubyte)* p, _Unwind_Context* ctx,
117                        Encoding encoding) {
118 	if (encoding.isOmit()) {
119 		import core.stdc.stdlib, core.stdc.stdio;
120 		printf("Encoding specifies omit flag, should not read.\n".ptr);
121 		exit(-1);
122 	}
123 
124 	auto pcrel = cast(uintptr_t) p;
125 	uintptr_t result;
126 
127 	switch (encoding.getFormat()) {
128 		case Format.Uleb128:
129 			result = read_uleb128(p);
130 			break;
131 
132 		case Format.Sleb128:
133 			result = read_sleb128(p);
134 			break;
135 
136 		case Format.Absptr:
137 			result = *(cast(uintptr_t*) p);
138 			p += uintptr_t.sizeof;
139 			break;
140 
141 		case Format.Udata2:
142 			result = *(cast(ushort*) p);
143 			p += ushort.sizeof;
144 			break;
145 
146 		case Format.Udata4:
147 			result = *(cast(uint*) p);
148 			p += uint.sizeof;
149 			break;
150 
151 		case Format.Udata8:
152 			result = cast(uintptr_t) *(cast(ulong*) p);
153 			p += ulong.sizeof;
154 			break;
155 
156 		case Format.Sdata2:
157 			result = cast(uintptr_t) *(cast(short*) p);
158 			p += short.sizeof;
159 			break;
160 
161 		case Format.Sdata4:
162 			result = cast(uintptr_t) *(cast(int*) p);
163 			p += int.sizeof;
164 			break;
165 
166 		case Format.Sdata8:
167 			result = cast(uintptr_t) *(cast(long*) p);
168 			p += long.sizeof;
169 			break;
170 
171 		default:
172 			import core.stdc.stdlib, core.stdc.stdio;
173 			printf("FORMAT NOT SUPPORTED %d\n".ptr, encoding.getFormat());
174 			exit(-1);
175 	}
176 
177 	switch (encoding.getBase()) {
178 		case Base.Absptr:
179 		case Base.Aligned:
180 			break;
181 
182 		case Base.Pcrel:
183 			result += pcrel;
184 			break;
185 
186 		case Base.Textrel:
187 			auto txt = _Unwind_GetTextRelBase(ctx);
188 			result += cast(uintptr_t) txt;
189 			break;
190 
191 		case Base.Datarel:
192 			auto data = _Unwind_GetDataRelBase(ctx);
193 			result += cast(uintptr_t) data;
194 			break;
195 
196 		case Base.Funcrel:
197 			auto region = _Unwind_GetRegionStart(ctx);
198 			result += cast(uintptr_t) region;
199 			break;
200 
201 		default:
202 			import core.stdc.stdlib, core.stdc.stdio;
203 			printf("BASE NOT SUPPORTED %d\n".ptr, encoding.getBase());
204 			exit(-1);
205 	}
206 
207 	if (encoding.isIndirect()) {
208 		result = *(cast(uintptr_t*) result);
209 	}
210 
211 	return result;
212 }
213 
214 struct LsdHeaderInfo {
215 	_Unwind_Ptr start;
216 	_Unwind_Ptr lpStart;
217 
218 	Encoding callSiteEncoding;
219 	Encoding typeEncoding;
220 
221 	const(ubyte)* typeTable;
222 	const(ubyte)* actionTable;
223 }
224 
225 auto parseLsdHeader(ref const(ubyte)* p, _Unwind_Context* ctx) {
226 	LsdHeaderInfo infos;
227 
228 	// infos.start = ctx ? _Unwind_GetRegionStart(ctx) : null;
229 	if (ctx !is null) {
230 		infos.start = _Unwind_GetRegionStart(ctx);
231 	}
232 
233 	auto encoding = Encoding(*p++);
234 	/+
235 	info.lpStart = encoding.isOmit()
236 		? infos.start
237 		: read_encoded_value(p, ctx, encoding);
238 	+/
239 	if (encoding.isOmit()) {
240 		infos.lpStart = infos.start;
241 	} else {
242 		auto encoded = read_encoded(p, ctx, encoding);
243 		infos.lpStart = cast(void*) encoded;
244 	}
245 
246 	infos.typeEncoding = Encoding(*p++);
247 	if (!infos.typeEncoding.isOmit()) {
248 		auto tmp = read_uleb128(p);
249 		infos.typeTable = p + tmp;
250 	}
251 
252 	infos.callSiteEncoding = Encoding(*p++);
253 	auto tmp = read_uleb128(p);
254 	infos.actionTable = p + tmp;
255 
256 	return infos;
257 }