Home | History | Annotate | Download | only in common
      1 // Copyright (c) 2011 Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 // Original author: Jim Blandy <jimb (at) mozilla.com> <jimb (at) red-bean.com>
     31 
     32 // module.cc: Implement google_breakpad::Module.  See module.h.
     33 
     34 #include "common/module.h"
     35 
     36 #include <assert.h>
     37 #include <errno.h>
     38 #include <stdio.h>
     39 #include <string.h>
     40 
     41 #include <iostream>
     42 #include <utility>
     43 
     44 namespace google_breakpad {
     45 
     46 using std::dec;
     47 using std::endl;
     48 using std::hex;
     49 
     50 
     51 Module::Module(const string &name, const string &os,
     52                const string &architecture, const string &id) :
     53     name_(name),
     54     os_(os),
     55     architecture_(architecture),
     56     id_(id),
     57     load_address_(0) { }
     58 
     59 Module::~Module() {
     60   for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
     61     delete it->second;
     62   for (FunctionSet::iterator it = functions_.begin();
     63        it != functions_.end(); ++it) {
     64     delete *it;
     65   }
     66   for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin();
     67        it != stack_frame_entries_.end(); ++it) {
     68     delete *it;
     69   }
     70   for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it)
     71     delete *it;
     72 }
     73 
     74 void Module::SetLoadAddress(Address address) {
     75   load_address_ = address;
     76 }
     77 
     78 void Module::AddFunction(Function *function) {
     79   // FUNC lines must not hold an empty name, so catch the problem early if
     80   // callers try to add one.
     81   assert(!function->name.empty());
     82 
     83   // FUNCs are better than PUBLICs as they come with sizes, so remove an extern
     84   // with the same address if present.
     85   Extern ext(function->address);
     86   ExternSet::iterator it_ext = externs_.find(&ext);
     87   if (it_ext == externs_.end() &&
     88       architecture_ == "arm" &&
     89       (function->address & 0x1) == 0) {
     90     // ARM THUMB functions have bit 0 set. ARM64 does not have THUMB.
     91     Extern arm_thumb_ext(function->address | 0x1);
     92     it_ext = externs_.find(&arm_thumb_ext);
     93   }
     94   if (it_ext != externs_.end()) {
     95     delete *it_ext;
     96     externs_.erase(it_ext);
     97   }
     98 #if _DEBUG
     99   {
    100     // There should be no other PUBLIC symbols that overlap with the function.
    101     Extern debug_ext(function->address);
    102     ExternSet::iterator it_debug = externs_.lower_bound(&ext);
    103     assert(it_debug == externs_.end() ||
    104            (*it_debug)->address >= function->address + function->size);
    105   }
    106 #endif
    107 
    108   std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function);
    109   if (!ret.second && (*ret.first != function)) {
    110     // Free the duplicate that was not inserted because this Module
    111     // now owns it.
    112     delete function;
    113   }
    114 }
    115 
    116 void Module::AddFunctions(vector<Function *>::iterator begin,
    117                           vector<Function *>::iterator end) {
    118   for (vector<Function *>::iterator it = begin; it != end; ++it)
    119     AddFunction(*it);
    120 }
    121 
    122 void Module::AddStackFrameEntry(StackFrameEntry *stack_frame_entry) {
    123   stack_frame_entries_.push_back(stack_frame_entry);
    124 }
    125 
    126 void Module::AddExtern(Extern *ext) {
    127   std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext);
    128   if (!ret.second) {
    129     // Free the duplicate that was not inserted because this Module
    130     // now owns it.
    131     delete ext;
    132   }
    133 }
    134 
    135 void Module::GetFunctions(vector<Function *> *vec,
    136                           vector<Function *>::iterator i) {
    137   vec->insert(i, functions_.begin(), functions_.end());
    138 }
    139 
    140 void Module::GetExterns(vector<Extern *> *vec,
    141                         vector<Extern *>::iterator i) {
    142   vec->insert(i, externs_.begin(), externs_.end());
    143 }
    144 
    145 Module::File *Module::FindFile(const string &name) {
    146   // A tricky bit here.  The key of each map entry needs to be a
    147   // pointer to the entry's File's name string.  This means that we
    148   // can't do the initial lookup with any operation that would create
    149   // an empty entry for us if the name isn't found (like, say,
    150   // operator[] or insert do), because such a created entry's key will
    151   // be a pointer the string passed as our argument.  Since the key of
    152   // a map's value type is const, we can't fix it up once we've
    153   // created our file.  lower_bound does the lookup without doing an
    154   // insertion, and returns a good hint iterator to pass to insert.
    155   // Our "destiny" is where we belong, whether we're there or not now.
    156   FileByNameMap::iterator destiny = files_.lower_bound(&name);
    157   if (destiny == files_.end()
    158       || *destiny->first != name) {  // Repeated string comparison, boo hoo.
    159     File *file = new File(name);
    160     file->source_id = -1;
    161     destiny = files_.insert(destiny,
    162                             FileByNameMap::value_type(&file->name, file));
    163   }
    164   return destiny->second;
    165 }
    166 
    167 Module::File *Module::FindFile(const char *name) {
    168   string name_string = name;
    169   return FindFile(name_string);
    170 }
    171 
    172 Module::File *Module::FindExistingFile(const string &name) {
    173   FileByNameMap::iterator it = files_.find(&name);
    174   return (it == files_.end()) ? NULL : it->second;
    175 }
    176 
    177 void Module::GetFiles(vector<File *> *vec) {
    178   vec->clear();
    179   for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
    180     vec->push_back(it->second);
    181 }
    182 
    183 void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) const {
    184   *vec = stack_frame_entries_;
    185 }
    186 
    187 void Module::AssignSourceIds() {
    188   // First, give every source file an id of -1.
    189   for (FileByNameMap::iterator file_it = files_.begin();
    190        file_it != files_.end(); ++file_it) {
    191     file_it->second->source_id = -1;
    192   }
    193 
    194   // Next, mark all files actually cited by our functions' line number
    195   // info, by setting each one's source id to zero.
    196   for (FunctionSet::const_iterator func_it = functions_.begin();
    197        func_it != functions_.end(); ++func_it) {
    198     Function *func = *func_it;
    199     for (vector<Line>::iterator line_it = func->lines.begin();
    200          line_it != func->lines.end(); ++line_it)
    201       line_it->file->source_id = 0;
    202   }
    203 
    204   // Finally, assign source ids to those files that have been marked.
    205   // We could have just assigned source id numbers while traversing
    206   // the line numbers, but doing it this way numbers the files in
    207   // lexicographical order by name, which is neat.
    208   int next_source_id = 0;
    209   for (FileByNameMap::iterator file_it = files_.begin();
    210        file_it != files_.end(); ++file_it) {
    211     if (!file_it->second->source_id)
    212       file_it->second->source_id = next_source_id++;
    213   }
    214 }
    215 
    216 bool Module::ReportError() {
    217   fprintf(stderr, "error writing symbol file: %s\n",
    218           strerror(errno));
    219   return false;
    220 }
    221 
    222 bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
    223   for (RuleMap::const_iterator it = rule_map.begin();
    224        it != rule_map.end(); ++it) {
    225     if (it != rule_map.begin())
    226       stream << ' ';
    227     stream << it->first << ": " << it->second;
    228   }
    229   return stream.good();
    230 }
    231 
    232 bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
    233   stream << "MODULE " << os_ << " " << architecture_ << " "
    234          << id_ << " " << name_ << endl;
    235   if (!stream.good())
    236     return ReportError();
    237 
    238   if (symbol_data != ONLY_CFI) {
    239     AssignSourceIds();
    240 
    241     // Write out files.
    242     for (FileByNameMap::iterator file_it = files_.begin();
    243          file_it != files_.end(); ++file_it) {
    244       File *file = file_it->second;
    245       if (file->source_id >= 0) {
    246         stream << "FILE " << file->source_id << " " <<  file->name << endl;
    247         if (!stream.good())
    248           return ReportError();
    249       }
    250     }
    251 
    252     // Write out functions and their lines.
    253     for (FunctionSet::const_iterator func_it = functions_.begin();
    254          func_it != functions_.end(); ++func_it) {
    255       Function *func = *func_it;
    256       stream << "FUNC " << hex
    257              << (func->address - load_address_) << " "
    258              << func->size << " "
    259              << func->parameter_size << " "
    260              << func->name << dec << endl;
    261       if (!stream.good())
    262         return ReportError();
    263 
    264       for (vector<Line>::iterator line_it = func->lines.begin();
    265            line_it != func->lines.end(); ++line_it) {
    266         stream << hex
    267                << (line_it->address - load_address_) << " "
    268                << line_it->size << " "
    269                << dec
    270                << line_it->number << " "
    271                << line_it->file->source_id << endl;
    272         if (!stream.good())
    273           return ReportError();
    274       }
    275     }
    276 
    277     // Write out 'PUBLIC' records.
    278     for (ExternSet::const_iterator extern_it = externs_.begin();
    279          extern_it != externs_.end(); ++extern_it) {
    280       Extern *ext = *extern_it;
    281       stream << "PUBLIC " << hex
    282              << (ext->address - load_address_) << " 0 "
    283              << ext->name << dec << endl;
    284     }
    285   }
    286 
    287   if (symbol_data != NO_CFI) {
    288     // Write out 'STACK CFI INIT' and 'STACK CFI' records.
    289     vector<StackFrameEntry *>::const_iterator frame_it;
    290     for (frame_it = stack_frame_entries_.begin();
    291          frame_it != stack_frame_entries_.end(); ++frame_it) {
    292       StackFrameEntry *entry = *frame_it;
    293       stream << "STACK CFI INIT " << hex
    294              << (entry->address - load_address_) << " "
    295              << entry->size << " " << dec;
    296       if (!stream.good()
    297           || !WriteRuleMap(entry->initial_rules, stream))
    298         return ReportError();
    299 
    300       stream << endl;
    301 
    302       // Write out this entry's delta rules as 'STACK CFI' records.
    303       for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin();
    304            delta_it != entry->rule_changes.end(); ++delta_it) {
    305         stream << "STACK CFI " << hex
    306                << (delta_it->first - load_address_) << " " << dec;
    307         if (!stream.good()
    308             || !WriteRuleMap(delta_it->second, stream))
    309           return ReportError();
    310 
    311         stream << endl;
    312       }
    313     }
    314   }
    315 
    316   return true;
    317 }
    318 
    319 }  // namespace google_breakpad
    320