LCOV - code coverage report
Current view: directory - toolkit/crashreporter/google-breakpad/src/common - stabs_reader.cc (source / functions) Found Hit Coverage
Test: app.info Lines: 119 0 0.0 %
Date: 2012-06-02 Functions: 7 0 0.0 %

       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                 : // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
      30                 : 
      31                 : // This file implements the google_breakpad::StabsReader class.
      32                 : // See stabs_reader.h.
      33                 : 
      34                 : #include "common/stabs_reader.h"
      35                 : 
      36                 : #include <assert.h>
      37                 : #include <stab.h>
      38                 : #include <string.h>
      39                 : 
      40                 : using std::vector;
      41                 : 
      42                 : namespace google_breakpad {
      43                 : 
      44               0 : StabsReader::EntryIterator::EntryIterator(const ByteBuffer *buffer,
      45                 :                                           bool big_endian, size_t value_size)
      46               0 :     : value_size_(value_size), cursor_(buffer, big_endian) {
      47                 :   // Actually, we could handle weird sizes just fine, but they're
      48                 :   // probably mistakes --- expressed in bits, say.
      49               0 :   assert(value_size == 4 || value_size == 8);
      50               0 :   entry_.index = 0;
      51               0 :   Fetch();
      52               0 : }
      53                 : 
      54               0 : void StabsReader::EntryIterator::Fetch() {
      55                 :   cursor_
      56               0 :       .Read(4, false, &entry_.name_offset)
      57               0 :       .Read(1, false, &entry_.type)
      58               0 :       .Read(1, false, &entry_.other)
      59               0 :       .Read(2, false, &entry_.descriptor)
      60               0 :       .Read(value_size_, false, &entry_.value);
      61               0 :   entry_.at_end = !cursor_;
      62               0 : }
      63                 : 
      64               0 : StabsReader::StabsReader(const uint8_t *stab,    size_t stab_size,
      65                 :                          const uint8_t *stabstr, size_t stabstr_size,
      66                 :                          bool big_endian, size_t value_size, bool unitized,
      67                 :                          StabsHandler *handler)
      68                 :     : entries_(stab, stab_size),
      69                 :       strings_(stabstr, stabstr_size),
      70                 :       iterator_(&entries_, big_endian, value_size),
      71                 :       unitized_(unitized),
      72                 :       handler_(handler),
      73                 :       string_offset_(0),
      74                 :       next_cu_string_offset_(0),
      75               0 :       current_source_file_(NULL) { }
      76                 : 
      77               0 : const char *StabsReader::SymbolString() {
      78               0 :   ptrdiff_t offset = string_offset_ + iterator_->name_offset;
      79               0 :   if (offset < 0 || (size_t) offset >= strings_.Size()) {
      80                 :     handler_->Warning("symbol %d: name offset outside the string section\n",
      81               0 :                       iterator_->index);
      82                 :     // Return our null string, to keep our promise about all names being
      83                 :     // taken from the string section.
      84               0 :     offset = 0;
      85                 :   }
      86               0 :   return reinterpret_cast<const char *>(strings_.start + offset);
      87                 : }
      88                 : 
      89               0 : bool StabsReader::Process() {
      90               0 :   while (!iterator_->at_end) {
      91               0 :     if (iterator_->type == N_SO) {
      92               0 :       if (! ProcessCompilationUnit())
      93               0 :         return false;
      94               0 :     } else if (iterator_->type == N_UNDF && unitized_) {
      95                 :       // In unitized STABS (including Linux STABS, and pretty much anything
      96                 :       // else that puts STABS data in sections), at the head of each
      97                 :       // compilation unit's entries there is an N_UNDF stab giving the
      98                 :       // number of symbols in the compilation unit, and the number of bytes
      99                 :       // that compilation unit's strings take up in the .stabstr section.
     100                 :       // Each CU's strings are separate; the n_strx values are offsets
     101                 :       // within the current CU's portion of the .stabstr section.
     102                 :       //
     103                 :       // As an optimization, the GNU linker combines all the
     104                 :       // compilation units into one, with a single N_UNDF at the
     105                 :       // beginning. However, other linkers, like Gold, do not perform
     106                 :       // this optimization.
     107               0 :       string_offset_ = next_cu_string_offset_;
     108               0 :       next_cu_string_offset_ = iterator_->value;
     109               0 :       ++iterator_;
     110                 :     } else
     111               0 :       ++iterator_;
     112                 :   }
     113               0 :   return true;
     114                 : }
     115                 : 
     116               0 : bool StabsReader::ProcessCompilationUnit() {
     117               0 :   assert(!iterator_->at_end && iterator_->type == N_SO);
     118                 : 
     119                 :   // There may be an N_SO entry whose name ends with a slash,
     120                 :   // indicating the directory in which the compilation occurred.
     121                 :   // The build directory defaults to NULL.
     122               0 :   const char *build_directory = NULL;  
     123                 :   {
     124               0 :     const char *name = SymbolString();
     125               0 :     if (name[0] && name[strlen(name) - 1] == '/') {
     126               0 :       build_directory = name;
     127               0 :       ++iterator_;
     128                 :     }
     129                 :   }
     130                 :       
     131                 :   // We expect to see an N_SO entry with a filename next, indicating
     132                 :   // the start of the compilation unit.
     133                 :   {
     134               0 :     if (iterator_->at_end || iterator_->type != N_SO)
     135               0 :       return true;
     136               0 :     const char *name = SymbolString();
     137               0 :     if (name[0] == '\0') {
     138                 :       // This seems to be a stray end-of-compilation-unit marker;
     139                 :       // consume it, but don't report the end, since we didn't see a
     140                 :       // beginning.
     141               0 :       ++iterator_;
     142               0 :       return true;
     143                 :     }
     144               0 :     current_source_file_ = name;
     145                 :   }
     146                 : 
     147               0 :   if (! handler_->StartCompilationUnit(current_source_file_,
     148               0 :                                        iterator_->value,
     149               0 :                                        build_directory))
     150               0 :     return false;
     151                 : 
     152               0 :   ++iterator_;
     153                 : 
     154                 :   // The STABS documentation says that some compilers may emit
     155                 :   // additional N_SO entries with names immediately following the
     156                 :   // first, and that they should be ignored.  However, the original
     157                 :   // Breakpad STABS reader doesn't ignore them, so we won't either.
     158                 : 
     159                 :   // Process the body of the compilation unit, up to the next N_SO.
     160               0 :   while (!iterator_->at_end && iterator_->type != N_SO) {
     161               0 :     if (iterator_->type == N_FUN) {
     162               0 :       if (! ProcessFunction())
     163               0 :         return false;
     164               0 :     } else if (iterator_->type == N_SLINE) {
     165                 :       // Mac OS X STABS place SLINE records before functions.
     166                 :       Line line;
     167                 :       // The value of an N_SLINE entry that appears outside a function is
     168                 :       // the absolute address of the line.
     169               0 :       line.address = iterator_->value;
     170               0 :       line.filename = current_source_file_;
     171                 :       // The n_desc of a N_SLINE entry is the line number.  It's a
     172                 :       // signed 16-bit field; line numbers from 32768 to 65535 are
     173                 :       // stored as n-65536.
     174               0 :       line.number = (uint16_t) iterator_->descriptor;
     175               0 :       queued_lines_.push_back(line);
     176               0 :       ++iterator_;
     177               0 :     } else if (iterator_->type == N_SOL) {
     178               0 :       current_source_file_ = SymbolString();
     179               0 :       ++iterator_;
     180                 :     } else {
     181                 :       // Ignore anything else.
     182               0 :       ++iterator_;
     183                 :     }
     184                 :   }
     185                 : 
     186                 :   // An N_SO with an empty name indicates the end of the compilation
     187                 :   // unit.  Default to zero.
     188               0 :   uint64_t ending_address = 0;
     189               0 :   if (!iterator_->at_end) {
     190               0 :     assert(iterator_->type == N_SO);
     191               0 :     const char *name = SymbolString();
     192               0 :     if (name[0] == '\0') {
     193               0 :       ending_address = iterator_->value;
     194               0 :       ++iterator_;
     195                 :     }
     196                 :   }
     197                 : 
     198               0 :   if (! handler_->EndCompilationUnit(ending_address))
     199               0 :     return false;
     200                 : 
     201               0 :   queued_lines_.clear();
     202                 : 
     203               0 :   return true;
     204                 : }          
     205                 : 
     206               0 : bool StabsReader::ProcessFunction() {
     207               0 :   assert(!iterator_->at_end && iterator_->type == N_FUN);
     208                 : 
     209               0 :   uint64_t function_address = iterator_->value;
     210                 :   // The STABS string for an N_FUN entry is the name of the function,
     211                 :   // followed by a colon, followed by type information for the
     212                 :   // function.  We want to pass the name alone to StartFunction.
     213               0 :   const char *stab_string = SymbolString();
     214               0 :   const char *name_end = strchr(stab_string, ':');
     215               0 :   if (! name_end)
     216               0 :     name_end = stab_string + strlen(stab_string);
     217               0 :   std::string name(stab_string, name_end - stab_string);
     218               0 :   if (! handler_->StartFunction(name, function_address))
     219               0 :     return false;
     220               0 :   ++iterator_;
     221                 : 
     222                 :   // If there were any SLINE records given before the function, report them now.
     223               0 :   for (vector<Line>::const_iterator it = queued_lines_.begin();
     224               0 :        it != queued_lines_.end(); it++) {
     225               0 :     if (!handler_->Line(it->address, it->filename, it->number))
     226               0 :       return false;
     227                 :   }
     228               0 :   queued_lines_.clear();
     229                 :   
     230               0 :   while (!iterator_->at_end) {
     231               0 :     if (iterator_->type == N_SO || iterator_->type == N_FUN)
     232               0 :       break;
     233               0 :     else if (iterator_->type == N_SLINE) {
     234                 :       // The value of an N_SLINE entry is the offset of the line from
     235                 :       // the function's start address.
     236               0 :       uint64_t line_address = function_address + iterator_->value;
     237                 :       // The n_desc of a N_SLINE entry is the line number.  It's a
     238                 :       // signed 16-bit field; line numbers from 32768 to 65535 are
     239                 :       // stored as n-65536.
     240               0 :       uint16_t line_number = iterator_->descriptor;
     241               0 :       if (! handler_->Line(line_address, current_source_file_, line_number))
     242               0 :         return false;
     243               0 :       ++iterator_;
     244               0 :     } else if (iterator_->type == N_SOL) {
     245               0 :       current_source_file_ = SymbolString();
     246               0 :       ++iterator_;
     247                 :     } else
     248                 :       // Ignore anything else.
     249               0 :       ++iterator_;
     250                 :   }
     251                 : 
     252                 :   // We've reached the end of the function. See if we can figure out its
     253                 :   // ending address.
     254               0 :   uint64_t ending_address = 0;
     255               0 :   if (!iterator_->at_end) {
     256               0 :     assert(iterator_->type == N_SO || iterator_->type == N_FUN);
     257               0 :     if (iterator_->type == N_FUN) {
     258               0 :       const char *name = SymbolString();
     259               0 :       if (name[0] == '\0') {
     260                 :         // An N_FUN entry with no name is a terminator for this function;
     261                 :         // its value is the function's size.
     262               0 :         ending_address = function_address + iterator_->value;
     263               0 :         ++iterator_;
     264                 :       } else {
     265                 :         // An N_FUN entry with a name is the next function, and we can take
     266                 :         // its value as our ending address. Don't advance the iterator, as
     267                 :         // we'll use this symbol to start the next function as well.
     268               0 :         ending_address = iterator_->value;
     269                 :       }
     270                 :     } else {
     271                 :       // An N_SO entry could be an end-of-compilation-unit marker, or the
     272                 :       // start of the next compilation unit, but in either case, its value
     273                 :       // is our ending address. We don't advance the iterator;
     274                 :       // ProcessCompilationUnit will decide what to do with this symbol.
     275               0 :       ending_address = iterator_->value;
     276                 :     }
     277                 :   }
     278                 : 
     279               0 :   if (! handler_->EndFunction(ending_address))
     280               0 :     return false;
     281                 : 
     282               0 :   return true;
     283                 : }
     284                 : 
     285                 : } // namespace google_breakpad

Generated by: LCOV version 1.7