toolkit/crashreporter/google-breakpad/src/common/stabs_reader.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,326 @@
     1.4 +// -*- mode: c++ -*-
     1.5 +
     1.6 +// Copyright (c) 2010 Google Inc. All Rights Reserved.
     1.7 +//
     1.8 +// Redistribution and use in source and binary forms, with or without
     1.9 +// modification, are permitted provided that the following conditions are
    1.10 +// met:
    1.11 +//
    1.12 +//     * Redistributions of source code must retain the above copyright
    1.13 +// notice, this list of conditions and the following disclaimer.
    1.14 +//     * Redistributions in binary form must reproduce the above
    1.15 +// copyright notice, this list of conditions and the following disclaimer
    1.16 +// in the documentation and/or other materials provided with the
    1.17 +// distribution.
    1.18 +//     * Neither the name of Google Inc. nor the names of its
    1.19 +// contributors may be used to endorse or promote products derived from
    1.20 +// this software without specific prior written permission.
    1.21 +//
    1.22 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.23 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    1.24 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.25 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    1.26 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.27 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    1.28 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.29 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    1.30 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.31 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    1.32 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.33 +
    1.34 +// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
    1.35 +
    1.36 +// stabs_reader.h: Define StabsReader, a parser for STABS debugging
    1.37 +// information. A description of the STABS debugging format can be
    1.38 +// found at:
    1.39 +//
    1.40 +//    http://sourceware.org/gdb/current/onlinedocs/stabs_toc.html
    1.41 +//
    1.42 +// The comments here assume you understand the format.
    1.43 +//
    1.44 +// This parser can handle big-endian and little-endian data, and the symbol
    1.45 +// values may be either 32 or 64 bits long. It handles both STABS in
    1.46 +// sections (as used on Linux) and STABS appearing directly in an
    1.47 +// a.out-like symbol table (as used in Darwin OS X Mach-O files).
    1.48 +
    1.49 +#ifndef COMMON_STABS_READER_H__
    1.50 +#define COMMON_STABS_READER_H__
    1.51 +
    1.52 +#include <stddef.h>
    1.53 +#include <stdint.h>
    1.54 +
    1.55 +#ifdef HAVE_CONFIG_H
    1.56 +#include <config.h>
    1.57 +#endif
    1.58 +
    1.59 +#ifdef HAVE_A_OUT_H
    1.60 +#include <a.out.h>
    1.61 +#endif
    1.62 +#ifdef HAVE_MACH_O_NLIST_H
    1.63 +#include <mach-o/nlist.h>
    1.64 +#endif
    1.65 +
    1.66 +#include <string>
    1.67 +#include <vector>
    1.68 +
    1.69 +#include "common/byte_cursor.h"
    1.70 +#include "common/using_std_string.h"
    1.71 +
    1.72 +namespace google_breakpad {
    1.73 +
    1.74 +class StabsHandler;
    1.75 +
    1.76 +class StabsReader {
    1.77 + public:
    1.78 +  // Create a reader for the STABS debug information whose .stab section is
    1.79 +  // being traversed by ITERATOR, and whose .stabstr section is referred to
    1.80 +  // by STRINGS. The reader will call the member functions of HANDLER to
    1.81 +  // report the information it finds, when the reader's 'Process' member
    1.82 +  // function is called.
    1.83 +  //
    1.84 +  // BIG_ENDIAN should be true if the entries in the .stab section are in
    1.85 +  // big-endian form, or false if they are in little-endian form.
    1.86 +  //
    1.87 +  // VALUE_SIZE should be either 4 or 8, indicating the size of the 'value'
    1.88 +  // field in each entry in bytes.
    1.89 +  //
    1.90 +  // UNITIZED should be true if the STABS data is stored in units with
    1.91 +  // N_UNDF headers. This is usually the case for STABS stored in sections,
    1.92 +  // like .stab/.stabstr, and usually not the case for STABS stored in the
    1.93 +  // actual symbol table; UNITIZED should be true when parsing Linux stabs,
    1.94 +  // false when parsing Mac OS X STABS. For details, see:
    1.95 +  // http://sourceware.org/gdb/current/onlinedocs/stabs/Stab-Section-Basics.html
    1.96 +  // 
    1.97 +  // Note that, in ELF, the .stabstr section should be found using the
    1.98 +  // 'sh_link' field of the .stab section header, not by name.
    1.99 +  StabsReader(const uint8_t *stab,    size_t stab_size,
   1.100 +              const uint8_t *stabstr, size_t stabstr_size,
   1.101 +              bool big_endian, size_t value_size, bool unitized,
   1.102 +              StabsHandler *handler);
   1.103 +
   1.104 +  // Process the STABS data, calling the handler's member functions to
   1.105 +  // report what we find.  While the handler functions return true,
   1.106 +  // continue to process until we reach the end of the section.  If we
   1.107 +  // processed the entire section and all handlers returned true,
   1.108 +  // return true.  If any handler returned false, return false.
   1.109 +  // 
   1.110 +  // This is only meant to be called once per StabsReader instance;
   1.111 +  // resuming a prior processing pass that stopped abruptly isn't supported.
   1.112 +  bool Process();
   1.113 +
   1.114 + private:
   1.115 +
   1.116 +  // An class for walking arrays of STABS entries. This isolates the main
   1.117 +  // STABS reader from the exact format (size; endianness) of the entries
   1.118 +  // themselves.
   1.119 +  class EntryIterator {
   1.120 +   public:
   1.121 +    // The contents of a STABS entry, adjusted for the host's endianness,
   1.122 +    // word size, 'struct nlist' layout, and so on.
   1.123 +    struct Entry {
   1.124 +      // True if this iterator has reached the end of the entry array. When
   1.125 +      // this is set, the other members of this structure are not valid.
   1.126 +      bool at_end;
   1.127 +
   1.128 +      // The number of this entry within the list.
   1.129 +      size_t index;
   1.130 +
   1.131 +      // The current entry's name offset. This is the offset within the
   1.132 +      // current compilation unit's strings, as establish by the N_UNDF entries.
   1.133 +      size_t name_offset;
   1.134 +
   1.135 +      // The current entry's type, 'other' field, descriptor, and value.
   1.136 +      unsigned char type;
   1.137 +      unsigned char other;
   1.138 +      short descriptor;
   1.139 +      uint64_t value;
   1.140 +    };
   1.141 +
   1.142 +    // Create a EntryIterator walking the entries in BUFFER. Treat the
   1.143 +    // entries as big-endian if BIG_ENDIAN is true, as little-endian
   1.144 +    // otherwise. Assume each entry has a 'value' field whose size is
   1.145 +    // VALUE_SIZE.
   1.146 +    //
   1.147 +    // This would not be terribly clean to extend to other format variations,
   1.148 +    // but it's enough to handle Linux and Mac, and we'd like STABS to die
   1.149 +    // anyway.
   1.150 +    //
   1.151 +    // For the record: on Linux, STABS entry values are always 32 bits,
   1.152 +    // regardless of the architecture address size (don't ask me why); on
   1.153 +    // Mac, they are 32 or 64 bits long. Oddly, the section header's entry
   1.154 +    // size for a Linux ELF .stab section varies according to the ELF class
   1.155 +    // from 12 to 20 even as the actual entries remain unchanged.
   1.156 +    EntryIterator(const ByteBuffer *buffer, bool big_endian, size_t value_size);
   1.157 +
   1.158 +    // Move to the next entry. This function's behavior is undefined if
   1.159 +    // at_end() is true when it is called.
   1.160 +    EntryIterator &operator++() { Fetch(); entry_.index++; return *this; }
   1.161 +
   1.162 +    // Dereferencing this iterator produces a reference to an Entry structure
   1.163 +    // that holds the current entry's values. The entry is owned by this
   1.164 +    // EntryIterator, and will be invalidated at the next call to operator++.
   1.165 +    const Entry &operator*() const { return entry_; }
   1.166 +    const Entry *operator->() const { return &entry_; }
   1.167 +
   1.168 +   private:
   1.169 +    // Read the STABS entry at cursor_, and set entry_ appropriately.
   1.170 +    void Fetch();
   1.171 +
   1.172 +    // The size of entries' value field, in bytes.
   1.173 +    size_t value_size_;
   1.174 +
   1.175 +    // A byte cursor traversing buffer_.
   1.176 +    ByteCursor cursor_;
   1.177 +
   1.178 +    // Values for the entry this iterator refers to.
   1.179 +    Entry entry_;
   1.180 +  };
   1.181 +
   1.182 +  // A source line, saved to be reported later.
   1.183 +  struct Line {
   1.184 +    uint64_t address;
   1.185 +    const char *filename;
   1.186 +    int number;
   1.187 +  };
   1.188 +
   1.189 +  // Return the name of the current symbol.
   1.190 +  const char *SymbolString();
   1.191 +
   1.192 +  // Process a compilation unit starting at symbol_.  Return true
   1.193 +  // to continue processing, or false to abort.
   1.194 +  bool ProcessCompilationUnit();
   1.195 +
   1.196 +  // Process a function in current_source_file_ starting at symbol_.
   1.197 +  // Return true to continue processing, or false to abort.
   1.198 +  bool ProcessFunction();
   1.199 +
   1.200 +  // Process an exported function symbol.
   1.201 +  // Return true to continue processing, or false to abort.
   1.202 +  bool ProcessExtern();
   1.203 +
   1.204 +  // The STABS entries being parsed.
   1.205 +  ByteBuffer entries_;
   1.206 +
   1.207 +  // The string section to which the entries refer.
   1.208 +  ByteBuffer strings_;
   1.209 +
   1.210 +  // The iterator walking the STABS entries.
   1.211 +  EntryIterator iterator_;
   1.212 +
   1.213 +  // True if the data is "unitized"; see the explanation in the comment for
   1.214 +  // StabsReader::StabsReader.
   1.215 +  bool unitized_;
   1.216 +
   1.217 +  StabsHandler *handler_;
   1.218 +
   1.219 +  // The offset of the current compilation unit's strings within stabstr_.
   1.220 +  size_t string_offset_;
   1.221 +
   1.222 +  // The value string_offset_ should have for the next compilation unit,
   1.223 +  // as established by N_UNDF entries.
   1.224 +  size_t next_cu_string_offset_;
   1.225 +
   1.226 +  // The current source file name.
   1.227 +  const char *current_source_file_;
   1.228 +
   1.229 +  // Mac OS X STABS place SLINE records before functions; we accumulate a
   1.230 +  // vector of these until we see the FUN record, and then report them
   1.231 +  // after the StartFunction call.
   1.232 +  std::vector<Line> queued_lines_;
   1.233 +};
   1.234 +
   1.235 +// Consumer-provided callback structure for the STABS reader.  Clients
   1.236 +// of the STABS reader provide an instance of this structure.  The
   1.237 +// reader then invokes the member functions of that instance to report
   1.238 +// the information it finds.
   1.239 +//
   1.240 +// The default definitions of the member functions do nothing, and return
   1.241 +// true so processing will continue.
   1.242 +class StabsHandler {
   1.243 + public:
   1.244 +  StabsHandler() { }
   1.245 +  virtual ~StabsHandler() { }
   1.246 +
   1.247 +  // Some general notes about the handler callback functions:
   1.248 +
   1.249 +  // Processing proceeds until the end of the .stabs section, or until
   1.250 +  // one of these functions returns false.
   1.251 +
   1.252 +  // The addresses given are as reported in the STABS info, without
   1.253 +  // regard for whether the module may be loaded at different
   1.254 +  // addresses at different times (a shared library, say).  When
   1.255 +  // processing STABS from an ELF shared library, the addresses given
   1.256 +  // all assume the library is loaded at its nominal load address.
   1.257 +  // They are *not* offsets from the nominal load address.  If you
   1.258 +  // want offsets, you must subtract off the library's nominal load
   1.259 +  // address.
   1.260 +
   1.261 +  // The arguments to these functions named FILENAME are all
   1.262 +  // references to strings stored in the .stabstr section.  Because
   1.263 +  // both the Linux and Solaris linkers factor out duplicate strings
   1.264 +  // from the .stabstr section, the consumer can assume that if two
   1.265 +  // FILENAME values are different addresses, they represent different
   1.266 +  // file names.
   1.267 +  //
   1.268 +  // Thus, it's safe to use (say) std::map<char *, ...>, which does
   1.269 +  // string address comparisons, not string content comparisons.
   1.270 +  // Since all the strings are in same array of characters --- the
   1.271 +  // .stabstr section --- comparing their addresses produces
   1.272 +  // predictable, if not lexicographically meaningful, results.
   1.273 +
   1.274 +  // Begin processing a compilation unit whose main source file is
   1.275 +  // named FILENAME, and whose base address is ADDRESS.  If
   1.276 +  // BUILD_DIRECTORY is non-NULL, it is the name of the build
   1.277 +  // directory in which the compilation occurred.
   1.278 +  virtual bool StartCompilationUnit(const char *filename, uint64_t address,
   1.279 +                                    const char *build_directory) {
   1.280 +    return true;
   1.281 +  }
   1.282 +
   1.283 +  // Finish processing the compilation unit.  If ADDRESS is non-zero,
   1.284 +  // it is the ending address of the compilation unit.  If ADDRESS is
   1.285 +  // zero, then the compilation unit's ending address is not
   1.286 +  // available, and the consumer must infer it by other means.
   1.287 +  virtual bool EndCompilationUnit(uint64_t address) { return true; }
   1.288 +
   1.289 +  // Begin processing a function named NAME, whose starting address is
   1.290 +  // ADDRESS.  This function belongs to the compilation unit that was
   1.291 +  // most recently started but not ended.
   1.292 +  //
   1.293 +  // Note that, unlike filenames, NAME is not a pointer into the
   1.294 +  // .stabstr section; this is because the name as it appears in the
   1.295 +  // STABS data is followed by type information.  The value passed to
   1.296 +  // StartFunction is the function name alone.
   1.297 +  //
   1.298 +  // In languages that use name mangling, like C++, NAME is mangled.
   1.299 +  virtual bool StartFunction(const string &name, uint64_t address) {
   1.300 +    return true;
   1.301 +  }
   1.302 +
   1.303 +  // Finish processing the function.  If ADDRESS is non-zero, it is
   1.304 +  // the ending address for the function.  If ADDRESS is zero, then
   1.305 +  // the function's ending address is not available, and the consumer
   1.306 +  // must infer it by other means.
   1.307 +  virtual bool EndFunction(uint64_t address) { return true; }
   1.308 +  
   1.309 +  // Report that the code at ADDRESS is attributable to line NUMBER of
   1.310 +  // the source file named FILENAME.  The caller must infer the ending
   1.311 +  // address of the line.
   1.312 +  virtual bool Line(uint64_t address, const char *filename, int number) {
   1.313 +    return true;
   1.314 +  }
   1.315 +
   1.316 +  // Report that an exported function NAME is present at ADDRESS.
   1.317 +  // The size of the function is unknown.
   1.318 +  virtual bool Extern(const string &name, uint64_t address) {
   1.319 +    return true;
   1.320 +  }
   1.321 +
   1.322 +  // Report a warning.  FORMAT is a printf-like format string,
   1.323 +  // specifying how to format the subsequent arguments.
   1.324 +  virtual void Warning(const char *format, ...) = 0;
   1.325 +};
   1.326 +
   1.327 +} // namespace google_breakpad
   1.328 +
   1.329 +#endif  // COMMON_STABS_READER_H__

mercurial