source: rtems-tools/rtemstoolkit/rld-dwarf.cpp @ 558cab8

Last change on this file since 558cab8 was 558cab8, checked in by Chris Johns <chrisj@…>, on May 8, 2018 at 5:09:38 AM

rtemstoolkit: Add libdwarf C++ interface.

Provide a C++ interface to libdwarf to:

  • Manage DWARF debug data
  • Manage CU
  • Manage DIE
  • Handle CU line addresses
  • Handle CU source files

Update #3417

  • Property mode set to 100644
File size: 22.8 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
36namespace 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 &die;
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}
Note: See TracBrowser for help on using the repository browser.