source: rtems-tools/rtemstoolkit/rld-dwarf.cpp @ 0fe7902

Last change on this file since 0fe7902 was 0fe7902, checked in by Alex White <alex.white@…>, on 02/24/21 at 22:41:02

rld-dwarf: Fix file::get_source

The file::get_source method was giving "unknown:-1" for valid
addresses. This has been fixed.

  • Property mode set to 100644
File size: 56.5 KB
Line 
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#include <rld-symbols.h>
36
37namespace rld
38{
39  namespace dwarf
40  {
41    typedef std::vector < dwarf_die > dies_active;
42    dies_active active_dies;
43
44    bool active_dies_present (dwarf_die die)
45    {
46      return std::find (active_dies.begin(), active_dies.end(), die) != active_dies.end();
47    }
48
49    void dies_active_add (dwarf_die die)
50    {
51      if (active_dies_present (die))
52      {
53        std::cout << "DDdd : dup : " << die << std::endl;
54      }
55      else
56      {
57        active_dies.push_back (die);
58      }
59    }
60
61    void dies_active_remove (dwarf_die die)
62    {
63      dies_active::iterator di = std::find (active_dies.begin(), active_dies.end(), die);
64      if (di == active_dies.end ())
65      {
66        std::cout << "DDdd : no found : " << die << std::endl;
67      }
68      else
69      {
70        active_dies.erase (di);
71      }
72    }
73
74    /**
75     * The libdwarf error.
76     */
77    void libdwarf_error_check (const std::string where,
78                               int               result,
79                               dwarf_error&      error)
80    {
81      if (result != DW_DLV_OK)
82      {
83        std::ostringstream exe_where;
84        std::string        what;
85        exe_where << "dwarf:" << where;
86        what = ::dwarf_errmsg (error);
87        throw rld::error (what, exe_where.str ());
88      }
89    }
90
91    address::address (const sources& source, dwarf_line& line)
92      : addr (0),
93        source (&source),
94        source_index (-1),
95        source_line (-1),
96        begin_statement (false),
97        block (false),
98        end_sequence (false)
99    {
100      dwarf_error de;
101      int         dr;
102      dr = ::dwarf_lineaddr(line, &addr, &de);
103      libdwarf_error_check ("address::address", dr, de);
104      dr = ::dwarf_line_srcfileno(line, &source_index, &de);
105      libdwarf_error_check ("address::address", dr, de);
106      dwarf_unsigned src_line;
107      dr = ::dwarf_lineno(line, &src_line, &de);
108      libdwarf_error_check ("address::address", dr, de);
109      source_line = src_line;
110      dwarf_bool b;
111      dr = ::dwarf_linebeginstatement(line, &b, &de);
112      libdwarf_error_check ("address::address", dr, de);
113      begin_statement = b ? true : false;
114      dr = ::dwarf_lineblock(line, &b, &de);
115      libdwarf_error_check ("address::address", dr, de);
116      block = b ? true : false;
117      dr = ::dwarf_lineendsequence(line, &b, &de);
118      libdwarf_error_check ("address::address", dr, de);
119      end_sequence = b ? true : false;
120    }
121
122    address::address (const address& orig, const sources& source)
123      : addr (orig.addr),
124        source (&source),
125        source_index (orig.source_index),
126        source_line (orig.source_line),
127        begin_statement (orig.begin_statement),
128        block (orig.block),
129        end_sequence (orig.end_sequence)
130    {
131    }
132
133    address::address (const address& orig, dwarf_address addr)
134      : addr (addr),
135        source (orig.source),
136        source_index (orig.source_index),
137        source_line (orig.source_line),
138        begin_statement (orig.begin_statement),
139        block (orig.block),
140        end_sequence (orig.end_sequence)
141    {
142    }
143
144    address::address (const address& orig)
145      : addr (orig.addr),
146        source (orig.source),
147        source_index (orig.source_index),
148        source_line (orig.source_line),
149        begin_statement (orig.begin_statement),
150        block (orig.block),
151        end_sequence (orig.end_sequence)
152    {
153    }
154
155    address::address ()
156      : addr (0),
157        source (nullptr),
158        source_index (-1),
159        source_line (-1),
160        begin_statement (false),
161        block (false),
162        end_sequence (false)
163    {
164    }
165
166    address::~address ()
167    {
168      source = nullptr;
169      source_line = -1;
170    }
171
172    bool
173    address::valid () const
174    {
175      return source != nullptr && source_line > 0;
176    }
177
178    dwarf_address
179    address::location () const
180    {
181      return addr;
182    }
183
184    std::string
185    address::path () const
186    {
187      if (source == nullptr)
188        throw rld::error ("invalid source pointer", "dwarf:address:path");
189      return (*source)[source_index];
190    }
191
192    int
193    address::line () const
194    {
195      return source_line;
196    }
197
198    bool
199    address::is_a_begin_statement () const
200    {
201      return begin_statement;
202    }
203
204    bool
205    address::is_in_a_block () const
206    {
207      return block;
208    }
209
210    bool
211    address::is_an_end_sequence () const
212    {
213      return end_sequence;
214    }
215
216    address&
217    address::operator = (const address& rhs)
218    {
219      if (this != &rhs)
220      {
221        addr = rhs.addr;
222        source = rhs.source;
223        source_index = rhs.source_index;
224        source_line = rhs.source_line;
225        begin_statement = rhs.begin_statement;
226        block = rhs.block;
227        end_sequence = rhs.end_sequence;
228      }
229      return *this;
230    }
231
232    bool
233    address::operator < (const address& rhs) const
234    {
235      return addr < rhs.addr;
236    }
237
238    range::range (const dwarf_ranges* range)
239      : range_ (range)
240    {
241    }
242
243    range::range (const range& orig)
244      : range_ (orig.range_)
245    {
246    }
247
248    range::~range ()
249    {
250    }
251
252    dwarf_unsigned
253    range::addr1 () const
254    {
255      if (range_ == nullptr)
256        throw rld::error ("No valid range", "rld:dwarf:range:addr1");
257      return range_->dwr_addr1;
258    }
259
260    dwarf_unsigned
261    range::addr2 () const
262    {
263      if (range_ == nullptr)
264        throw rld::error ("No valid range", "rld:dwarf:range:addr2");
265      return range_->dwr_addr2;
266    }
267
268    dwarf_ranges_type
269    range::type () const
270    {
271      if (range_ == nullptr)
272        throw rld::error ("No valid range", "rld:dwarf:range:type");
273      return range_->dwr_type;
274    }
275
276    bool
277    range::empty () const
278    {
279      /**
280       * See DWARF 2.17.3.
281       *
282       * A bounded range entry whose beginning and ending address offsets are
283       * equal (including zero) indicates an empty range and may be ignored.
284       */
285      return type () == DW_RANGES_ENTRY && addr1 () == addr2 ();
286    }
287
288    bool
289    range::end () const
290    {
291      return type () == DW_RANGES_END;
292    }
293
294    range&
295    range::operator = (const range& rhs)
296    {
297      if (this != &rhs)
298        range_ = rhs.range_;
299      return *this;
300    }
301
302    void
303    range::dump (std::ostream& out) const
304    {
305      dwarf_ranges_type type_ = type ();
306      const char*       type_s = "invalid";
307      const char*       type_labels[] = {
308        "BOUNDED",
309        "BASE",
310        "END"
311      };
312      if (type_ <= DW_RANGES_END)
313        type_s = type_labels[type_];
314      out << type_s << '-'
315          << std::hex << std::setfill ('0')
316          << "0x" << std::setw (8) << addr1 ()
317          << ":0x" << std::setw (8) << addr2 ()
318          << std::dec << std::setfill (' ');
319    }
320
321    address_ranges::address_ranges (file& debug)
322      : debug (debug),
323        offset (-1),
324        dranges (nullptr),
325        dranges_count (0)
326    {
327    }
328
329    address_ranges::address_ranges (debug_info_entry& die)
330      : debug (die.get_debug ()),
331        offset (-1),
332        dranges (nullptr),
333        dranges_count (0)
334    {
335      load (die);
336    }
337
338    address_ranges::address_ranges (file& debug, dwarf_offset offset)
339      : debug (debug),
340        offset (offset),
341        dranges (nullptr),
342        dranges_count (0)
343    {
344      load (offset);
345    }
346
347    address_ranges::address_ranges (const address_ranges& orig)
348      : debug (orig.debug),
349        offset (orig.offset),
350        dranges (nullptr),
351        dranges_count (0)
352    {
353      load (orig.offset);
354    }
355
356    address_ranges::~address_ranges ()
357    {
358      if (dranges != nullptr)
359      {
360        ::dwarf_ranges_dealloc (debug, dranges, dranges_count);
361        dranges = nullptr;
362        dranges_count = 0;
363        ranges_.clear ();
364      }
365    }
366
367    bool
368    address_ranges::load (debug_info_entry& die, bool error)
369    {
370      dwarf_attribute attr;
371      dwarf_error     de;
372      int             dr;
373      dr = ::dwarf_attr (die, DW_AT_ranges, &attr, &de);
374      if (dr != DW_DLV_OK)
375      {
376        if (!error)
377          return false;
378        libdwarf_error_check ("rld:dwarf::address_ranges:load", dr, de);
379      }
380      dr = ::dwarf_global_formref (attr, &offset, &de);
381      if (dr != DW_DLV_OK)
382      {
383        if (!error)
384          return false;
385        libdwarf_error_check ("rld:dwarf::address_ranges:load", dr, de);
386      }
387      load (offset);
388      return true;
389    }
390
391    bool
392    address_ranges::load (dwarf_offset offset_, bool error)
393    {
394      if (offset_ > 0)
395      {
396        if (dranges != nullptr)
397          ::dwarf_ranges_dealloc (debug, dranges, dranges_count);
398
399        ranges_.clear ();
400
401        dranges = nullptr;
402        dranges_count = 0;
403
404        offset = offset_;
405
406        dwarf_error de;
407        int         dr;
408
409        dr = ::dwarf_get_ranges (debug, offset,
410                                 &dranges, &dranges_count, nullptr, &de);
411        if (dr != DW_DLV_OK)
412        {
413          if (!error)
414            return false;
415          libdwarf_error_check ("rld:dwarf::ranges:load", dr, de);
416        }
417
418        if (dranges != nullptr && dranges_count > 0)
419        {
420          for (dwarf_signed r = 0; r < dranges_count; ++r)
421            ranges_.push_back (range (&dranges[r]));
422        }
423      }
424
425      return true;
426    }
427
428    const ranges&
429    address_ranges::get () const
430    {
431      return ranges_;
432    }
433
434    bool
435    address_ranges::empty () const
436    {
437      return ranges_.empty ();
438    }
439
440    address_ranges&
441    address_ranges::operator = (const address_ranges& rhs)
442    {
443      if (this != &rhs)
444      {
445        if (debug != rhs.debug)
446          throw rld::error ("invalid debug", "address_ranges:=");
447        load (rhs.offset);
448      }
449      return *this;
450    }
451
452    void
453    address_ranges::dump (std::ostream& out) const
454    {
455      bool first = true;
456      out << '[';
457      for (auto& r : ranges_)
458      {
459        if (!first)
460          out << ',';
461        r.dump (out);
462        first = false;
463      }
464      out << ']';
465    }
466
467    line_addresses::line_addresses (file&             debug,
468                                    debug_info_entry& die)
469      : debug (debug),
470        lines (nullptr),
471        count_ (0)
472    {
473      if (!die.source_lines (lines, count_))
474      {
475        lines = nullptr;
476        count_ = 0;
477      }
478    }
479
480    line_addresses::~line_addresses ()
481    {
482      if (lines && count_ > 0)
483      {
484        ::dwarf_srclines_dealloc (debug, lines, count_);
485        lines = nullptr;
486        count_ = 0;
487      }
488    }
489
490    size_t
491    line_addresses::count () const
492    {
493      return count_;
494    }
495
496    dwarf_line&
497    line_addresses::operator [] (const int index)
498    {
499      if (index < 0 || index >= count_)
500        throw rld::error ("index out of range",
501                          "line_addresses:indexing");
502      return lines[index];
503    }
504
505    sources::sources (file& debug, dwarf_offset die_offset)
506      : debug (debug),
507        source (nullptr),
508        count (0),
509        die_offset (die_offset)
510    {
511      debug_info_entry die (debug, die_offset);
512      die.source_files (source, count);
513    }
514
515    sources::sources (const sources& orig)
516      : debug (orig.debug),
517        source (nullptr),
518        count (0),
519        die_offset (orig.die_offset)
520    {
521      /*
522       * In a copy constructor we need to get our own copy of the strings. To
523       * do that we need to get the DIE at the offset in the original.
524       */
525      debug_info_entry die (debug, die_offset);
526      die.source_files (source, count);
527    }
528
529    sources::~sources ()
530    {
531      dealloc ();
532    }
533
534    std::string
535    sources::operator [] (const int index) const
536    {
537      if (index <= 0 || index > count)
538        return "unknown";
539      return std::string (source[index - 1]);
540    }
541
542    void
543    sources::dealloc ()
544    {
545      if (source && count > 0)
546      {
547        /*
548         * The elftoolchain cleans the memory up and there is no compatible
549         * call we can put here so adding the required code causes is a double
550         * free resulting in a crash.
551         */
552        if (false)
553        {
554          for (int s = 0; s < count; ++s)
555            ::dwarf_dealloc (debug, source[s], DW_DLA_STRING);
556          ::dwarf_dealloc (debug, source, DW_DLA_LIST);
557        }
558        source = nullptr;
559        count = 0;
560      }
561    }
562
563    sources&
564    sources::operator = (sources&& rhs)
565    {
566      if (this != &rhs)
567      {
568        debug = rhs.debug;
569        source = rhs.source;
570        count = rhs.count;
571        die_offset = rhs.die_offset;
572        rhs.source = nullptr;
573        rhs.count = 0;
574      }
575      return *this;
576    }
577
578    variable::variable (file& debug, debug_info_entry& die)
579      : debug (debug),
580        external_ (false),
581        declaration_ (false)
582    {
583      dwarf_bool db;
584
585      if (die.attribute (DW_AT_external, db, false))
586        external_ = db ? true : false;
587
588      if (die.attribute (DW_AT_declaration, db, false))
589        declaration_ = db ? true : false;
590
591      /*
592       * Get the name attribute. (if present)
593       */
594      die.attribute (DW_AT_name, name_);
595      die.attribute (DW_AT_decl_file, decl_file_);
596      die.attribute (DW_AT_decl_line, decl_line_);
597
598      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
599      {
600        std::cout << "dwarf::variable: ";
601        dump (std::cout);
602        std::cout << std::endl;
603      }
604    }
605
606    variable::variable (const variable& orig)
607      : debug (orig.debug),
608        external_ (orig.external_),
609        declaration_ (orig.declaration_),
610        name_ (orig.name_),
611        decl_file_ (orig.decl_file_),
612        decl_line_ (orig. decl_line_)
613    {
614    }
615
616    variable::~variable ()
617    {
618    }
619
620    std::string
621    variable::name () const
622    {
623      return name_;
624    }
625
626    bool
627    variable::is_external () const
628    {
629      return external_;
630    }
631
632    bool
633    variable::is_declaration () const
634    {
635      return declaration_;
636    }
637
638    size_t
639    variable::size () const
640    {
641      size_t s = 0;
642      return s;
643    }
644
645    variable&
646    variable::operator = (const variable& rhs)
647    {
648      if (this != &rhs)
649      {
650        debug = rhs.debug;
651        external_ = rhs.external_;
652        declaration_ = rhs.declaration_;
653        name_ = rhs.name_;
654        decl_file_ = rhs.decl_file_;
655        decl_line_ = rhs.decl_line_;
656      }
657      return *this;
658    }
659
660    void
661    variable::dump (std::ostream& out) const
662    {
663      if (name_.empty ())
664        out << "NO-NAME";
665      else
666        out << name_;
667      out << " ["
668          << (char) (external_ ? 'E' : '-')
669          << (char) (declaration_ ? 'D' : '-')
670          << "] size=" << size ()
671          << std::hex << std::setfill ('0')
672          << " (0x" << size () << ')'
673          << std::dec << std::setfill (' ');
674    }
675
676
677    function::function (file& debug, debug_info_entry& die)
678      : debug (debug),
679        machine_code_ (false),
680        external_ (false),
681        declaration_ (false),
682        inline_ (DW_INL_not_inlined),
683        entry_pc_ (0),
684        has_entry_pc_ (false),
685        pc_low_ (0),
686        pc_high_ (0),
687        ranges_ (debug),
688        call_line_ (0)
689    {
690      dwarf_bool db;
691
692      if (die.attribute (DW_AT_external, db, false))
693        external_ = db ? true : false;
694
695      if (die.attribute (DW_AT_declaration, db, false))
696        declaration_ = db ? true : false;
697
698      if (die.attribute (DW_AT_entry_pc, entry_pc_, false))
699        has_entry_pc_ = true;
700
701      die.attribute (DW_AT_linkage_name, linkage_name_, false);
702      die.attribute (DW_AT_call_file, decl_file_, false);
703      die.attribute (DW_AT_call_line, decl_line_, false);
704      die.attribute (DW_AT_call_file, call_file_, false);
705      die.attribute (DW_AT_call_line, call_line_, false);
706
707      if (!die.attribute (DW_AT_inline, inline_, false))
708        inline_ = DW_INL_not_inlined;
709
710      /*
711       * If ranges are not found see if the PC low and PC high attributes
712       * can be found.
713       */
714      ranges_.load (die, false);
715      if (ranges_.empty ())
716      {
717        bool is_address;
718        if (die.get_lowpc (pc_low_) && die.get_highpc (pc_high_, is_address))
719        {
720          machine_code_ = true;
721          if (!is_address)
722            pc_high_ += pc_low_;
723        }
724      }
725      else
726      {
727        for (auto& r : ranges_.get ())
728        {
729          if (!r.end () && !r.empty ())
730          {
731            machine_code_ = true;
732            break;
733          }
734        }
735      }
736
737      /*
738       * Get the name attribute. (if present)
739       */
740      if (!die.attribute (DW_AT_name, name_, false))
741      {
742        bool found = false;
743
744        /*
745         * For inlined function, the actual name is probably in the DIE
746         * referenced by DW_AT_abstract_origin. (if present)
747         */
748        dwarf_attribute abst_at;
749        if (die.attribute (DW_AT_abstract_origin, abst_at, false))
750        {
751          dwarf_offset abst_at_die_offset;
752          dwarf_error  de;
753          int          dr;
754          dr = ::dwarf_global_formref (abst_at, &abst_at_die_offset, &de);
755          if (dr == DW_DLV_OK)
756          {
757            debug_info_entry abst_at_die (debug, abst_at_die_offset);
758            if (abst_at_die.attribute (DW_AT_name, name_, false))
759            {
760              found = true;
761              abst_at_die.attribute (DW_AT_inline, inline_, false);
762              if (abst_at_die.attribute (DW_AT_external, db, false))
763                external_ = db ? true : false;
764              if (abst_at_die.attribute (DW_AT_declaration, db, false))
765                declaration_ = db ? true : false;
766              abst_at_die.attribute (DW_AT_linkage_name, linkage_name_, false);
767              abst_at_die.attribute (DW_AT_decl_file, decl_file_, false);
768              abst_at_die.attribute (DW_AT_decl_line, decl_line_, false);
769            }
770          }
771        }
772
773        /*
774         * If DW_AT_name is not present, but DW_AT_specification is present,
775         * then probably the actual name is in the DIE referenced by
776         * DW_AT_specification.
777         */
778        if (!found)
779        {
780          dwarf_attribute spec;
781          if (die.attribute (DW_AT_specification, spec, false))
782          {
783            dwarf_offset spec_die_offset;
784            dwarf_error  de;
785            int          dr;
786            dr = ::dwarf_global_formref (spec, &spec_die_offset, &de);
787            if (dr == DW_DLV_OK)
788            {
789              debug_info_entry spec_die (debug, spec_die_offset);
790              if (spec_die.attribute (DW_AT_name, name_, false))
791              {
792                found = true;
793                if (spec_die.attribute (DW_AT_external, db, false))
794                  external_ = db ? true : false;
795                if (spec_die.attribute (DW_AT_declaration, db, false))
796                  declaration_ = db ? true : false;
797                spec_die.attribute (DW_AT_linkage_name, linkage_name_, false);
798                spec_die.attribute (DW_AT_decl_file, decl_file_, false);
799                spec_die.attribute (DW_AT_decl_line, decl_line_, false);
800              }
801            }
802          }
803        }
804      }
805
806      if (!linkage_name_.empty() && name_.empty())
807        rld::symbols::demangle_name(linkage_name_, name_);
808
809      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
810      {
811        std::cout << "dwarf::function: ";
812        dump (std::cout);
813        std::cout << std::endl;
814      }
815    }
816
817    function::function (const function& orig)
818      : debug (orig.debug),
819        machine_code_ (orig.machine_code_),
820        external_ (orig.external_),
821        declaration_ (orig.declaration_),
822        inline_ (orig.inline_),
823        entry_pc_ (orig.entry_pc_),
824        has_entry_pc_ (orig.has_entry_pc_),
825        pc_low_ (orig.pc_low_),
826        pc_high_ (orig.pc_high_),
827        ranges_ (orig.ranges_),
828        name_ (orig.name_),
829        linkage_name_ (orig.linkage_name_),
830        call_file_ (orig.call_file_),
831        call_line_ (orig.call_line_)
832    {
833    }
834
835    function::~function ()
836    {
837    }
838
839    std::string
840    function::name () const
841    {
842      return name_;
843    }
844
845    const address_ranges&
846    function::get_ranges () const
847    {
848      return ranges_;
849    }
850
851    dwarf_unsigned
852    function::pc_low () const
853    {
854      dwarf_address addr = pc_low_;
855      if (!ranges_.empty ())
856      {
857        addr = ~0;
858        for (auto& r : ranges_.get ())
859        {
860          if (!r.end () && !r.empty () && r.addr1 () < addr)
861            addr = r.addr1 ();
862        }
863      }
864      if (has_entry_pc_ && addr < entry_pc_)
865        addr += entry_pc_;
866      return addr;
867    }
868
869    dwarf_unsigned
870    function::pc_high () const
871    {
872      dwarf_address addr = pc_high_;
873      if (!ranges_.empty ())
874      {
875        addr = 0;
876        for (auto& r : ranges_.get ())
877        {
878          if (!r.end () && !r.empty () && r.addr2 () > addr)
879            addr = r.addr2 ();
880        }
881      }
882      if (has_entry_pc_ && addr < entry_pc_)
883        addr += entry_pc_;
884      return addr;
885    }
886
887    bool
888    function::has_entry_pc () const
889    {
890      return has_entry_pc_;
891    }
892
893    bool
894    function::has_machine_code () const
895    {
896      return machine_code_;
897    }
898
899    bool
900    function::is_external () const
901    {
902      return external_;
903    }
904
905    bool
906    function::is_declaration () const
907    {
908      return declaration_;
909    }
910
911    bool
912    function::is_inlined () const
913    {
914      return inline_ == DW_INL_inlined || inline_ == DW_INL_declared_inlined;
915    }
916
917    function::inlined
918    function::get_inlined () const
919    {
920      inlined i = inl_not_inlined;
921      switch (inline_)
922      {
923        default:
924        case DW_INL_not_inlined:
925          break;
926        case DW_INL_inlined:
927          i = inl_inline;
928          break;
929        case DW_INL_declared_not_inlined:
930          i = inl_declared_not_inlined;
931          break;
932        case DW_INL_declared_inlined:
933          i = inl_declared_inlined;
934          break;
935      }
936      return i;
937    }
938
939    std::string
940    function::call_file () const
941    {
942      return call_file_;
943    }
944
945    bool
946    function::inside (dwarf_address addr) const
947    {
948      return !name_.empty () && has_machine_code () &&
949        addr >= pc_low () && addr <= pc_high ();
950    }
951
952    size_t
953    function::size () const
954    {
955      size_t s = 0;
956      if (!name_.empty () && has_machine_code ())
957      {
958        if (ranges_.empty ())
959          s = pc_high () - pc_low ();
960        else
961        {
962          for (auto& r : ranges_.get ())
963          {
964            if (!r.end () && !r.empty ())
965              s += r.addr2 () - r.addr1 ();
966          }
967        }
968      }
969      return s;
970    }
971
972    function&
973    function::operator = (const function& rhs)
974    {
975      if (this != &rhs)
976      {
977        debug = rhs.debug;
978        machine_code_ = rhs.machine_code_;
979        external_ = rhs.external_;
980        declaration_ = rhs.declaration_;
981        inline_ = rhs.inline_;
982        entry_pc_ = rhs.entry_pc_;
983        has_entry_pc_ = rhs.has_entry_pc_;
984        pc_low_ = rhs.pc_low_;
985        pc_high_ = rhs.pc_high_;
986        ranges_ = rhs.ranges_;
987        name_ = rhs.name_;
988        linkage_name_ = rhs.linkage_name_;
989        call_file_ = rhs.call_file_;
990      }
991      return *this;
992    }
993
994    void
995    function::dump (std::ostream& out) const
996    {
997      if (name_.empty ())
998        out << "NO-NAME";
999      else
1000        out << name_;
1001      out << " ["
1002          << (char) (machine_code_ ? 'M' : '-')
1003          << (char) (external_ ? 'E' : '-')
1004          << (char) (declaration_ ? 'D' : '-')
1005          << (char) (is_inlined () ? 'I' : '-')
1006          << (char) (has_entry_pc_ ? 'P' : '-')
1007          << "] size=" << size ()
1008          << std::hex << std::setfill ('0')
1009          << " (0x" << size () << ')';
1010      if (has_entry_pc_)
1011        out << " epc=0x" << entry_pc_;
1012      out << " pc_low=0x" << pc_low_
1013          << " pc_high=0x" << pc_high_;
1014      if (!linkage_name_.empty ())
1015      {
1016        std::string show_name;
1017        rld::symbols::demangle_name(linkage_name_, show_name);
1018        out << " ln=" << show_name;
1019      }
1020      out << std::dec << std::setfill (' ');
1021      if (!call_file_.empty ())
1022        out << " cf=" << call_file_ << ':' << call_line_;
1023      if (!ranges_.empty ())
1024      {
1025        out << " ranges=";
1026        ranges_.dump (out);
1027      }
1028    }
1029
1030    bool
1031    function_compare::operator () (const function& a,
1032                                   const function& b) const
1033    {
1034      bool r = true;
1035
1036      switch (by)
1037      {
1038        case fc_by_name:
1039        default:
1040          r =  a.name () < b.name ();
1041          break;
1042        case fc_by_size:
1043          r = a.size () < b.size ();
1044          break;
1045        case fc_by_address:
1046          r = a.pc_low () < b.pc_low ();
1047          break;
1048      }
1049
1050      return r;
1051    }
1052
1053    function_compare:: function_compare (const function_compare::sort_by by)
1054      : by (by)
1055    {
1056    }
1057
1058    debug_info_entry::debug_info_entry (file& debug)
1059      : debug (debug),
1060        die (nullptr),
1061        tag_ (0),
1062        offset_ (0)
1063    {
1064    }
1065
1066    debug_info_entry::debug_info_entry (file& debug, dwarf_die& die)
1067      : debug (debug),
1068        die (die),
1069        tag_ (0),
1070        offset_ (0)
1071    {
1072      update ();
1073    }
1074
1075    debug_info_entry::debug_info_entry (file& debug, dwarf_offset offset__)
1076      : debug (debug),
1077        die (nullptr),
1078        tag_ (0),
1079        offset_ (offset__)
1080    {
1081      update ();
1082    }
1083
1084    debug_info_entry::debug_info_entry (const debug_info_entry& orig)
1085      : debug (orig.debug),
1086        die (nullptr),
1087        tag_ (orig.tag_),
1088        offset_ (orig.offset_)
1089    {
1090      update ();
1091    }
1092
1093    debug_info_entry::~debug_info_entry ()
1094    {
1095      dealloc ();
1096    }
1097
1098    void
1099    debug_info_entry::update ()
1100    {
1101      dwarf_error de;
1102      int         dr;
1103      if (offset_ == 0 && die != nullptr)
1104      {
1105        dr = ::dwarf_dieoffset (die, &offset_, &de);
1106        libdwarf_error_check ("debug_info_entry:update", dr, de);
1107      }
1108      if (offset_ != 0 && die == nullptr)
1109      {
1110        dwarf_die ddie;
1111        dr = ::dwarf_offdie (debug, offset_, &ddie, &de);
1112        libdwarf_error_check ("debug_info_entry:update", dr, de);
1113        die = ddie;
1114      }
1115      valid ();
1116    }
1117
1118    bool
1119    debug_info_entry::valid (bool fatal) const
1120    {
1121      bool r = die == nullptr || offset_ == 0;
1122      if (r && fatal)
1123      {
1124        std::string what = "no DIE and offset";
1125        if (offset_ != 0)
1126          what = "no DIE";
1127        else if (die != nullptr)
1128          what = "no offset";
1129        throw rld::error (what, "debug_info_entry:valid");
1130      }
1131      return r;
1132    }
1133
1134    dwarf_die
1135    debug_info_entry::get () const
1136    {
1137      return die;
1138    }
1139
1140    debug_info_entry::operator dwarf_die& ()
1141    {
1142      return die;
1143    }
1144
1145    debug_info_entry::operator dwarf_die* ()
1146    {
1147      return &die;
1148    }
1149
1150    debug_info_entry&
1151    debug_info_entry::operator = (debug_info_entry& rhs)
1152    {
1153      if (this != &rhs)
1154      {
1155        if (debug != rhs.debug)
1156          throw rld::error ("DIE debug info mismatch",
1157                            "dwarf:debug_info_entry:operator=");
1158        dealloc ();
1159        die = rhs.die;
1160        tag_ = rhs.tag_;
1161        offset_ = rhs.offset_;
1162        rhs.die = nullptr;
1163        if (offset_ != 0 || die != nullptr)
1164          update ();
1165      }
1166      return *this;
1167    }
1168
1169    debug_info_entry&
1170    debug_info_entry::operator = (dwarf_offset offset__)
1171    {
1172      dealloc ();
1173      if (offset__ != 0)
1174      {
1175        offset_ = offset__;
1176        tag_ = 0;
1177        update ();
1178      }
1179      return *this;
1180    }
1181
1182    bool
1183    debug_info_entry::operator == (debug_info_entry& rhs) const
1184    {
1185      return debug == rhs.debug && die == rhs.die &&
1186        tag_ == rhs.tag_ && offset_ == rhs.offset_;
1187    }
1188
1189    bool
1190    debug_info_entry::operator == (const dwarf_die rhs) const
1191    {
1192      return die == rhs;
1193    }
1194
1195    dwarf_tag
1196    debug_info_entry::tag ()
1197    {
1198      if (tag_ == 0)
1199      {
1200        dwarf_error de;
1201        int         dr;
1202        dr = ::dwarf_tag (die, &tag_, &de);
1203        libdwarf_error_check ("debug_info_entry:tag", dr, de);
1204      }
1205      return tag_;
1206    }
1207
1208    dwarf_offset
1209    debug_info_entry::offset ()
1210    {
1211      if (offset_ == 0)
1212      {
1213        dwarf_error de;
1214        int         dr;
1215        dr = ::dwarf_dieoffset (die, &offset_, &de);
1216        libdwarf_error_check ("debug_info_entry:offset", dr, de);
1217      }
1218      return offset_;
1219    }
1220
1221    bool
1222    debug_info_entry::get_lowpc (dwarf_address& addr, bool error) const
1223    {
1224      dwarf_error de;
1225      int         dr;
1226      dr = ::dwarf_lowpc (die, &addr, &de);
1227      if (error)
1228        libdwarf_error_check ("debug_info_entry:lowpc", dr, de);
1229      return dr == DW_DLV_OK;
1230    }
1231
1232    bool
1233    debug_info_entry::get_highpc (dwarf_address& addr,
1234                                  bool&          is_address,
1235                                  bool           error) const
1236    {
1237      dwarf_half       form;
1238      dwarf_form_class class_;
1239      dwarf_error      de;
1240      int              dr;
1241      dr = ::dwarf_highpc_b (die, &addr, &form, &class_, &de);
1242      if (error)
1243        libdwarf_error_check ("debug_info_entry:highpc", dr, de);
1244      is_address = class_ == DW_FORM_CLASS_ADDRESS;
1245      return dr == DW_DLV_OK;
1246    }
1247
1248    bool
1249    debug_info_entry::attribute (dwarf_attr       attr,
1250                                 dwarf_attribute& value,
1251                                 bool             error) const
1252    {
1253      dwarf_error de;
1254      int         dr;
1255      dr = ::dwarf_attr (die, attr, &value, &de);
1256      if (error)
1257        libdwarf_error_check ("debug_info_entry:attribute(attr)", dr, de);
1258      return dr == DW_DLV_OK;
1259    }
1260
1261    bool
1262    debug_info_entry::attribute (dwarf_attr  attr,
1263                                 dwarf_bool& value,
1264                                 bool        error) const
1265    {
1266      dwarf_error de;
1267      int         dr;
1268      dr = ::dwarf_attrval_flag (die, attr, &value, &de);
1269      if (error)
1270        libdwarf_error_check ("debug_info_entry:attribute(flag)", dr, de);
1271      return dr == DW_DLV_OK;
1272    }
1273
1274    bool
1275    debug_info_entry::attribute (dwarf_attr      attr,
1276                                 dwarf_unsigned& value,
1277                                 bool            error) const
1278    {
1279      dwarf_error de;
1280      int         dr;
1281      dr = ::dwarf_attrval_unsigned (die, attr, &value, &de);
1282      if (error)
1283        libdwarf_error_check ("debug_info_entry:attribute(unsigned)", dr, de);
1284      return dr == DW_DLV_OK;
1285    }
1286
1287    bool
1288    debug_info_entry::attribute (dwarf_attr   attr,
1289                                 std::string& value,
1290                                 bool         error) const
1291    {
1292      dwarf_error de;
1293      int         dr;
1294      const char* s = nullptr;
1295      value.clear ();
1296      dr = ::dwarf_attrval_string (die, attr, &s, &de);
1297      if (error)
1298        libdwarf_error_check ("debug_info_entry:attribute(string)", dr, de);
1299      if (s != nullptr)
1300        value = s;
1301      return dr == DW_DLV_OK;
1302    }
1303
1304    bool
1305    debug_info_entry::source_lines (dwarf_line*&  lines,
1306                                    dwarf_signed& linecount) const
1307    {
1308      dwarf_error de;
1309      int         dr;
1310      if (lines != nullptr)
1311        throw rld::error ("lines is not null", "debug_info_entry:source_lines");
1312      linecount = 0;
1313      dr = ::dwarf_srclines (die, &lines, &linecount, &de);
1314      if (dr ==  DW_DLV_NO_ENTRY)
1315        return false;
1316      libdwarf_error_check ("debug_info_entry:source_lines ", dr, de);
1317      return true;
1318    }
1319
1320    void
1321    debug_info_entry::source_files (char**&       sources,
1322                                    dwarf_signed& sourcecount) const
1323    {
1324      dwarf_error de;
1325      int         dr;
1326      dr = ::dwarf_srcfiles (die, &sources, &sourcecount, &de);
1327      libdwarf_error_check ("debug_info_entry:source_files ", dr, de);
1328    }
1329
1330    bool
1331    debug_info_entry::ranges (dwarf_ranges*& ranges,
1332                              dwarf_signed&  rangescount) const
1333    {
1334      dwarf_unsigned ranges_off;
1335      if (attribute (DW_AT_ranges, ranges_off, false))
1336      {
1337        dwarf_error de;
1338        int         dr;
1339        dr = ::dwarf_get_ranges (debug, ranges_off,
1340                                 &ranges, &rangescount, nullptr, &de);
1341        libdwarf_error_check ("debug_info_entry:ranges ", dr, de);
1342        return ranges != nullptr && rangescount > 0;
1343      }
1344      return false;
1345    }
1346
1347    bool
1348    debug_info_entry::get_child (debug_info_entry& child_die)
1349    {
1350      debug_info_entry ret_die (get_debug ());
1351      dwarf_error      de;
1352      int              dr;
1353      dr = ::dwarf_child (die, ret_die, &de);
1354      if (dr == DW_DLV_OK)
1355      {
1356        ret_die.update ();
1357        child_die = ret_die;
1358        child_die.valid ();
1359      }
1360      return dr == DW_DLV_OK;
1361    }
1362
1363    bool
1364    debug_info_entry::has_child () const
1365    {
1366      debug_info_entry ret_die (get_debug ());
1367      dwarf_error      de;
1368      int              dr;
1369      dr = ::dwarf_child (die, ret_die, &de);
1370      return dr == DW_DLV_OK;
1371    }
1372
1373    bool
1374    debug_info_entry::get_sibling (debug_info_entry& sibling_die)
1375    {
1376      debug_info_entry ret_die (get_debug ());
1377      dwarf_error      de;
1378      int              dr;
1379      dr = ::dwarf_siblingof (debug, die, ret_die, &de);
1380      if (dr == DW_DLV_NO_ENTRY)
1381        return false;
1382      libdwarf_error_check ("compilation_unit::sibling", dr, de);
1383      sibling_die = ret_die;
1384      return true;
1385    }
1386
1387    bool
1388    debug_info_entry::has_sibling () const
1389    {
1390      debug_info_entry ret_die (get_debug ());
1391      dwarf_error      de;
1392      int              dr;
1393      dr = ::dwarf_siblingof (debug, die, ret_die, &de);
1394      return dr == DW_DLV_OK;
1395    }
1396
1397    file&
1398    debug_info_entry::get_debug () const
1399    {
1400      return debug;
1401    }
1402
1403    void
1404    debug_info_entry::dealloc ()
1405    {
1406      if (die != nullptr) {
1407        ::dwarf_dealloc (debug, die, DW_DLA_DIE);
1408        die = nullptr;
1409      }
1410    }
1411
1412    void
1413    debug_info_entry::dump (std::ostream& out,
1414                            std::string   prefix,
1415                            bool          newline)
1416    {
1417      std::string level_prefix;
1418
1419      for (auto c : prefix)
1420      {
1421        switch (c)
1422        {
1423          case '+':
1424            c = '|';
1425            break;
1426          case '-':
1427            c = ' ';
1428            break;
1429          default:
1430            break;
1431        }
1432        level_prefix += c;
1433      }
1434
1435      const char* s;
1436      ::dwarf_get_TAG_name (tag (), &s);
1437      out << level_prefix.substr (0, level_prefix.length () - 1)
1438          << "+- " << s << " ("
1439          << std::hex << std::setfill ('0')
1440          << std::setw (8) << offset_
1441          << std::dec << std::setfill (' ')
1442          << ')' << std::endl;
1443
1444      dwarf_attribute* attributes;
1445      dwarf_signed     attr_count;
1446      dwarf_error      de;
1447      int              dr;
1448
1449      dr = ::dwarf_attrlist (die, &attributes, &attr_count, &de);
1450      if (dr == DW_DLV_OK)
1451      {
1452        for (int a = 0; a < attr_count; ++a)
1453        {
1454          dwarf_attr attr;
1455          dr = ::dwarf_whatattr (attributes[a], &attr, &de);
1456          libdwarf_error_check ("debug_info_entry::dump", dr, de);
1457          dwarf_half form;
1458          dr = ::dwarf_whatform (attributes[a], &form, &de);
1459          libdwarf_error_check ("debug_info_entry::dump", dr, de);
1460          const char* f;
1461          dwarf_get_FORM_name (form, &f);
1462          dwarf_get_AT_name (attr, &s);
1463          if (a > 0)
1464            out << std::endl;
1465          out << level_prefix << " +- "
1466              << s << " (" << attr << ") [" << f << ']';
1467          debug_info_entry v_die (debug);
1468          address_ranges   v_ranges (debug);
1469          dwarf_unsigned   v_unsigned;
1470          dwarf_bool       v_bool;
1471          dwarf_offset     v_offset;
1472          switch (form)
1473          {
1474            case DW_FORM_block:
1475            case DW_FORM_block1:
1476            case DW_FORM_block2:
1477            case DW_FORM_block4:
1478              break;
1479            case DW_FORM_addr:
1480            case DW_FORM_data1:
1481            case DW_FORM_data2:
1482            case DW_FORM_data4:
1483            case DW_FORM_data8:
1484            case DW_FORM_udata:
1485              dr = ::dwarf_attrval_unsigned (die, attr, &v_unsigned, &de);
1486              libdwarf_error_check ("debug_info_entry::dump", dr, de);
1487              s = "";
1488              switch (attr)
1489              {
1490                case DW_AT_inline:
1491                  dwarf_get_INL_name(v_unsigned, &s);
1492                  break;
1493                default:
1494                  break;
1495              }
1496              out << " : "
1497                  << std::hex << std::setfill ('0')
1498                  << std::setw (8) << v_unsigned
1499                  << std::dec << std::setfill (' ')
1500                  << " (" << v_unsigned << ") " << s;
1501              break;
1502            case DW_FORM_ref1:
1503            case DW_FORM_ref2:
1504            case DW_FORM_ref4:
1505            case DW_FORM_ref8:
1506            case DW_FORM_ref_udata:
1507              dr = ::dwarf_global_formref (attributes[a], &v_offset, &de);
1508              libdwarf_error_check ("debug_info_entry::dump", dr, de);
1509              out << " : "
1510                  << std::hex << std::setfill ('0')
1511                  << std::setw (8) << v_offset
1512                  << std::dec << std::setfill (' ')
1513                  << " (" << v_offset << ')';
1514              switch (attr)
1515              {
1516                case DW_AT_abstract_origin:
1517                case DW_AT_specification:
1518                  v_die = v_offset;
1519                  out << std::endl;
1520                  v_die.dump (out, prefix + " |  ", false);
1521                  break;
1522                default:
1523                  break;
1524              }
1525              break;
1526            case DW_FORM_exprloc:
1527              break;
1528            case DW_FORM_flag:
1529            case DW_FORM_flag_present:
1530              dr = ::dwarf_attrval_flag (die, attr, &v_bool, &de);
1531              libdwarf_error_check ("debug_info_entry::dump", dr, de);
1532              out << " : " << v_bool;
1533              break;
1534              break;
1535            case DW_FORM_string:
1536            case DW_FORM_strp:
1537              dr = ::dwarf_attrval_string (die, attr, &s, &de);
1538              libdwarf_error_check ("debug_info_entry::dump", dr, de);
1539              out << " : " << s;
1540              if (rld::symbols::is_cplusplus(s))
1541              {
1542                std::string cpps;
1543                rld::symbols::demangle_name(s, cpps);
1544                out << " `" << cpps << '`';
1545              }
1546              break;
1547            case DW_FORM_sec_offset:
1548              switch (attr)
1549              {
1550                case DW_AT_ranges:
1551                  dr = ::dwarf_global_formref (attributes[a], &v_offset, &de);
1552                  libdwarf_error_check ("debug_info_entry::dump", dr, de);
1553                  out << ' ';
1554                  v_ranges.load (v_offset);
1555                  v_ranges.dump (out);
1556                  break;
1557                default:
1558                  break;
1559              }
1560              break;
1561            case DW_FORM_indirect:
1562            case DW_FORM_ref_addr:
1563            case DW_FORM_ref_sig8:
1564            case DW_FORM_sdata:
1565              break;
1566          }
1567        }
1568        if (newline)
1569          out <<  std::endl;
1570      }
1571    }
1572
1573    void
1574    die_dump_children (debug_info_entry& die,
1575                       std::ostream&     out,
1576                       std::string       prefix,
1577                       int               depth,
1578                       int               nesting)
1579    {
1580      debug_info_entry child (die.get_debug ());
1581      if (die.get_child (child))
1582        die_dump (child, out, prefix, depth, nesting);
1583    }
1584
1585    void
1586    die_dump (debug_info_entry& die,
1587              std::ostream&     out,
1588              std::string       prefix,
1589              int               depth,
1590              int               nesting)
1591    {
1592      ++nesting;
1593
1594      while (true)
1595      {
1596        char v = die.has_sibling () || die.has_child () ? '+' : ' ';
1597
1598        die.dump (out, prefix + v);
1599
1600        if (depth < 0 || nesting < depth)
1601          die_dump_children (die, out, prefix + "+   ", depth, nesting);
1602
1603        debug_info_entry next (die.get_debug ());
1604
1605        if (!die.get_sibling (next))
1606          break;
1607
1608        die = next;
1609      }
1610    }
1611
1612    compilation_unit::compilation_unit (file&             debug,
1613                                        debug_info_entry& die,
1614                                        dwarf_unsigned    offset)
1615      : debug (debug),
1616        offset_ (offset),
1617        pc_low_ (0),
1618        pc_high_ (0),
1619        ranges_ (debug),
1620        die_offset (die.offset ()),
1621        source_ (debug, die_offset)
1622    {
1623      die.attribute (DW_AT_name, name_);
1624
1625      die.attribute (DW_AT_producer, producer_);
1626
1627      ranges_.load (die, false);
1628
1629      if (ranges_.empty ())
1630      {
1631        bool is_address;
1632        die.get_lowpc (pc_low_);
1633        if (die.get_highpc (pc_high_, is_address))
1634        {
1635          if (!is_address)
1636            pc_high_ += pc_low_;
1637        }
1638        else
1639          pc_high_ = ~0U;
1640      }
1641      else
1642      {
1643        pc_low_ = ~0U;
1644        for (auto& r : ranges_.get ())
1645        {
1646          if (!r.end () && !r.empty () && r.addr1 () < pc_low_)
1647            pc_low_ = r.addr1 ();
1648        }
1649        pc_high_ = 0U;
1650        for (auto& r : ranges_.get ())
1651        {
1652          if (!r.end () && !r.empty () && r.addr2 () > pc_high_)
1653            pc_high_ = r.addr2 ();
1654        }
1655      }
1656
1657      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
1658      {
1659        std::cout << std::hex << std::setfill ('0')
1660                  << "dwarf::compilation_unit: "
1661                  << rld::path::basename (name_)
1662                  << ": (0x" << std::setw (8) << offset_ << ") ";
1663        if (pc_low_ != 0 && pc_high_ != ~0U)
1664          std::cout << "pc_low = 0x" << std::setw (8) << pc_low_
1665                    << " pc_high = 0x" << std::setw (8) << pc_high_;
1666       std::cout  << std::setfill (' ') << std::dec
1667                  << std::endl
1668                  << " ] " << producer_
1669                  << std::endl;
1670      }
1671
1672      line_addresses lines (debug, die);
1673      dwarf_address  pc = 0;
1674      bool           seq_check = true;
1675      dwarf_address  seq_base = 0;
1676
1677      for (size_t l = 0; l < lines.count (); ++l)
1678      {
1679        address       daddr (source_, lines[l]);
1680        dwarf_address loc = daddr.location ();
1681        /*
1682         * A CU's line program can have some sequences at the start where the
1683         * address is incorrectly set to 0. Ignore these entries.
1684         */
1685        if (pc == 0)
1686        {
1687          if (!seq_check)
1688          {
1689            seq_check = daddr.is_an_end_sequence ();
1690            continue;
1691          }
1692          if (loc == 0)
1693          {
1694            seq_check = false;
1695            continue;
1696          }
1697        }
1698        /*
1699         * A sequence of line program instruction may set the address to 0. Use
1700         * the last location from the previous sequence as the sequence's base
1701         * address. All locations will be offset from the that base until the
1702         * end of this sequence.
1703         */
1704        if (loc == 0 && seq_base == 0)
1705          seq_base = pc;
1706        if (seq_base != 0)
1707          loc += seq_base;
1708        if (daddr.is_an_end_sequence ())
1709          seq_base = 0;
1710        address addr (daddr, loc);
1711        if (loc >= pc_low_ && loc <= pc_high_)
1712        {
1713          pc = loc;
1714          addr_lines_.push_back (addr);
1715        }
1716      }
1717
1718      if (!addr_lines_.empty ())
1719      {
1720        std::stable_sort (addr_lines_.begin (), addr_lines_.end ());
1721        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
1722        {
1723          auto first = addr_lines_.begin ();
1724          auto last = addr_lines_.end () - 1;
1725          std::cout << "dwarf::compilation_unit: line_low=0x"
1726                    << std::hex << std::setfill('0')
1727                    << std::setw (8) << first->location ()
1728                    << ", line_high=0x"
1729                    << std::setw (8) << last->location ()
1730                    << std::dec << std::setfill(' ')
1731                    << std::endl;
1732        }
1733      }
1734
1735      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
1736      {
1737        int lc = 0;
1738        for (auto& l : addr_lines_)
1739        {
1740          std::cout << "dwarf::compilation_unit: " << std::setw (3) << ++lc
1741                    << ": 0x"
1742                    << std::hex << std::setfill('0')
1743                    << std::setw (8) << l.location ()
1744                    << std::dec << std::setfill(' ')
1745                    << " - "
1746                    << (char) (l.is_a_begin_statement () ? 'B' : '.')
1747                    << (char) (l.is_in_a_block () ? 'I' : '.')
1748                    << (char) (l.is_an_end_sequence () ? 'E' : '.')
1749                    << " - "
1750                    << rld::path::basename (l.path ())
1751                    << ':' <<l.line ()
1752                    << std::endl;
1753        }
1754      }
1755    }
1756
1757    compilation_unit::compilation_unit (const compilation_unit& orig)
1758      : debug (orig.debug),
1759        offset_ (orig.offset_),
1760        name_ (orig.name_),
1761        producer_ (orig.producer_),
1762        pc_low_ (orig.pc_low_),
1763        pc_high_ (orig.pc_high_),
1764        ranges_ (orig.ranges_),
1765        die_offset (orig.die_offset),
1766        source_ (debug, die_offset)
1767    {
1768      for (auto& line : orig.addr_lines_)
1769        addr_lines_.push_back (address (line, source_));
1770      std::stable_sort (addr_lines_.begin (), addr_lines_.end ());
1771    }
1772
1773    compilation_unit::~compilation_unit ()
1774    {
1775    }
1776
1777    void
1778    compilation_unit::load_types ()
1779    {
1780      //dump_die ();
1781    }
1782
1783    void
1784    compilation_unit::load_variables ()
1785    {
1786      debug_info_entry die (debug, die_offset);
1787      debug_info_entry child (debug);
1788      if (die.get_child (child))
1789        load_variables (child);
1790    }
1791
1792    void
1793    compilation_unit::load_variables (debug_info_entry& die)
1794    {
1795      while (true)
1796      {
1797        if (die.tag () == DW_TAG_variable)
1798        {
1799          function func (debug, die);
1800          functions_.push_back (func);
1801        }
1802
1803        debug_info_entry next (die.get_debug ());
1804
1805        if (die.get_child (next))
1806          load_functions (next);
1807
1808        if (!die.get_sibling (next))
1809          break;
1810
1811        die = next;
1812      }
1813    }
1814
1815    void
1816    compilation_unit::load_functions ()
1817    {
1818      debug_info_entry die (debug, die_offset);
1819      debug_info_entry child (debug);
1820      if (die.get_child (child))
1821        load_functions (child);
1822    }
1823
1824    void
1825    compilation_unit::load_functions (debug_info_entry& die)
1826    {
1827      while (true)
1828      {
1829        if (die.tag () == DW_TAG_subprogram ||
1830            die.tag () == DW_TAG_entry_point ||
1831            die.tag () == DW_TAG_inlined_subroutine)
1832        {
1833          function func (debug, die);
1834          functions_.push_back (func);
1835        }
1836
1837        debug_info_entry next (die.get_debug ());
1838
1839        if (die.get_child (next))
1840          load_functions (next);
1841
1842        if (!die.get_sibling (next))
1843          break;
1844
1845        die = next;
1846      }
1847    }
1848
1849    std::string
1850    compilation_unit::name () const
1851    {
1852      return name_;
1853    }
1854
1855    std::string
1856    compilation_unit::producer () const
1857    {
1858      return producer_;
1859    }
1860
1861    unsigned int
1862    compilation_unit::pc_low () const
1863    {
1864      return pc_low_;
1865    }
1866
1867    unsigned int
1868    compilation_unit::pc_high () const
1869    {
1870      return pc_high_;
1871    }
1872
1873    bool
1874    compilation_unit::get_source (const dwarf_address addr,
1875                                  address&            addr_line)
1876    {
1877      if (!addr_lines_.empty () && inside (addr))
1878      {
1879        address last_loc;
1880        for (auto& loc : addr_lines_)
1881        {
1882          if (addr <= loc.location ())
1883          {
1884            if (addr == loc.location ())
1885              addr_line = loc;
1886            else
1887              addr_line = last_loc;
1888            return addr_line.valid ();
1889          }
1890          last_loc = loc;
1891        }
1892      }
1893      return false;
1894    }
1895
1896    functions&
1897    compilation_unit::get_functions ()
1898    {
1899      return functions_;
1900    }
1901
1902    bool
1903    compilation_unit::inside (dwarf_unsigned addr) const
1904    {
1905      return addr >= pc_low_ && addr < pc_high_;
1906    }
1907
1908    compilation_unit&
1909    compilation_unit::operator = (const compilation_unit& rhs)
1910    {
1911      if (this != &rhs)
1912      {
1913        debug = rhs.debug;
1914
1915        /*
1916         * This is a copy operator so we need to get a new copy of the strings,
1917         * we cannot steal the other copy.
1918         */
1919        offset_ = rhs.offset_;
1920        name_ = rhs.name_;
1921        producer_ = rhs.producer_;
1922        source_ = sources (debug, die_offset);
1923        for (auto& line : rhs.addr_lines_)
1924          addr_lines_.push_back (address (line, source_));
1925        pc_low_ = rhs.pc_low_;
1926        pc_high_ = rhs.pc_high_;
1927        ranges_ = rhs.ranges_;
1928        die_offset = rhs.die_offset;
1929      }
1930      return *this;
1931    }
1932
1933    void
1934    compilation_unit::dump_die (std::ostream&     out,
1935                                const std::string prefix,
1936                                int               depth)
1937    {
1938      debug_info_entry die (debug, die_offset);
1939      out << "CU @ 0x" << std::hex << offset_ << std::dec << std::endl;
1940      die_dump (die, out, prefix, depth);
1941    }
1942
1943    source_flags::source_flags (const std::string& source)
1944      : source (source)
1945    {
1946    }
1947
1948    bool
1949    source_flags_compare::operator () (const source_flags& a,
1950                                       const source_flags& b) const
1951    {
1952      if (by_basename)
1953        return rld::path::basename (a.source) < rld::path::basename (b.source);
1954      return a.source < b.source;
1955    }
1956
1957    source_flags_compare::source_flags_compare (bool by_basename)
1958      : by_basename (by_basename)
1959    {
1960    }
1961
1962    producer_source::producer_source (const std::string& producer)
1963      : producer (producer)
1964    {
1965    }
1966
1967    producer_source::producer_source ()
1968    {
1969    }
1970
1971    file::file ()
1972      : debug (nullptr),
1973        elf_ (nullptr)
1974    {
1975    }
1976
1977    file::~file ()
1978    {
1979      try
1980      {
1981        end ();
1982      }
1983      catch (rld::error re)
1984      {
1985        std::cerr << "error: rld::dwarf::file::~file: "
1986                  << re.where << ": " << re.what
1987                  << std::endl;
1988      }
1989      catch (...)
1990      {
1991        std::cerr << "error: rld::dwarf::file::~file: unhandled exception"
1992                  << std::endl;
1993      }
1994    }
1995
1996    void
1997    file::begin (rld::elf::file& elf__)
1998    {
1999      if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
2000        std::cout << "dwarf::begin: " << elf__.name () << std::endl;
2001
2002      if (debug != nullptr || elf_ != nullptr)
2003        throw rld::error ("Already called", "dwarf:file:begin");
2004
2005      /*
2006       * DWARF data is not writable.
2007       */
2008      if (elf__.is_writable ())
2009        throw rld::error ("Cannot write DWARF info", "dwarf:file:begin");
2010
2011      /*
2012       * Initialise the DWARF instance.
2013       */
2014      dwarf_error de;
2015      int dr = ::dwarf_elf_init (elf__.get_elf (),
2016                                 DW_DLC_READ,
2017                                 nullptr,
2018                                 this,
2019                                 &debug,
2020                                 &de);
2021      libdwarf_error_check ("file:begin", dr, de);
2022
2023      /*
2024       * Record the ELF instance and obtain a reference to it. The ELF file
2025       * cannot end while the DWARF file has not ended.
2026       */
2027      elf__.reference_obtain ();
2028      elf_ = &elf__;
2029    }
2030
2031    void
2032    file::end ()
2033    {
2034      if (debug)
2035      {
2036        if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
2037          std::cout << "dwarf::end: " << name () << std::endl;
2038
2039        cus.clear ();
2040
2041        ::dwarf_finish (debug, 0);
2042        if (elf_)
2043          elf_->reference_release ();
2044        elf_ = nullptr;
2045        debug = nullptr;
2046      }
2047    }
2048
2049    void
2050    file::dump (std::ostream&     out,
2051                const std::string prefix,
2052                int               depth)
2053    {
2054      while (true)
2055      {
2056        dwarf_unsigned cu_next_offset = 0;
2057        dwarf_error    de;
2058        int            dr;
2059
2060        dr = ::dwarf_next_cu_header_c(debug, 1,
2061                                      nullptr, nullptr, nullptr,  nullptr,
2062                                      nullptr, nullptr, nullptr,  nullptr,
2063                                      &cu_next_offset, &de);
2064        if (dr != DW_DLV_OK)
2065          break;
2066
2067        /*
2068         * Find the CU DIE by asking the CU for it's first DIE.
2069         */
2070        debug_info_entry die (*this);
2071
2072        while (true)
2073        {
2074          debug_info_entry sibling (*this);
2075          if (!die.get_sibling (sibling))
2076            break;
2077          if (sibling.tag () == DW_TAG_compile_unit)
2078            die_dump (sibling, out, prefix, depth);
2079          die = sibling;
2080        }
2081      }
2082    }
2083
2084    void
2085    file::load_debug ()
2086    {
2087      dwarf_unsigned cu_offset = 0;
2088
2089      while (true)
2090      {
2091        dwarf_unsigned cu_next_offset = 0;
2092        dwarf_error    de;
2093        int            dr;
2094
2095        dr = ::dwarf_next_cu_header_c(debug, 1,
2096                                      nullptr, nullptr, nullptr,  nullptr,
2097                                      nullptr, nullptr, nullptr,  nullptr,
2098                                      &cu_next_offset, &de);
2099        if (dr != DW_DLV_OK)
2100          break;
2101
2102        /*
2103         * Find the CU DIE.
2104         */
2105        debug_info_entry die (*this);
2106        debug_info_entry ret_die (*this);
2107
2108        while (true)
2109        {
2110          dr = ::dwarf_siblingof(debug, die, ret_die, &de);
2111          if (dr != DW_DLV_OK)
2112            break;
2113
2114          if (ret_die.tag () == DW_TAG_compile_unit)
2115          {
2116            cus.push_back (compilation_unit (*this, ret_die, cu_offset));
2117            break;
2118          }
2119
2120          die = ret_die;
2121        }
2122
2123        cu_offset = cu_next_offset;
2124      }
2125    }
2126
2127    void
2128    file::load_types ()
2129    {
2130      for (auto& cu : cus)
2131        cu.load_types ();
2132    }
2133
2134    void
2135    file::load_variables ()
2136    {
2137      for (auto& cu : cus)
2138        cu.load_variables ();
2139    }
2140
2141    void
2142    file::load_functions ()
2143    {
2144      for (auto& cu : cus)
2145        cu.load_functions ();
2146    }
2147
2148    bool
2149    file::get_source (const unsigned int addr,
2150                      std::string&       source_file,
2151                      int&               source_line)
2152    {
2153      bool r = false;
2154
2155      /*
2156       * Search the CU's collecting the addresses. An address can appear in
2157       * more than one CU. It may be the last address and the first.
2158       */
2159      source_file = "unknown";
2160      source_line = -1;
2161
2162      address match;
2163
2164      for (auto& cu : cus)
2165      {
2166        address line;
2167        r = cu.get_source (addr, line);
2168        if (r)
2169        {
2170          if (!match.valid ())
2171          {
2172            match = line;
2173          }
2174          else if (match.is_an_end_sequence () || !line.is_an_end_sequence ())
2175          {
2176            match = line;
2177          }
2178        }
2179      }
2180
2181      if (match.valid ())
2182      {
2183        source_file = match.path ();
2184        source_line = match.line ();
2185        r = true;
2186      }
2187
2188      return r;
2189    }
2190
2191    bool
2192    file::get_function (const unsigned int addr,
2193                        std::string&       name)
2194    {
2195      name = "unknown";
2196
2197      for (auto& cu : cus)
2198      {
2199        for (auto& func : cu.get_functions ())
2200        {
2201          if (func.inside (addr))
2202          {
2203            name = func.name ();
2204            return true;
2205          }
2206        }
2207      }
2208
2209      return false;
2210    }
2211
2212    void
2213    file::get_producer_sources (producer_sources& producers)
2214    {
2215      for (auto& cu : cus)
2216      {
2217        std::string     producer = cu.producer ();
2218        producer_source new_producer;
2219        source_flags    sf (cu.name ());
2220        rld::strings    parts;
2221
2222        rld::split (parts, producer);
2223
2224        for (auto& s : parts)
2225        {
2226          if (s[0] == '-')
2227            sf.flags.push_back (s);
2228          else
2229            new_producer.producer +=  ' ' + s;
2230        }
2231
2232        bool add = true;
2233
2234        for (auto& p : producers)
2235        {
2236          if (p.producer == new_producer.producer)
2237          {
2238            p.sources.push_back (sf);
2239            add = false;
2240            break;
2241          }
2242        }
2243        if (add)
2244        {
2245          new_producer.sources.push_back (sf);
2246          producers.push_back (new_producer);
2247        }
2248      }
2249    }
2250
2251    dwarf&
2252    file::get_debug ()
2253    {
2254      return debug;
2255    }
2256
2257    compilation_units&
2258    file::get_cus ()
2259    {
2260      return cus;
2261    }
2262
2263    const std::string&
2264    file::name () const
2265    {
2266      if (!elf_)
2267        throw rld::error ("No begin called", "dwarf:fie:name");
2268      return elf_->name ();
2269    }
2270
2271    void
2272    file::check (const char* where) const
2273    {
2274      if (!debug || !elf_)
2275      {
2276        std::string w = where;
2277        throw rld::error ("No DWARF or ELF file", "dwarf:file:" + w);
2278      }
2279    }
2280
2281  }
2282}
Note: See TracBrowser for help on using the repository browser.