Home | History | Annotate | Download | only in dwarf
      1 // Copyright (c) 2010 Google Inc. All Rights Reserved.
      2 //
      3 // Redistribution and use in source and binary forms, with or without
      4 // modification, are permitted provided that the following conditions are
      5 // met:
      6 //
      7 //     * Redistributions of source code must retain the above copyright
      8 // notice, this list of conditions and the following disclaimer.
      9 //     * Redistributions in binary form must reproduce the above
     10 // copyright notice, this list of conditions and the following disclaimer
     11 // in the documentation and/or other materials provided with the
     12 // distribution.
     13 //     * Neither the name of Google Inc. nor the names of its
     14 // contributors may be used to endorse or promote products derived from
     15 // this software without specific prior written permission.
     16 //
     17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28 
     29 // This is a client for the dwarf2reader to extract function and line
     30 // information from the debug info.
     31 
     32 #include <assert.h>
     33 #include <limits.h>
     34 #include <stdio.h>
     35 
     36 #include <map>
     37 #include <queue>
     38 #include <vector>
     39 
     40 #include "common/dwarf/functioninfo.h"
     41 #include "common/dwarf/bytereader.h"
     42 #include "common/scoped_ptr.h"
     43 #include "common/using_std_string.h"
     44 
     45 using google_breakpad::scoped_ptr;
     46 
     47 namespace dwarf2reader {
     48 
     49 CULineInfoHandler::CULineInfoHandler(std::vector<SourceFileInfo>* files,
     50                                      std::vector<string>* dirs,
     51                                      LineMap* linemap):linemap_(linemap),
     52                                                        files_(files),
     53                                                        dirs_(dirs) {
     54   // The dirs and files are 1 indexed, so just make sure we put
     55   // nothing in the 0 vector.
     56   assert(dirs->size() == 0);
     57   assert(files->size() == 0);
     58   dirs->push_back("");
     59   SourceFileInfo s;
     60   s.name = "";
     61   s.lowpc = ULLONG_MAX;
     62   files->push_back(s);
     63 }
     64 
     65 void CULineInfoHandler::DefineDir(const string& name, uint32 dir_num) {
     66   // These should never come out of order, actually
     67   assert(dir_num == dirs_->size());
     68   dirs_->push_back(name);
     69 }
     70 
     71 void CULineInfoHandler::DefineFile(const string& name,
     72                                    int32 file_num, uint32 dir_num,
     73                                    uint64 mod_time, uint64 length) {
     74   assert(dir_num >= 0);
     75   assert(dir_num < dirs_->size());
     76 
     77   // These should never come out of order, actually.
     78   if (file_num == (int32)files_->size() || file_num == -1) {
     79     string dir = dirs_->at(dir_num);
     80 
     81     SourceFileInfo s;
     82     s.lowpc = ULLONG_MAX;
     83 
     84     if (dir == "") {
     85       s.name = name;
     86     } else {
     87       s.name = dir + "/" + name;
     88     }
     89 
     90     files_->push_back(s);
     91   } else {
     92     fprintf(stderr, "error in DefineFile");
     93   }
     94 }
     95 
     96 void CULineInfoHandler::AddLine(uint64 address, uint64 length, uint32 file_num,
     97                                 uint32 line_num, uint32 column_num) {
     98   if (file_num < files_->size()) {
     99     linemap_->insert(
    100         std::make_pair(address,
    101                        std::make_pair(files_->at(file_num).name.c_str(),
    102                                       line_num)));
    103 
    104     if (address < files_->at(file_num).lowpc) {
    105       files_->at(file_num).lowpc = address;
    106     }
    107   } else {
    108     fprintf(stderr, "error in AddLine");
    109   }
    110 }
    111 
    112 bool CUFunctionInfoHandler::StartCompilationUnit(uint64 offset,
    113                                                  uint8 address_size,
    114                                                  uint8 offset_size,
    115                                                  uint64 cu_length,
    116                                                  uint8 dwarf_version) {
    117   current_compilation_unit_offset_ = offset;
    118   return true;
    119 }
    120 
    121 
    122 // For function info, we only care about subprograms and inlined
    123 // subroutines. For line info, the DW_AT_stmt_list lives in the
    124 // compile unit tag.
    125 
    126 bool CUFunctionInfoHandler::StartDIE(uint64 offset, enum DwarfTag tag) {
    127   switch (tag) {
    128     case DW_TAG_subprogram:
    129     case DW_TAG_inlined_subroutine: {
    130       current_function_info_ = new FunctionInfo;
    131       current_function_info_->lowpc = current_function_info_->highpc = 0;
    132       current_function_info_->name = "";
    133       current_function_info_->line = 0;
    134       current_function_info_->file = "";
    135       offset_to_funcinfo_->insert(std::make_pair(offset,
    136                                                  current_function_info_));
    137     };
    138       // FALLTHROUGH
    139     case DW_TAG_compile_unit:
    140       return true;
    141     default:
    142       return false;
    143   }
    144   return false;
    145 }
    146 
    147 // Only care about the name attribute for functions
    148 
    149 void CUFunctionInfoHandler::ProcessAttributeString(uint64 offset,
    150                                                    enum DwarfAttribute attr,
    151                                                    enum DwarfForm form,
    152                                                    const string &data) {
    153   if (current_function_info_) {
    154     if (attr == DW_AT_name)
    155       current_function_info_->name = data;
    156     else if (attr == DW_AT_MIPS_linkage_name)
    157       current_function_info_->mangled_name = data;
    158   }
    159 }
    160 
    161 void CUFunctionInfoHandler::ProcessAttributeUnsigned(uint64 offset,
    162                                                      enum DwarfAttribute attr,
    163                                                      enum DwarfForm form,
    164                                                      uint64 data) {
    165   if (attr == DW_AT_stmt_list) {
    166     SectionMap::const_iterator iter = sections_.find("__debug_line");
    167     assert(iter != sections_.end());
    168 
    169     scoped_ptr<LineInfo> lireader(new LineInfo(iter->second.first + data,
    170                                                iter->second.second  - data,
    171                                                reader_, linehandler_));
    172     lireader->Start();
    173   } else if (current_function_info_) {
    174     switch (attr) {
    175       case DW_AT_low_pc:
    176         current_function_info_->lowpc = data;
    177         break;
    178       case DW_AT_high_pc:
    179         current_function_info_->highpc = data;
    180         break;
    181       case DW_AT_decl_line:
    182         current_function_info_->line = data;
    183         break;
    184       case DW_AT_decl_file:
    185         current_function_info_->file = files_->at(data).name;
    186         break;
    187       default:
    188         break;
    189     }
    190   }
    191 }
    192 
    193 void CUFunctionInfoHandler::ProcessAttributeReference(uint64 offset,
    194                                                       enum DwarfAttribute attr,
    195                                                       enum DwarfForm form,
    196                                                       uint64 data) {
    197   if (current_function_info_) {
    198     switch (attr) {
    199       case DW_AT_specification: {
    200         // Some functions have a "specification" attribute
    201         // which means they were defined elsewhere. The name
    202         // attribute is not repeated, and must be taken from
    203         // the specification DIE. Here we'll assume that
    204         // any DIE referenced in this manner will already have
    205         // been seen, but that's not really required by the spec.
    206         FunctionMap::iterator iter = offset_to_funcinfo_->find(data);
    207         if (iter != offset_to_funcinfo_->end()) {
    208           current_function_info_->name = iter->second->name;
    209           current_function_info_->mangled_name = iter->second->mangled_name;
    210         } else {
    211           // If you hit this, this code probably needs to be rewritten.
    212           fprintf(stderr,
    213                   "Error: DW_AT_specification was seen before the referenced "
    214                   "DIE! (Looking for DIE at offset %08llx, in DIE at "
    215                   "offset %08llx)\n", data, offset);
    216         }
    217         break;
    218       }
    219       default:
    220         break;
    221     }
    222   }
    223 }
    224 
    225 void CUFunctionInfoHandler::EndDIE(uint64 offset) {
    226   if (current_function_info_ && current_function_info_->lowpc)
    227     address_to_funcinfo_->insert(std::make_pair(current_function_info_->lowpc,
    228                                                 current_function_info_));
    229 }
    230 
    231 }  // namespace dwarf2reader
    232