1 | /* |
---|
2 | * Copyright (c) 2018, Chris Johns <chrisj@rtems.org> |
---|
3 | * |
---|
4 | * Permission to use, copy, modify, and/or distribute this software for any |
---|
5 | * purpose with or without fee is hereby granted, provided that the above |
---|
6 | * copyright notice and this permission notice appear in all copies. |
---|
7 | * |
---|
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
---|
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
---|
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
---|
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
---|
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
---|
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
---|
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
---|
15 | */ |
---|
16 | /** |
---|
17 | * @file |
---|
18 | * |
---|
19 | * @ingroup rtems-ld |
---|
20 | * |
---|
21 | * @brief RTEMS Linker DWARF module manages the DWARF format images. |
---|
22 | * |
---|
23 | */ |
---|
24 | |
---|
25 | #include <string.h> |
---|
26 | |
---|
27 | #include <iostream> |
---|
28 | #include <iomanip> |
---|
29 | #include <list> |
---|
30 | #include <map> |
---|
31 | |
---|
32 | #include <rld.h> |
---|
33 | #include <rld-path.h> |
---|
34 | #include <rld-dwarf.h> |
---|
35 | |
---|
36 | namespace rld |
---|
37 | { |
---|
38 | namespace dwarf |
---|
39 | { |
---|
40 | /** |
---|
41 | * The libdwarf error. |
---|
42 | */ |
---|
43 | void libdwarf_error_check (const std::string where, |
---|
44 | int result, |
---|
45 | dwarf_error& error) |
---|
46 | { |
---|
47 | if (result != DW_DLV_OK) |
---|
48 | { |
---|
49 | std::ostringstream exe_where; |
---|
50 | std::string what; |
---|
51 | exe_where << "dwarf:" << where; |
---|
52 | what = dwarf_errmsg (error); |
---|
53 | throw rld::error (what, exe_where.str ()); |
---|
54 | } |
---|
55 | } |
---|
56 | |
---|
57 | address::address (const sources& source, dwarf_line& line) |
---|
58 | : addr (0), |
---|
59 | source (&source), |
---|
60 | source_index (-1), |
---|
61 | source_line (-1), |
---|
62 | begin_statement (false), |
---|
63 | block (false), |
---|
64 | end_sequence (false) |
---|
65 | { |
---|
66 | dwarf_error de; |
---|
67 | int dr; |
---|
68 | dr = ::dwarf_lineaddr(line, &addr, &de); |
---|
69 | libdwarf_error_check ("address::address", dr, de); |
---|
70 | dr = ::dwarf_line_srcfileno(line, &source_index, &de); |
---|
71 | libdwarf_error_check ("address::address", dr, de); |
---|
72 | dr = ::dwarf_lineno(line, &source_line, &de); |
---|
73 | libdwarf_error_check ("address::address", dr, de); |
---|
74 | dwarf_bool b; |
---|
75 | dr = ::dwarf_linebeginstatement(line, &b, &de); |
---|
76 | libdwarf_error_check ("address::address", dr, de); |
---|
77 | begin_statement = b ? true : false; |
---|
78 | dr = ::dwarf_lineblock(line, &b, &de); |
---|
79 | libdwarf_error_check ("address::address", dr, de); |
---|
80 | block = b ? true : false; |
---|
81 | dr = ::dwarf_lineendsequence(line, &b, &de); |
---|
82 | libdwarf_error_check ("address::address", dr, de); |
---|
83 | end_sequence = b ? true : false; |
---|
84 | } |
---|
85 | |
---|
86 | address::address (const address& orig) |
---|
87 | : addr (orig.addr), |
---|
88 | source (orig.source), |
---|
89 | source_index (orig.source_index), |
---|
90 | source_line (orig.source_line), |
---|
91 | begin_statement (orig.begin_statement), |
---|
92 | block (orig.block), |
---|
93 | end_sequence (orig.end_sequence) |
---|
94 | { |
---|
95 | } |
---|
96 | |
---|
97 | address::address () |
---|
98 | : addr (0), |
---|
99 | source (nullptr), |
---|
100 | source_index (-1), |
---|
101 | source_line (-1), |
---|
102 | begin_statement (false), |
---|
103 | block (false), |
---|
104 | end_sequence (false) |
---|
105 | { |
---|
106 | } |
---|
107 | |
---|
108 | address::~address () |
---|
109 | { |
---|
110 | source = nullptr; |
---|
111 | } |
---|
112 | |
---|
113 | bool |
---|
114 | address::valid () const |
---|
115 | { |
---|
116 | return source_line > 0; |
---|
117 | } |
---|
118 | |
---|
119 | dwarf_address |
---|
120 | address::location () const |
---|
121 | { |
---|
122 | return addr; |
---|
123 | } |
---|
124 | |
---|
125 | std::string |
---|
126 | address::path () const |
---|
127 | { |
---|
128 | if (source == nullptr) |
---|
129 | throw rld::error ("invalid source pointer", "dwarf:address:path"); |
---|
130 | return (*source)[source_index]; |
---|
131 | } |
---|
132 | |
---|
133 | int |
---|
134 | address::line () const |
---|
135 | { |
---|
136 | return source_line; |
---|
137 | } |
---|
138 | |
---|
139 | bool |
---|
140 | address::is_a_begin_statement () const |
---|
141 | { |
---|
142 | return begin_statement; |
---|
143 | } |
---|
144 | |
---|
145 | bool |
---|
146 | address::is_in_a_block () const |
---|
147 | { |
---|
148 | return block; |
---|
149 | } |
---|
150 | |
---|
151 | bool |
---|
152 | address::is_an_end_sequence () const |
---|
153 | { |
---|
154 | return end_sequence; |
---|
155 | } |
---|
156 | |
---|
157 | address& |
---|
158 | address::operator = (address& rhs) |
---|
159 | { |
---|
160 | if (this != &rhs) |
---|
161 | { |
---|
162 | addr = rhs.addr; |
---|
163 | source = rhs.source; |
---|
164 | source_index = rhs.source_index; |
---|
165 | source_line = rhs.source_line; |
---|
166 | begin_statement = rhs.begin_statement; |
---|
167 | block = rhs.block; |
---|
168 | end_sequence = rhs.end_sequence; |
---|
169 | } |
---|
170 | return *this; |
---|
171 | } |
---|
172 | |
---|
173 | line_addresses::line_addresses (file& debug, |
---|
174 | debug_info_entry& die) |
---|
175 | : debug (debug), |
---|
176 | lines (nullptr), |
---|
177 | count_ (0) |
---|
178 | { |
---|
179 | if (!die.source_lines (lines, count_)) |
---|
180 | { |
---|
181 | lines = nullptr; |
---|
182 | count_ = 0; |
---|
183 | } |
---|
184 | } |
---|
185 | |
---|
186 | line_addresses::line_addresses (line_addresses&& orig) |
---|
187 | : debug (orig.debug), |
---|
188 | lines (orig.lines), |
---|
189 | count_ (orig.count_) |
---|
190 | { |
---|
191 | orig.lines = nullptr; |
---|
192 | orig.count_ = 0; |
---|
193 | } |
---|
194 | |
---|
195 | line_addresses::~line_addresses () |
---|
196 | { |
---|
197 | if (lines && count_ > 0) |
---|
198 | { |
---|
199 | ::dwarf_srclines_dealloc (debug, lines, count_); |
---|
200 | lines = nullptr; |
---|
201 | count_ = 0; |
---|
202 | } |
---|
203 | } |
---|
204 | |
---|
205 | size_t |
---|
206 | line_addresses::count () const |
---|
207 | { |
---|
208 | return count_; |
---|
209 | } |
---|
210 | |
---|
211 | dwarf_line& |
---|
212 | line_addresses::operator [] (const int index) |
---|
213 | { |
---|
214 | if (index < 0 || index >= count_) |
---|
215 | throw rld::error ("index out of range", |
---|
216 | "line_addresses:indexing"); |
---|
217 | return lines[index]; |
---|
218 | } |
---|
219 | |
---|
220 | sources::sources (file& debug, debug_info_entry& die) |
---|
221 | : debug (debug), |
---|
222 | source (nullptr), |
---|
223 | count (0), |
---|
224 | die_offset (die.offset ()) |
---|
225 | { |
---|
226 | die.source_files (source, count); |
---|
227 | } |
---|
228 | |
---|
229 | sources::sources (const sources& orig) |
---|
230 | : debug (orig.debug), |
---|
231 | source (nullptr), |
---|
232 | count (0), |
---|
233 | die_offset (orig.die_offset) |
---|
234 | { |
---|
235 | /* |
---|
236 | * In a copy constructor we need to get our own copy of the strings. To |
---|
237 | * do that we need to get the DIE at the offset in the original. |
---|
238 | */ |
---|
239 | debug_info_entry die (debug, die_offset); |
---|
240 | die.source_files (source, count); |
---|
241 | } |
---|
242 | |
---|
243 | sources::sources (sources&& orig) |
---|
244 | : debug (orig.debug), |
---|
245 | source (orig.source), |
---|
246 | count (orig.count), |
---|
247 | die_offset (orig.die_offset) |
---|
248 | { |
---|
249 | orig.source = nullptr; |
---|
250 | orig.count = 0; |
---|
251 | } |
---|
252 | |
---|
253 | sources::~sources () |
---|
254 | { |
---|
255 | dealloc (); |
---|
256 | } |
---|
257 | |
---|
258 | std::string |
---|
259 | sources::operator [] (const int index) const |
---|
260 | { |
---|
261 | if (index <= 0 || index > count) |
---|
262 | return "unknown"; |
---|
263 | return source[index - 1]; |
---|
264 | } |
---|
265 | |
---|
266 | void |
---|
267 | sources::dealloc () |
---|
268 | { |
---|
269 | if (source && count > 0) |
---|
270 | { |
---|
271 | /* |
---|
272 | * The elftoolchain cleans the memory up and there is no compatible |
---|
273 | * call we can put here so adding the required code causes is a double |
---|
274 | * free results in a crash. |
---|
275 | */ |
---|
276 | if (false) |
---|
277 | { |
---|
278 | for (int s = 0; s < count; ++s) |
---|
279 | ::dwarf_dealloc (debug, source[s], DW_DLA_STRING); |
---|
280 | ::dwarf_dealloc (debug, source, DW_DLA_LIST); |
---|
281 | } |
---|
282 | source = nullptr; |
---|
283 | count = 0; |
---|
284 | } |
---|
285 | } |
---|
286 | |
---|
287 | sources& |
---|
288 | sources::operator = (sources&& rhs) |
---|
289 | { |
---|
290 | if (this != &rhs) |
---|
291 | { |
---|
292 | debug = rhs.debug; |
---|
293 | source = rhs.source; |
---|
294 | count = rhs.count; |
---|
295 | die_offset = rhs.die_offset; |
---|
296 | rhs.source = nullptr; |
---|
297 | rhs.count = 0; |
---|
298 | } |
---|
299 | return *this; |
---|
300 | } |
---|
301 | |
---|
302 | debug_info_entry::debug_info_entry (file& debug) |
---|
303 | : debug (debug), |
---|
304 | die (nullptr), |
---|
305 | tag_ (0), |
---|
306 | offset_ (0) |
---|
307 | { |
---|
308 | } |
---|
309 | |
---|
310 | debug_info_entry::debug_info_entry (file& debug, dwarf_die& die) |
---|
311 | : debug (debug), |
---|
312 | die (die), |
---|
313 | tag_ (0), |
---|
314 | offset_ (0) |
---|
315 | { |
---|
316 | } |
---|
317 | |
---|
318 | debug_info_entry::debug_info_entry (file& debug, dwarf_offset offset__) |
---|
319 | : debug (debug), |
---|
320 | die (nullptr), |
---|
321 | tag_ (0), |
---|
322 | offset_ (offset__) |
---|
323 | { |
---|
324 | dwarf_error de; |
---|
325 | int dr; |
---|
326 | dr = ::dwarf_offdie (debug, offset_, &die, &de); |
---|
327 | libdwarf_error_check ("debug_info_entry:debug_info_entry", dr, de); |
---|
328 | } |
---|
329 | |
---|
330 | debug_info_entry::debug_info_entry (debug_info_entry&& orig) |
---|
331 | : debug (orig.debug), |
---|
332 | die (orig.die), |
---|
333 | tag_ (orig.tag_), |
---|
334 | offset_ (orig.offset_) |
---|
335 | { |
---|
336 | orig.die = nullptr; |
---|
337 | orig.tag_ = 0; |
---|
338 | orig.offset_ = 0; |
---|
339 | } |
---|
340 | |
---|
341 | debug_info_entry::~debug_info_entry () |
---|
342 | { |
---|
343 | if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) |
---|
344 | std::cout << "dwarf::debug_info_entry::~debug_info_entry" << std::endl; |
---|
345 | dealloc (); |
---|
346 | } |
---|
347 | |
---|
348 | dwarf_die |
---|
349 | debug_info_entry::get () const |
---|
350 | { |
---|
351 | return die; |
---|
352 | } |
---|
353 | |
---|
354 | debug_info_entry::operator dwarf_die& () |
---|
355 | { |
---|
356 | return die; |
---|
357 | } |
---|
358 | |
---|
359 | debug_info_entry::operator dwarf_die* () |
---|
360 | { |
---|
361 | return ¨ |
---|
362 | } |
---|
363 | |
---|
364 | debug_info_entry& |
---|
365 | debug_info_entry::operator = (debug_info_entry& rhs) |
---|
366 | { |
---|
367 | if (this != &rhs) |
---|
368 | { |
---|
369 | if (debug != rhs.debug) |
---|
370 | throw rld::error ("DIE debug info mismatch", |
---|
371 | "dwarf:debug_info_entry:operator="); |
---|
372 | dealloc (); |
---|
373 | die = rhs.die; |
---|
374 | tag_ = rhs.tag_; |
---|
375 | offset_ = rhs.offset_; |
---|
376 | rhs.die = nullptr; |
---|
377 | } |
---|
378 | return *this; |
---|
379 | } |
---|
380 | |
---|
381 | bool |
---|
382 | debug_info_entry::operator == (debug_info_entry& rhs) const |
---|
383 | { |
---|
384 | return debug == rhs.debug && die == rhs.die && |
---|
385 | tag_ == rhs.tag_ && offset_ == rhs.offset_; |
---|
386 | } |
---|
387 | |
---|
388 | bool |
---|
389 | debug_info_entry::operator == (const dwarf_die rhs) const |
---|
390 | { |
---|
391 | return die == rhs; |
---|
392 | } |
---|
393 | |
---|
394 | dwarf_tag |
---|
395 | debug_info_entry::tag () |
---|
396 | { |
---|
397 | if (tag_ == 0) |
---|
398 | { |
---|
399 | dwarf_error de; |
---|
400 | int dr; |
---|
401 | dr = ::dwarf_tag(die, &tag_, &de); |
---|
402 | libdwarf_error_check ("debug_info_entry:debug_info_entry", dr, de); |
---|
403 | } |
---|
404 | return tag_; |
---|
405 | } |
---|
406 | |
---|
407 | dwarf_offset |
---|
408 | debug_info_entry::offset () |
---|
409 | { |
---|
410 | if (offset_ == 0) |
---|
411 | { |
---|
412 | dwarf_error de; |
---|
413 | int dr; |
---|
414 | dr = ::dwarf_dieoffset (die, &offset_, &de); |
---|
415 | libdwarf_error_check ("debug_info_entry:debug_info_entry", dr, de); |
---|
416 | } |
---|
417 | return offset_; |
---|
418 | } |
---|
419 | |
---|
420 | bool |
---|
421 | debug_info_entry::attribute (dwarf_attr attr, |
---|
422 | dwarf_unsigned& value, |
---|
423 | bool error) const |
---|
424 | { |
---|
425 | dwarf_error de; |
---|
426 | int dr; |
---|
427 | dr = ::dwarf_attrval_unsigned (die, attr, &value, &de); |
---|
428 | if (error) |
---|
429 | libdwarf_error_check ("debug_info_entry:attribute ", dr, de); |
---|
430 | return dr == DW_DLV_OK; |
---|
431 | } |
---|
432 | |
---|
433 | bool |
---|
434 | debug_info_entry::attribute (dwarf_attr attr, |
---|
435 | std::string& value, |
---|
436 | bool error) const |
---|
437 | { |
---|
438 | dwarf_error de; |
---|
439 | int dr; |
---|
440 | const char* s = nullptr; |
---|
441 | value.clear (); |
---|
442 | dr = ::dwarf_attrval_string (die, attr, &s, &de); |
---|
443 | if (error) |
---|
444 | libdwarf_error_check ("debug_info_entry:attribute ", dr, de); |
---|
445 | if (s != nullptr) |
---|
446 | value = s; |
---|
447 | return dr == DW_DLV_OK; |
---|
448 | } |
---|
449 | |
---|
450 | bool |
---|
451 | debug_info_entry::source_lines (dwarf_line*& lines, |
---|
452 | dwarf_signed& linecount) const |
---|
453 | { |
---|
454 | dwarf_error de; |
---|
455 | int dr; |
---|
456 | if (lines != nullptr) |
---|
457 | throw rld::error ("lines is not null", "debug_info_entry:source_lines"); |
---|
458 | linecount = 0; |
---|
459 | dr = ::dwarf_srclines (die, &lines, &linecount, &de); |
---|
460 | if (dr == DW_DLV_NO_ENTRY) |
---|
461 | return false; |
---|
462 | libdwarf_error_check ("debug_info_entry:source_lines ", dr, de); |
---|
463 | return true; |
---|
464 | } |
---|
465 | |
---|
466 | void |
---|
467 | debug_info_entry::source_files (char**& sources, |
---|
468 | dwarf_signed& sourcecount) const |
---|
469 | { |
---|
470 | dwarf_error de; |
---|
471 | int dr; |
---|
472 | dr = ::dwarf_srcfiles (die, &sources, &sourcecount, &de); |
---|
473 | libdwarf_error_check ("debug_info_entry:source_files ", dr, de); |
---|
474 | } |
---|
475 | |
---|
476 | void |
---|
477 | debug_info_entry::dealloc () |
---|
478 | { |
---|
479 | if (die != nullptr) { |
---|
480 | ::dwarf_dealloc (debug, die, DW_DLA_DIE); |
---|
481 | die = nullptr; |
---|
482 | } |
---|
483 | } |
---|
484 | |
---|
485 | compilation_unit::compilation_unit (file& debug, |
---|
486 | debug_info_entry& die, |
---|
487 | dwarf_unsigned offset) |
---|
488 | : debug (debug), |
---|
489 | offset_ (offset), |
---|
490 | pc_low_ (0), |
---|
491 | pc_high_ (0), |
---|
492 | source_ (debug, die), |
---|
493 | die_offset (die.offset ()) |
---|
494 | { |
---|
495 | die.attribute (DW_AT_name, name_); |
---|
496 | name_ = name_; |
---|
497 | |
---|
498 | die.attribute (DW_AT_producer, producer_); |
---|
499 | |
---|
500 | die.attribute (DW_AT_low_pc, pc_low_, false); |
---|
501 | |
---|
502 | if (!die.attribute (DW_AT_high_pc, pc_high_, false)) |
---|
503 | pc_high_ = ~0U; |
---|
504 | |
---|
505 | if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) |
---|
506 | { |
---|
507 | std::cout << std::hex << std::setfill ('0') |
---|
508 | << "dwarf::compilation_unit: " |
---|
509 | << rld::path::basename (name_) |
---|
510 | << ": (0x" << std::setw (8) << offset_ << ") "; |
---|
511 | if (pc_low_ != 0 && pc_high_ != ~0U) |
---|
512 | std::cout << "pc_low = " << std::setw (8) << pc_low_ |
---|
513 | << " pc_high = " << std::setw (8) << pc_high_; |
---|
514 | std::cout << std::setfill (' ') << std::dec |
---|
515 | << std::endl |
---|
516 | << " ] " << producer_ |
---|
517 | << std::endl; |
---|
518 | } |
---|
519 | |
---|
520 | line_addresses lines (debug, die); |
---|
521 | dwarf_address pc = 0; |
---|
522 | |
---|
523 | for (size_t l = 0; l < lines.count (); ++l) |
---|
524 | { |
---|
525 | address addr (source_, lines[l]); |
---|
526 | dwarf_address loc = addr.location (); |
---|
527 | if (inside (loc) && loc >= pc) |
---|
528 | { |
---|
529 | pc = loc; |
---|
530 | addr_lines_[addr.location ()] = addr; |
---|
531 | if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) |
---|
532 | { |
---|
533 | std::cout << "dwarf::compilation_unit: " |
---|
534 | << std::hex << std::setw (8) << addr.location () << std::dec |
---|
535 | << " - " |
---|
536 | << (char) (addr.is_a_begin_statement () ? 'B' : '.') |
---|
537 | << (char) (addr.is_in_a_block () ? 'I' : '.') |
---|
538 | << (char) (addr.is_an_end_sequence () ? 'E' : '.') |
---|
539 | << " - " |
---|
540 | << rld::path::basename (addr.path ()) |
---|
541 | << ':' << addr.line () |
---|
542 | << std::endl; |
---|
543 | } |
---|
544 | } |
---|
545 | } |
---|
546 | } |
---|
547 | |
---|
548 | compilation_unit::compilation_unit (compilation_unit&& orig) |
---|
549 | : debug (orig.debug), |
---|
550 | offset_ (orig.offset_), |
---|
551 | name_ (orig.name_), |
---|
552 | producer_ (orig.producer_), |
---|
553 | pc_low_ (orig.pc_low_), |
---|
554 | pc_high_ (orig.pc_high_), |
---|
555 | source_ (std::move (orig.source_)), |
---|
556 | addr_lines_ (orig.addr_lines_), |
---|
557 | die_offset (orig.die_offset) |
---|
558 | { |
---|
559 | orig.name_.clear (); |
---|
560 | orig.producer_.clear (); |
---|
561 | orig.offset_ = 0; |
---|
562 | orig.die_offset = 0; |
---|
563 | orig.pc_low_ = 0; |
---|
564 | orig.pc_high_ = 0; |
---|
565 | } |
---|
566 | |
---|
567 | compilation_unit::compilation_unit (const compilation_unit& orig) |
---|
568 | : debug (orig.debug), |
---|
569 | offset_ (orig.offset_), |
---|
570 | name_ (orig.name_), |
---|
571 | producer_ (orig.producer_), |
---|
572 | pc_low_ (orig.pc_low_), |
---|
573 | pc_high_ (orig.pc_high_), |
---|
574 | source_ (orig.source_), |
---|
575 | addr_lines_ (orig.addr_lines_), |
---|
576 | die_offset (orig.die_offset) |
---|
577 | { |
---|
578 | } |
---|
579 | |
---|
580 | compilation_unit::~compilation_unit () |
---|
581 | { |
---|
582 | if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) |
---|
583 | std::cout << "dwarf::compilation_unit::~compilation_unit: " << name_ << std::endl; |
---|
584 | } |
---|
585 | |
---|
586 | std::string |
---|
587 | compilation_unit::name () const |
---|
588 | { |
---|
589 | return name_; |
---|
590 | } |
---|
591 | |
---|
592 | std::string |
---|
593 | compilation_unit::producer () const |
---|
594 | { |
---|
595 | return producer_; |
---|
596 | } |
---|
597 | |
---|
598 | unsigned int |
---|
599 | compilation_unit::pc_low () const |
---|
600 | { |
---|
601 | return pc_low_; |
---|
602 | } |
---|
603 | |
---|
604 | unsigned int |
---|
605 | compilation_unit::pc_high () const |
---|
606 | { |
---|
607 | return pc_high_; |
---|
608 | } |
---|
609 | |
---|
610 | bool |
---|
611 | compilation_unit::get_source (const dwarf_address addr, |
---|
612 | address& addr_line) |
---|
613 | { |
---|
614 | if (addr_lines_.find (addr) == addr_lines_.end ()) |
---|
615 | return false; |
---|
616 | addr_line = addr_lines_[addr]; |
---|
617 | return true; |
---|
618 | } |
---|
619 | |
---|
620 | bool |
---|
621 | compilation_unit::inside (dwarf_unsigned addr) const |
---|
622 | { |
---|
623 | return addr >= pc_low_ && addr < pc_high_; |
---|
624 | } |
---|
625 | |
---|
626 | compilation_unit& |
---|
627 | compilation_unit::operator = (compilation_unit&& rhs) |
---|
628 | { |
---|
629 | if (this != &rhs) |
---|
630 | { |
---|
631 | debug = rhs.debug; |
---|
632 | offset_ = rhs.offset_; |
---|
633 | name_ = rhs.name_; |
---|
634 | producer_ = rhs.producer_; |
---|
635 | source_ = std::move (rhs.source_); |
---|
636 | addr_lines_ = std::move (rhs.addr_lines_), |
---|
637 | pc_low_ = rhs.pc_low_; |
---|
638 | pc_high_ = rhs.pc_high_; |
---|
639 | die_offset = rhs.die_offset; |
---|
640 | rhs.offset_ = 0; |
---|
641 | rhs.name_.clear (); |
---|
642 | rhs.pc_low_ = -1; |
---|
643 | rhs.pc_high_ = -1; |
---|
644 | rhs.die_offset = 0; |
---|
645 | } |
---|
646 | return *this; |
---|
647 | } |
---|
648 | |
---|
649 | compilation_unit& |
---|
650 | compilation_unit::operator = (const compilation_unit& rhs) |
---|
651 | { |
---|
652 | if (this != &rhs) |
---|
653 | { |
---|
654 | debug = rhs.debug; |
---|
655 | |
---|
656 | /* |
---|
657 | * This is a copy operator so we need to get a new copy of the strings, |
---|
658 | * we cannot steal the other copy. |
---|
659 | */ |
---|
660 | offset_ = rhs.offset_; |
---|
661 | name_ = rhs.name_; |
---|
662 | producer_ = rhs.producer_; |
---|
663 | debug_info_entry die (debug, rhs.offset_); |
---|
664 | source_ = sources (debug, die); |
---|
665 | addr_lines_ = addresses (rhs.addr_lines_); |
---|
666 | pc_low_ = rhs.pc_low_; |
---|
667 | pc_high_ = rhs.pc_high_; |
---|
668 | die_offset = rhs.die_offset; |
---|
669 | } |
---|
670 | return *this; |
---|
671 | } |
---|
672 | |
---|
673 | source_flags::source_flags (const std::string& source) |
---|
674 | : source (source) |
---|
675 | { |
---|
676 | } |
---|
677 | |
---|
678 | bool |
---|
679 | source_flags_compare::operator () (const source_flags& a, |
---|
680 | const source_flags& b) const |
---|
681 | { |
---|
682 | if (by_basename) |
---|
683 | return rld::path::basename (a.source) < rld::path::basename (b.source); |
---|
684 | return a.source < b.source; |
---|
685 | } |
---|
686 | |
---|
687 | source_flags_compare:: source_flags_compare (bool by_basename) |
---|
688 | : by_basename (by_basename) |
---|
689 | { |
---|
690 | } |
---|
691 | |
---|
692 | producer_source::producer_source (const std::string& producer) |
---|
693 | : producer (producer) |
---|
694 | { |
---|
695 | } |
---|
696 | |
---|
697 | producer_source::producer_source () |
---|
698 | { |
---|
699 | } |
---|
700 | |
---|
701 | file::file () |
---|
702 | : debug (nullptr), |
---|
703 | elf_ (nullptr) |
---|
704 | { |
---|
705 | } |
---|
706 | |
---|
707 | file::~file () |
---|
708 | { |
---|
709 | try |
---|
710 | { |
---|
711 | end (); |
---|
712 | } |
---|
713 | catch (rld::error re) |
---|
714 | { |
---|
715 | std::cerr << "error: rld::dwarf::file::~file: " |
---|
716 | << re.where << ": " << re.what |
---|
717 | << std::endl; |
---|
718 | } |
---|
719 | catch (...) |
---|
720 | { |
---|
721 | std::cerr << "error: rld::dwarf::file::~file: unhandled exception" |
---|
722 | << std::endl; |
---|
723 | } |
---|
724 | } |
---|
725 | |
---|
726 | void |
---|
727 | file::begin (rld::elf::file& elf__) |
---|
728 | { |
---|
729 | if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) |
---|
730 | std::cout << "dwarf::begin: " << elf__.name () << std::endl; |
---|
731 | |
---|
732 | if (debug != nullptr || elf_ != nullptr) |
---|
733 | throw rld::error ("Already called", "dwarf:file:begin"); |
---|
734 | |
---|
735 | /* |
---|
736 | * DWARF data is not writable. |
---|
737 | */ |
---|
738 | if (elf__.is_writable ()) |
---|
739 | throw rld::error ("Cannot write DWARF info", "dwarf:file:begin"); |
---|
740 | |
---|
741 | /* |
---|
742 | * Initialise the DWARF instance. |
---|
743 | */ |
---|
744 | dwarf_error de; |
---|
745 | int dr = ::dwarf_elf_init (elf__.get_elf (), |
---|
746 | DW_DLC_READ, |
---|
747 | nullptr, |
---|
748 | this, |
---|
749 | &debug, |
---|
750 | &de); |
---|
751 | libdwarf_error_check ("file:begin", dr, de); |
---|
752 | |
---|
753 | /* |
---|
754 | * Record the ELF instance and obtain a reference to it. The ELF file |
---|
755 | * cannot end while the DWARF file has not ended. |
---|
756 | */ |
---|
757 | elf__.reference_obtain (); |
---|
758 | elf_ = &elf__; |
---|
759 | } |
---|
760 | |
---|
761 | void |
---|
762 | file::end () |
---|
763 | { |
---|
764 | if (debug) |
---|
765 | { |
---|
766 | if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG) |
---|
767 | std::cout << "dwarf::end: " << name () << std::endl; |
---|
768 | |
---|
769 | cus.clear (); |
---|
770 | |
---|
771 | ::dwarf_finish (debug, 0); |
---|
772 | if (elf_) |
---|
773 | elf_->reference_release (); |
---|
774 | elf_ = nullptr; |
---|
775 | debug = nullptr; |
---|
776 | } |
---|
777 | } |
---|
778 | |
---|
779 | void |
---|
780 | file::load_debug () |
---|
781 | { |
---|
782 | dwarf_unsigned cu_offset = 0; |
---|
783 | |
---|
784 | while (true) |
---|
785 | { |
---|
786 | dwarf_unsigned cu_next_offset = 0; |
---|
787 | dwarf_error de; |
---|
788 | int dr; |
---|
789 | |
---|
790 | dr = ::dwarf_next_cu_header_c(debug, 1, |
---|
791 | nullptr, nullptr, nullptr, nullptr, |
---|
792 | nullptr, nullptr, nullptr, nullptr, |
---|
793 | &cu_next_offset, &de); |
---|
794 | if (dr != DW_DLV_OK) |
---|
795 | break; |
---|
796 | |
---|
797 | /* |
---|
798 | * Fnd the CU DIE. |
---|
799 | */ |
---|
800 | debug_info_entry die (*this); |
---|
801 | debug_info_entry ret_die (*this); |
---|
802 | |
---|
803 | while (true) |
---|
804 | { |
---|
805 | dr = ::dwarf_siblingof(debug, die, ret_die, &de); |
---|
806 | if (dr != DW_DLV_OK) |
---|
807 | break; |
---|
808 | |
---|
809 | if (ret_die.tag () == DW_TAG_compile_unit) |
---|
810 | { |
---|
811 | cus.push_back (compilation_unit (*this, ret_die, cu_offset)); |
---|
812 | break; |
---|
813 | } |
---|
814 | |
---|
815 | die = ret_die; |
---|
816 | } |
---|
817 | |
---|
818 | cu_offset = cu_next_offset; |
---|
819 | } |
---|
820 | } |
---|
821 | |
---|
822 | bool |
---|
823 | file::get_source (const unsigned int addr, |
---|
824 | std::string& source_file, |
---|
825 | int& source_line) |
---|
826 | { |
---|
827 | bool r = false; |
---|
828 | |
---|
829 | /* |
---|
830 | * Search the CU's collecting the addresses. An address can appear in |
---|
831 | * more than one CU. It may be the last address and the first. |
---|
832 | */ |
---|
833 | source_file = "unknown"; |
---|
834 | source_line = -1; |
---|
835 | |
---|
836 | address match; |
---|
837 | |
---|
838 | for (auto& cu : cus) |
---|
839 | { |
---|
840 | address line; |
---|
841 | r = cu.get_source (addr, line); |
---|
842 | if (r) |
---|
843 | { |
---|
844 | if (match.valid ()) |
---|
845 | { |
---|
846 | if (match.is_an_end_sequence ()) |
---|
847 | { |
---|
848 | match = line; |
---|
849 | } |
---|
850 | else if (!line.is_an_end_sequence ()) |
---|
851 | { |
---|
852 | match = line; |
---|
853 | } |
---|
854 | } |
---|
855 | } |
---|
856 | } |
---|
857 | |
---|
858 | if (match.valid ()) |
---|
859 | { |
---|
860 | source_file = match.path (); |
---|
861 | source_line = match.line (); |
---|
862 | r = true; |
---|
863 | } |
---|
864 | |
---|
865 | return r; |
---|
866 | } |
---|
867 | |
---|
868 | void |
---|
869 | file::get_producer_sources (producer_sources& producers) |
---|
870 | { |
---|
871 | for (auto& cu : cus) |
---|
872 | { |
---|
873 | std::string producer = cu.producer (); |
---|
874 | producer_source new_producer; |
---|
875 | source_flags sf (cu.name ()); |
---|
876 | rld::strings parts; |
---|
877 | |
---|
878 | rld::split (parts, producer); |
---|
879 | |
---|
880 | for (auto& s : parts) |
---|
881 | { |
---|
882 | if (s[0] == '-') |
---|
883 | sf.flags.push_back (s); |
---|
884 | else |
---|
885 | new_producer.producer += ' ' + s; |
---|
886 | } |
---|
887 | |
---|
888 | bool add = true; |
---|
889 | |
---|
890 | for (auto& p : producers) |
---|
891 | { |
---|
892 | if (p.producer == new_producer.producer) |
---|
893 | { |
---|
894 | p.sources.push_back (sf); |
---|
895 | add = false; |
---|
896 | break; |
---|
897 | } |
---|
898 | } |
---|
899 | if (add) |
---|
900 | { |
---|
901 | new_producer.sources.push_back (sf); |
---|
902 | producers.push_back (new_producer); |
---|
903 | } |
---|
904 | } |
---|
905 | } |
---|
906 | |
---|
907 | dwarf& |
---|
908 | file::get_debug () |
---|
909 | { |
---|
910 | return debug; |
---|
911 | } |
---|
912 | |
---|
913 | compilation_units& |
---|
914 | file::get_cus () |
---|
915 | { |
---|
916 | return cus; |
---|
917 | } |
---|
918 | |
---|
919 | const std::string& |
---|
920 | file::name () const |
---|
921 | { |
---|
922 | if (!elf_) |
---|
923 | throw rld::error ("No begin called", "dwarf:fie:name"); |
---|
924 | return elf_->name (); |
---|
925 | } |
---|
926 | |
---|
927 | void |
---|
928 | file::check (const char* where) const |
---|
929 | { |
---|
930 | if (!debug || !elf_) |
---|
931 | { |
---|
932 | std::string w = where; |
---|
933 | throw rld::error ("No DWARF or ELF file", "dwarf:file:" + w); |
---|
934 | } |
---|
935 | } |
---|
936 | |
---|
937 | } |
---|
938 | } |
---|