1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/stabs_reader.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,315 @@ 1.4 +// Copyright (c) 2010 Google Inc. All Rights Reserved. 1.5 +// 1.6 +// Redistribution and use in source and binary forms, with or without 1.7 +// modification, are permitted provided that the following conditions are 1.8 +// met: 1.9 +// 1.10 +// * Redistributions of source code must retain the above copyright 1.11 +// notice, this list of conditions and the following disclaimer. 1.12 +// * Redistributions in binary form must reproduce the above 1.13 +// copyright notice, this list of conditions and the following disclaimer 1.14 +// in the documentation and/or other materials provided with the 1.15 +// distribution. 1.16 +// * Neither the name of Google Inc. nor the names of its 1.17 +// contributors may be used to endorse or promote products derived from 1.18 +// this software without specific prior written permission. 1.19 +// 1.20 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.21 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.22 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.23 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.24 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.25 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.26 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.27 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.28 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.29 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.30 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.31 + 1.32 +// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> 1.33 + 1.34 +// This file implements the google_breakpad::StabsReader class. 1.35 +// See stabs_reader.h. 1.36 + 1.37 +#include "common/stabs_reader.h" 1.38 + 1.39 +#include <assert.h> 1.40 +#include <stab.h> 1.41 +#include <string.h> 1.42 + 1.43 +#include <string> 1.44 + 1.45 +#include "common/using_std_string.h" 1.46 + 1.47 +using std::vector; 1.48 + 1.49 +namespace google_breakpad { 1.50 + 1.51 +StabsReader::EntryIterator::EntryIterator(const ByteBuffer *buffer, 1.52 + bool big_endian, size_t value_size) 1.53 + : value_size_(value_size), cursor_(buffer, big_endian) { 1.54 + // Actually, we could handle weird sizes just fine, but they're 1.55 + // probably mistakes --- expressed in bits, say. 1.56 + assert(value_size == 4 || value_size == 8); 1.57 + entry_.index = 0; 1.58 + Fetch(); 1.59 +} 1.60 + 1.61 +void StabsReader::EntryIterator::Fetch() { 1.62 + cursor_ 1.63 + .Read(4, false, &entry_.name_offset) 1.64 + .Read(1, false, &entry_.type) 1.65 + .Read(1, false, &entry_.other) 1.66 + .Read(2, false, &entry_.descriptor) 1.67 + .Read(value_size_, false, &entry_.value); 1.68 + entry_.at_end = !cursor_; 1.69 +} 1.70 + 1.71 +StabsReader::StabsReader(const uint8_t *stab, size_t stab_size, 1.72 + const uint8_t *stabstr, size_t stabstr_size, 1.73 + bool big_endian, size_t value_size, bool unitized, 1.74 + StabsHandler *handler) 1.75 + : entries_(stab, stab_size), 1.76 + strings_(stabstr, stabstr_size), 1.77 + iterator_(&entries_, big_endian, value_size), 1.78 + unitized_(unitized), 1.79 + handler_(handler), 1.80 + string_offset_(0), 1.81 + next_cu_string_offset_(0), 1.82 + current_source_file_(NULL) { } 1.83 + 1.84 +const char *StabsReader::SymbolString() { 1.85 + ptrdiff_t offset = string_offset_ + iterator_->name_offset; 1.86 + if (offset < 0 || (size_t) offset >= strings_.Size()) { 1.87 + handler_->Warning("symbol %d: name offset outside the string section\n", 1.88 + iterator_->index); 1.89 + // Return our null string, to keep our promise about all names being 1.90 + // taken from the string section. 1.91 + offset = 0; 1.92 + } 1.93 + return reinterpret_cast<const char *>(strings_.start + offset); 1.94 +} 1.95 + 1.96 +bool StabsReader::Process() { 1.97 + while (!iterator_->at_end) { 1.98 + if (iterator_->type == N_SO) { 1.99 + if (! ProcessCompilationUnit()) 1.100 + return false; 1.101 + } else if (iterator_->type == N_UNDF && unitized_) { 1.102 + // In unitized STABS (including Linux STABS, and pretty much anything 1.103 + // else that puts STABS data in sections), at the head of each 1.104 + // compilation unit's entries there is an N_UNDF stab giving the 1.105 + // number of symbols in the compilation unit, and the number of bytes 1.106 + // that compilation unit's strings take up in the .stabstr section. 1.107 + // Each CU's strings are separate; the n_strx values are offsets 1.108 + // within the current CU's portion of the .stabstr section. 1.109 + // 1.110 + // As an optimization, the GNU linker combines all the 1.111 + // compilation units into one, with a single N_UNDF at the 1.112 + // beginning. However, other linkers, like Gold, do not perform 1.113 + // this optimization. 1.114 + string_offset_ = next_cu_string_offset_; 1.115 + next_cu_string_offset_ = iterator_->value; 1.116 + ++iterator_; 1.117 + } 1.118 +#if defined(HAVE_MACH_O_NLIST_H) 1.119 + // Export symbols in Mach-O binaries look like this. 1.120 + // This is necessary in order to be able to dump symbols 1.121 + // from OS X system libraries. 1.122 + else if ((iterator_->type & N_STAB) == 0 && 1.123 + (iterator_->type & N_TYPE) == N_SECT) { 1.124 + ProcessExtern(); 1.125 + } 1.126 +#endif 1.127 + else { 1.128 + ++iterator_; 1.129 + } 1.130 + } 1.131 + return true; 1.132 +} 1.133 + 1.134 +bool StabsReader::ProcessCompilationUnit() { 1.135 + assert(!iterator_->at_end && iterator_->type == N_SO); 1.136 + 1.137 + // There may be an N_SO entry whose name ends with a slash, 1.138 + // indicating the directory in which the compilation occurred. 1.139 + // The build directory defaults to NULL. 1.140 + const char *build_directory = NULL; 1.141 + { 1.142 + const char *name = SymbolString(); 1.143 + if (name[0] && name[strlen(name) - 1] == '/') { 1.144 + build_directory = name; 1.145 + ++iterator_; 1.146 + } 1.147 + } 1.148 + 1.149 + // We expect to see an N_SO entry with a filename next, indicating 1.150 + // the start of the compilation unit. 1.151 + { 1.152 + if (iterator_->at_end || iterator_->type != N_SO) 1.153 + return true; 1.154 + const char *name = SymbolString(); 1.155 + if (name[0] == '\0') { 1.156 + // This seems to be a stray end-of-compilation-unit marker; 1.157 + // consume it, but don't report the end, since we didn't see a 1.158 + // beginning. 1.159 + ++iterator_; 1.160 + return true; 1.161 + } 1.162 + current_source_file_ = name; 1.163 + } 1.164 + 1.165 + if (! handler_->StartCompilationUnit(current_source_file_, 1.166 + iterator_->value, 1.167 + build_directory)) 1.168 + return false; 1.169 + 1.170 + ++iterator_; 1.171 + 1.172 + // The STABS documentation says that some compilers may emit 1.173 + // additional N_SO entries with names immediately following the 1.174 + // first, and that they should be ignored. However, the original 1.175 + // Breakpad STABS reader doesn't ignore them, so we won't either. 1.176 + 1.177 + // Process the body of the compilation unit, up to the next N_SO. 1.178 + while (!iterator_->at_end && iterator_->type != N_SO) { 1.179 + if (iterator_->type == N_FUN) { 1.180 + if (! ProcessFunction()) 1.181 + return false; 1.182 + } else if (iterator_->type == N_SLINE) { 1.183 + // Mac OS X STABS place SLINE records before functions. 1.184 + Line line; 1.185 + // The value of an N_SLINE entry that appears outside a function is 1.186 + // the absolute address of the line. 1.187 + line.address = iterator_->value; 1.188 + line.filename = current_source_file_; 1.189 + // The n_desc of a N_SLINE entry is the line number. It's a 1.190 + // signed 16-bit field; line numbers from 32768 to 65535 are 1.191 + // stored as n-65536. 1.192 + line.number = (uint16_t) iterator_->descriptor; 1.193 + queued_lines_.push_back(line); 1.194 + ++iterator_; 1.195 + } else if (iterator_->type == N_SOL) { 1.196 + current_source_file_ = SymbolString(); 1.197 + ++iterator_; 1.198 + } else { 1.199 + // Ignore anything else. 1.200 + ++iterator_; 1.201 + } 1.202 + } 1.203 + 1.204 + // An N_SO with an empty name indicates the end of the compilation 1.205 + // unit. Default to zero. 1.206 + uint64_t ending_address = 0; 1.207 + if (!iterator_->at_end) { 1.208 + assert(iterator_->type == N_SO); 1.209 + const char *name = SymbolString(); 1.210 + if (name[0] == '\0') { 1.211 + ending_address = iterator_->value; 1.212 + ++iterator_; 1.213 + } 1.214 + } 1.215 + 1.216 + if (! handler_->EndCompilationUnit(ending_address)) 1.217 + return false; 1.218 + 1.219 + queued_lines_.clear(); 1.220 + 1.221 + return true; 1.222 +} 1.223 + 1.224 +bool StabsReader::ProcessFunction() { 1.225 + assert(!iterator_->at_end && iterator_->type == N_FUN); 1.226 + 1.227 + uint64_t function_address = iterator_->value; 1.228 + // The STABS string for an N_FUN entry is the name of the function, 1.229 + // followed by a colon, followed by type information for the 1.230 + // function. We want to pass the name alone to StartFunction. 1.231 + const char *stab_string = SymbolString(); 1.232 + const char *name_end = strchr(stab_string, ':'); 1.233 + if (! name_end) 1.234 + name_end = stab_string + strlen(stab_string); 1.235 + string name(stab_string, name_end - stab_string); 1.236 + if (! handler_->StartFunction(name, function_address)) 1.237 + return false; 1.238 + ++iterator_; 1.239 + 1.240 + // If there were any SLINE records given before the function, report them now. 1.241 + for (vector<Line>::const_iterator it = queued_lines_.begin(); 1.242 + it != queued_lines_.end(); it++) { 1.243 + if (!handler_->Line(it->address, it->filename, it->number)) 1.244 + return false; 1.245 + } 1.246 + queued_lines_.clear(); 1.247 + 1.248 + while (!iterator_->at_end) { 1.249 + if (iterator_->type == N_SO || iterator_->type == N_FUN) 1.250 + break; 1.251 + else if (iterator_->type == N_SLINE) { 1.252 + // The value of an N_SLINE entry is the offset of the line from 1.253 + // the function's start address. 1.254 + uint64_t line_address = function_address + iterator_->value; 1.255 + // The n_desc of a N_SLINE entry is the line number. It's a 1.256 + // signed 16-bit field; line numbers from 32768 to 65535 are 1.257 + // stored as n-65536. 1.258 + uint16_t line_number = iterator_->descriptor; 1.259 + if (! handler_->Line(line_address, current_source_file_, line_number)) 1.260 + return false; 1.261 + ++iterator_; 1.262 + } else if (iterator_->type == N_SOL) { 1.263 + current_source_file_ = SymbolString(); 1.264 + ++iterator_; 1.265 + } else 1.266 + // Ignore anything else. 1.267 + ++iterator_; 1.268 + } 1.269 + 1.270 + // We've reached the end of the function. See if we can figure out its 1.271 + // ending address. 1.272 + uint64_t ending_address = 0; 1.273 + if (!iterator_->at_end) { 1.274 + assert(iterator_->type == N_SO || iterator_->type == N_FUN); 1.275 + if (iterator_->type == N_FUN) { 1.276 + const char *symbol_name = SymbolString(); 1.277 + if (symbol_name[0] == '\0') { 1.278 + // An N_FUN entry with no name is a terminator for this function; 1.279 + // its value is the function's size. 1.280 + ending_address = function_address + iterator_->value; 1.281 + ++iterator_; 1.282 + } else { 1.283 + // An N_FUN entry with a name is the next function, and we can take 1.284 + // its value as our ending address. Don't advance the iterator, as 1.285 + // we'll use this symbol to start the next function as well. 1.286 + ending_address = iterator_->value; 1.287 + } 1.288 + } else { 1.289 + // An N_SO entry could be an end-of-compilation-unit marker, or the 1.290 + // start of the next compilation unit, but in either case, its value 1.291 + // is our ending address. We don't advance the iterator; 1.292 + // ProcessCompilationUnit will decide what to do with this symbol. 1.293 + ending_address = iterator_->value; 1.294 + } 1.295 + } 1.296 + 1.297 + if (! handler_->EndFunction(ending_address)) 1.298 + return false; 1.299 + 1.300 + return true; 1.301 +} 1.302 + 1.303 +bool StabsReader::ProcessExtern() { 1.304 +#if defined(HAVE_MACH_O_NLIST_H) 1.305 + assert(!iterator_->at_end && 1.306 + (iterator_->type & N_STAB) == 0 && 1.307 + (iterator_->type & N_TYPE) == N_SECT); 1.308 +#endif 1.309 + 1.310 + // TODO(mark): only do symbols in the text section? 1.311 + if (!handler_->Extern(SymbolString(), iterator_->value)) 1.312 + return false; 1.313 + 1.314 + ++iterator_; 1.315 + return true; 1.316 +} 1.317 + 1.318 +} // namespace google_breakpad