1 #![cfg(all(feature = "read", feature = "std", feature = "endian-reader"))]
2
3 use gimli::{
4 AttributeValue, DebugAbbrev, DebugAddr, DebugAddrBase, DebugAranges, DebugInfo, DebugLine,
5 DebugLoc, DebugLocLists, DebugPubNames, DebugPubTypes, DebugRanges, DebugRngLists, DebugStr,
6 Encoding, EndianSlice, Expression, LittleEndian, LocationLists, Operation, RangeLists, Reader,
7 };
8 use std::collections::hash_map::HashMap;
9 use std::env;
10 use std::fs::File;
11 use std::io::Read;
12 use std::path::PathBuf;
13 use std::rc::Rc;
14
read_section(section: &str) -> Vec<u8>15 fn read_section(section: &str) -> Vec<u8> {
16 let mut path = PathBuf::new();
17 if let Ok(dir) = env::var("CARGO_MANIFEST_DIR") {
18 path.push(dir);
19 }
20 path.push("fixtures/self");
21 path.push(section);
22
23 println!("Reading section \"{}\" at path {:?}", section, path);
24 assert!(path.is_file());
25 let mut file = File::open(path).unwrap();
26
27 let mut buf = Vec::new();
28 file.read_to_end(&mut buf).unwrap();
29 buf
30 }
31
parse_expression<R: Reader>(expr: Expression<R>, encoding: Encoding)32 fn parse_expression<R: Reader>(expr: Expression<R>, encoding: Encoding) {
33 let mut pc = expr.0.clone();
34 while !pc.is_empty() {
35 Operation::parse(&mut pc, encoding).expect("Should parse operation");
36 }
37
38 // Also attempt to evaluate some of it.
39 let mut eval = expr.evaluation(encoding);
40 eval.set_initial_value(0);
41 eval.evaluate().expect("Should evaluate expression");
42 }
43
impl_parse_self_debug_info<R: gimli::Reader>( debug_info: &DebugInfo<R>, debug_abbrev: &DebugAbbrev<R>, )44 fn impl_parse_self_debug_info<R: gimli::Reader>(
45 debug_info: &DebugInfo<R>,
46 debug_abbrev: &DebugAbbrev<R>,
47 ) {
48 let mut iter = debug_info.units();
49 while let Some(unit) = iter.next().expect("Should parse compilation unit") {
50 let abbrevs = unit
51 .abbreviations(&debug_abbrev)
52 .expect("Should parse abbreviations");
53
54 let mut cursor = unit.entries(&abbrevs);
55
56 while cursor.next_dfs().expect("Should parse next dfs").is_some() {
57 let entry = cursor.current().expect("Should have a current entry");
58
59 let mut attrs = entry.attrs();
60 while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
61 if let AttributeValue::Exprloc(expression) = attr.value() {
62 parse_expression(expression, unit.encoding());
63 }
64 }
65 }
66 }
67 }
68
69 #[test]
test_parse_self_debug_info()70 fn test_parse_self_debug_info() {
71 let debug_info = read_section("debug_info");
72 let debug_info = DebugInfo::new(&debug_info, LittleEndian);
73
74 let debug_abbrev = read_section("debug_abbrev");
75 let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
76
77 impl_parse_self_debug_info(&debug_info, &debug_abbrev);
78 }
79
80 #[test]
test_parse_self_debug_info_with_endian_rc_slice()81 fn test_parse_self_debug_info_with_endian_rc_slice() {
82 let debug_info = read_section("debug_info");
83 let debug_info = Rc::from(&debug_info[..]);
84 let debug_info = gimli::EndianRcSlice::new(debug_info, LittleEndian);
85 let debug_info = DebugInfo::from(debug_info);
86
87 let debug_abbrev = read_section("debug_abbrev");
88 let debug_abbrev = Rc::from(&debug_abbrev[..]);
89 let debug_abbrev = gimli::EndianRcSlice::new(debug_abbrev, LittleEndian);
90 let debug_abbrev = DebugAbbrev::from(debug_abbrev);
91
92 impl_parse_self_debug_info(&debug_info, &debug_abbrev);
93 }
94
95 #[test]
test_parse_self_debug_line()96 fn test_parse_self_debug_line() {
97 let debug_info = read_section("debug_info");
98 let debug_info = DebugInfo::new(&debug_info, LittleEndian);
99
100 let debug_abbrev = read_section("debug_abbrev");
101 let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
102
103 let debug_line = read_section("debug_line");
104 let debug_line = DebugLine::new(&debug_line, LittleEndian);
105
106 let debug_str = read_section("debug_str");
107 let debug_str = DebugStr::new(&debug_str, LittleEndian);
108
109 let mut iter = debug_info.units();
110 while let Some(unit) = iter.next().expect("Should parse compilation unit") {
111 let abbrevs = unit
112 .abbreviations(&debug_abbrev)
113 .expect("Should parse abbreviations");
114
115 let mut cursor = unit.entries(&abbrevs);
116 cursor.next_dfs().expect("Should parse next dfs");
117
118 let unit_entry = cursor.current().expect("Should have a root entry");
119
120 let comp_dir = unit_entry
121 .attr_value(gimli::DW_AT_comp_dir)
122 .expect("Should parse comp_dir attribute")
123 .and_then(|val| val.string_value(&debug_str));
124 let comp_name = unit_entry
125 .attr_value(gimli::DW_AT_name)
126 .expect("Should parse name attribute")
127 .and_then(|val| val.string_value(&debug_str));
128
129 if let Some(AttributeValue::DebugLineRef(offset)) = unit_entry
130 .attr_value(gimli::DW_AT_stmt_list)
131 .expect("Should parse stmt_list")
132 {
133 let program = debug_line
134 .program(offset, unit.address_size(), comp_dir, comp_name)
135 .expect("should parse line number program header");
136
137 let mut results = Vec::new();
138 let mut rows = program.rows();
139 while let Some((_, row)) = rows
140 .next_row()
141 .expect("Should parse and execute all rows in the line number program")
142 {
143 results.push(*row);
144 }
145 results.reverse();
146
147 let program = debug_line
148 .program(offset, unit.address_size(), comp_dir, comp_name)
149 .expect("should parse line number program header");
150 let (program, sequences) = program
151 .sequences()
152 .expect("should parse and execute the entire line number program");
153 assert!(!sequences.is_empty()); // Should be at least one sequence.
154 for sequence in sequences {
155 let mut rows = program.resume_from(&sequence);
156 while let Some((_, row)) = rows
157 .next_row()
158 .expect("Should parse and execute all rows after resuming")
159 {
160 let other_row = results.pop().unwrap();
161 assert!(row.address() >= sequence.start);
162 assert!(row.address() <= sequence.end);
163 assert_eq!(row.address(), other_row.address());
164 assert_eq!(row.line(), other_row.line());
165 }
166 }
167 assert!(results.is_empty());
168 }
169 }
170 }
171
172 #[test]
test_parse_self_debug_loc()173 fn test_parse_self_debug_loc() {
174 let debug_info = read_section("debug_info");
175 let debug_info = DebugInfo::new(&debug_info, LittleEndian);
176
177 let debug_abbrev = read_section("debug_abbrev");
178 let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
179
180 let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian));
181 let debug_addr_base = DebugAddrBase(0);
182
183 let debug_loc = read_section("debug_loc");
184 let debug_loc = DebugLoc::new(&debug_loc, LittleEndian);
185 let debug_loclists = DebugLocLists::new(&[], LittleEndian);
186 let loclists = LocationLists::new(debug_loc, debug_loclists);
187
188 let mut iter = debug_info.units();
189 while let Some(unit) = iter.next().expect("Should parse compilation unit") {
190 let abbrevs = unit
191 .abbreviations(&debug_abbrev)
192 .expect("Should parse abbreviations");
193
194 let mut cursor = unit.entries(&abbrevs);
195 cursor.next_dfs().expect("Should parse next dfs");
196
197 let mut low_pc = 0;
198
199 {
200 let unit_entry = cursor.current().expect("Should have a root entry");
201 let low_pc_attr = unit_entry
202 .attr_value(gimli::DW_AT_low_pc)
203 .expect("Should parse low_pc");
204 if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr {
205 low_pc = address;
206 }
207 }
208
209 while cursor.next_dfs().expect("Should parse next dfs").is_some() {
210 let entry = cursor.current().expect("Should have a current entry");
211 let mut attrs = entry.attrs();
212 while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
213 if let AttributeValue::LocationListsRef(offset) = attr.value() {
214 let mut locs = loclists
215 .locations(
216 offset,
217 unit.encoding(),
218 low_pc,
219 &debug_addr,
220 debug_addr_base,
221 )
222 .expect("Should parse locations OK");
223 while let Some(loc) = locs.next().expect("Should parse next location") {
224 assert!(loc.range.begin <= loc.range.end);
225 parse_expression(loc.data, unit.encoding());
226 }
227 }
228 }
229 }
230 }
231 }
232
233 #[test]
test_parse_self_debug_ranges()234 fn test_parse_self_debug_ranges() {
235 let debug_info = read_section("debug_info");
236 let debug_info = DebugInfo::new(&debug_info, LittleEndian);
237
238 let debug_abbrev = read_section("debug_abbrev");
239 let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
240
241 let debug_addr = DebugAddr::from(EndianSlice::new(&[], LittleEndian));
242 let debug_addr_base = DebugAddrBase(0);
243
244 let debug_ranges = read_section("debug_ranges");
245 let debug_ranges = DebugRanges::new(&debug_ranges, LittleEndian);
246 let debug_rnglists = DebugRngLists::new(&[], LittleEndian);
247 let rnglists = RangeLists::new(debug_ranges, debug_rnglists);
248
249 let mut iter = debug_info.units();
250 while let Some(unit) = iter.next().expect("Should parse compilation unit") {
251 let abbrevs = unit
252 .abbreviations(&debug_abbrev)
253 .expect("Should parse abbreviations");
254
255 let mut cursor = unit.entries(&abbrevs);
256 cursor.next_dfs().expect("Should parse next dfs");
257
258 let mut low_pc = 0;
259
260 {
261 let unit_entry = cursor.current().expect("Should have a root entry");
262 let low_pc_attr = unit_entry
263 .attr_value(gimli::DW_AT_low_pc)
264 .expect("Should parse low_pc");
265 if let Some(gimli::AttributeValue::Addr(address)) = low_pc_attr {
266 low_pc = address;
267 }
268 }
269
270 while cursor.next_dfs().expect("Should parse next dfs").is_some() {
271 let entry = cursor.current().expect("Should have a current entry");
272 let mut attrs = entry.attrs();
273 while let Some(attr) = attrs.next().expect("Should parse entry's attribute") {
274 if let AttributeValue::RangeListsRef(offset) = attr.value() {
275 let mut ranges = rnglists
276 .ranges(
277 offset,
278 unit.encoding(),
279 low_pc,
280 &debug_addr,
281 debug_addr_base,
282 )
283 .expect("Should parse ranges OK");
284 while let Some(range) = ranges.next().expect("Should parse next range") {
285 assert!(range.begin <= range.end);
286 }
287 }
288 }
289 }
290 }
291 }
292
293 #[test]
test_parse_self_debug_aranges()294 fn test_parse_self_debug_aranges() {
295 let debug_aranges = read_section("debug_aranges");
296 let debug_aranges = DebugAranges::new(&debug_aranges, LittleEndian);
297
298 let mut headers = debug_aranges.headers();
299 while let Some(header) = headers.next().expect("Should parse arange header OK") {
300 let mut entries = header.entries();
301 while let Some(_) = entries.next().expect("Should parse arange entry OK") {
302 // Not really anything else we can check right now.
303 }
304 }
305 }
306
307 #[test]
test_parse_self_debug_pubnames()308 fn test_parse_self_debug_pubnames() {
309 let debug_info = read_section("debug_info");
310 let debug_info = DebugInfo::new(&debug_info, LittleEndian);
311
312 let debug_abbrev = read_section("debug_abbrev");
313 let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
314
315 let debug_pubnames = read_section("debug_pubnames");
316 let debug_pubnames = DebugPubNames::new(&debug_pubnames, LittleEndian);
317
318 let mut units = HashMap::new();
319 let mut abbrevs = HashMap::new();
320 let mut pubnames = debug_pubnames.items();
321 while let Some(entry) = pubnames.next().expect("Should parse pubname OK") {
322 let unit_offset = entry.unit_header_offset();
323 let unit = units.entry(unit_offset).or_insert_with(|| {
324 debug_info
325 .header_from_offset(unit_offset)
326 .expect("Should parse unit header OK")
327 });
328 let abbrev_offset = unit.debug_abbrev_offset();
329 let abbrevs = abbrevs.entry(abbrev_offset).or_insert_with(|| {
330 debug_abbrev
331 .abbreviations(abbrev_offset)
332 .expect("Should parse abbreviations OK")
333 });
334 let mut cursor = unit
335 .entries_at_offset(abbrevs, entry.die_offset())
336 .expect("DIE offset should be valid");
337 assert!(cursor.next_dfs().expect("Should parse DIE").is_some());
338 }
339 }
340
341 #[test]
test_parse_self_debug_pubtypes()342 fn test_parse_self_debug_pubtypes() {
343 let debug_info = read_section("debug_info");
344 let debug_info = DebugInfo::new(&debug_info, LittleEndian);
345
346 let debug_abbrev = read_section("debug_abbrev");
347 let debug_abbrev = DebugAbbrev::new(&debug_abbrev, LittleEndian);
348
349 let debug_pubtypes = read_section("debug_pubtypes");
350 let debug_pubtypes = DebugPubTypes::new(&debug_pubtypes, LittleEndian);
351
352 let mut units = HashMap::new();
353 let mut abbrevs = HashMap::new();
354 let mut pubtypes = debug_pubtypes.items();
355 while let Some(entry) = pubtypes.next().expect("Should parse pubtype OK") {
356 let unit_offset = entry.unit_header_offset();
357 let unit = units.entry(unit_offset).or_insert_with(|| {
358 debug_info
359 .header_from_offset(unit_offset)
360 .expect("Should parse unit header OK")
361 });
362 let abbrev_offset = unit.debug_abbrev_offset();
363 let abbrevs = abbrevs.entry(abbrev_offset).or_insert_with(|| {
364 debug_abbrev
365 .abbreviations(abbrev_offset)
366 .expect("Should parse abbreviations OK")
367 });
368 let mut cursor = unit
369 .entries_at_offset(abbrevs, entry.die_offset())
370 .expect("DIE offset should be valid");
371 assert!(cursor.next_dfs().expect("Should parse DIE").is_some());
372 }
373 }
374
375 #[test]
test_parse_self_eh_frame()376 fn test_parse_self_eh_frame() {
377 use gimli::{BaseAddresses, CieOrFde, EhFrame, UnwindSection};
378
379 let eh_frame = read_section("eh_frame");
380 let mut eh_frame = EhFrame::new(&eh_frame, LittleEndian);
381 // The `.eh_frame` fixture data was created on a 64-bit machine.
382 eh_frame.set_address_size(8);
383
384 let bases = BaseAddresses::default()
385 .set_eh_frame(0)
386 .set_text(0)
387 .set_got(0);
388 let mut entries = eh_frame.entries(&bases);
389 while let Some(entry) = entries.next().expect("Should parse CFI entry OK") {
390 match entry {
391 CieOrFde::Cie(cie) => {
392 let mut instrs = cie.instructions(&eh_frame, &bases);
393 while let Some(_) = instrs.next().expect("Can parse next CFI instruction OK") {
394 // TODO FITZGEN
395 }
396 }
397 CieOrFde::Fde(partial) => {
398 let fde = partial
399 .parse(UnwindSection::cie_from_offset)
400 .expect("Should be able to get CIE for FDE");
401
402 let mut instrs = fde.instructions(&eh_frame, &bases);
403 while let Some(_) = instrs.next().expect("Can parse next CFI instruction OK") {
404 // TODO FITZGEN
405 }
406 }
407 }
408 }
409 }
410
411 #[test]
test_parse_self_eh_frame_hdr()412 fn test_parse_self_eh_frame_hdr() {
413 use gimli::{BaseAddresses, EhFrameHdr};
414
415 let eh_frame_hdr = read_section("eh_frame_hdr");
416 let eh_frame_hdr = EhFrameHdr::new(&eh_frame_hdr, LittleEndian);
417
418 let bases = BaseAddresses::default()
419 .set_eh_frame(0)
420 .set_eh_frame_hdr(0)
421 .set_text(0)
422 .set_got(0);
423
424 // `.eh_frame_hdr` was generated on a 64 bit machine.
425 let address_size = 8;
426
427 let _parsed_header = eh_frame_hdr
428 .parse(&bases, address_size)
429 .expect("we can parse the `.eh_frame_hdr` section OK");
430 }
431