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

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 // Copyright (c) 2010 Google Inc. All Rights Reserved.
michael@0 2 //
michael@0 3 // Redistribution and use in source and binary forms, with or without
michael@0 4 // modification, are permitted provided that the following conditions are
michael@0 5 // met:
michael@0 6 //
michael@0 7 // * Redistributions of source code must retain the above copyright
michael@0 8 // notice, this list of conditions and the following disclaimer.
michael@0 9 // * Redistributions in binary form must reproduce the above
michael@0 10 // copyright notice, this list of conditions and the following disclaimer
michael@0 11 // in the documentation and/or other materials provided with the
michael@0 12 // distribution.
michael@0 13 // * Neither the name of Google Inc. nor the names of its
michael@0 14 // contributors may be used to endorse or promote products derived from
michael@0 15 // this software without specific prior written permission.
michael@0 16 //
michael@0 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
michael@0 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
michael@0 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
michael@0 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
michael@0 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
michael@0 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
michael@0 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
michael@0 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
michael@0 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
michael@0 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
michael@0 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
michael@0 28
michael@0 29 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
michael@0 30
michael@0 31 // This file implements the google_breakpad::StabsReader class.
michael@0 32 // See stabs_reader.h.
michael@0 33
michael@0 34 #include "common/stabs_reader.h"
michael@0 35
michael@0 36 #include <assert.h>
michael@0 37 #include <stab.h>
michael@0 38 #include <string.h>
michael@0 39
michael@0 40 #include <string>
michael@0 41
michael@0 42 #include "common/using_std_string.h"
michael@0 43
michael@0 44 using std::vector;
michael@0 45
michael@0 46 namespace google_breakpad {
michael@0 47
michael@0 48 StabsReader::EntryIterator::EntryIterator(const ByteBuffer *buffer,
michael@0 49 bool big_endian, size_t value_size)
michael@0 50 : value_size_(value_size), cursor_(buffer, big_endian) {
michael@0 51 // Actually, we could handle weird sizes just fine, but they're
michael@0 52 // probably mistakes --- expressed in bits, say.
michael@0 53 assert(value_size == 4 || value_size == 8);
michael@0 54 entry_.index = 0;
michael@0 55 Fetch();
michael@0 56 }
michael@0 57
michael@0 58 void StabsReader::EntryIterator::Fetch() {
michael@0 59 cursor_
michael@0 60 .Read(4, false, &entry_.name_offset)
michael@0 61 .Read(1, false, &entry_.type)
michael@0 62 .Read(1, false, &entry_.other)
michael@0 63 .Read(2, false, &entry_.descriptor)
michael@0 64 .Read(value_size_, false, &entry_.value);
michael@0 65 entry_.at_end = !cursor_;
michael@0 66 }
michael@0 67
michael@0 68 StabsReader::StabsReader(const uint8_t *stab, size_t stab_size,
michael@0 69 const uint8_t *stabstr, size_t stabstr_size,
michael@0 70 bool big_endian, size_t value_size, bool unitized,
michael@0 71 StabsHandler *handler)
michael@0 72 : entries_(stab, stab_size),
michael@0 73 strings_(stabstr, stabstr_size),
michael@0 74 iterator_(&entries_, big_endian, value_size),
michael@0 75 unitized_(unitized),
michael@0 76 handler_(handler),
michael@0 77 string_offset_(0),
michael@0 78 next_cu_string_offset_(0),
michael@0 79 current_source_file_(NULL) { }
michael@0 80
michael@0 81 const char *StabsReader::SymbolString() {
michael@0 82 ptrdiff_t offset = string_offset_ + iterator_->name_offset;
michael@0 83 if (offset < 0 || (size_t) offset >= strings_.Size()) {
michael@0 84 handler_->Warning("symbol %d: name offset outside the string section\n",
michael@0 85 iterator_->index);
michael@0 86 // Return our null string, to keep our promise about all names being
michael@0 87 // taken from the string section.
michael@0 88 offset = 0;
michael@0 89 }
michael@0 90 return reinterpret_cast<const char *>(strings_.start + offset);
michael@0 91 }
michael@0 92
michael@0 93 bool StabsReader::Process() {
michael@0 94 while (!iterator_->at_end) {
michael@0 95 if (iterator_->type == N_SO) {
michael@0 96 if (! ProcessCompilationUnit())
michael@0 97 return false;
michael@0 98 } else if (iterator_->type == N_UNDF && unitized_) {
michael@0 99 // In unitized STABS (including Linux STABS, and pretty much anything
michael@0 100 // else that puts STABS data in sections), at the head of each
michael@0 101 // compilation unit's entries there is an N_UNDF stab giving the
michael@0 102 // number of symbols in the compilation unit, and the number of bytes
michael@0 103 // that compilation unit's strings take up in the .stabstr section.
michael@0 104 // Each CU's strings are separate; the n_strx values are offsets
michael@0 105 // within the current CU's portion of the .stabstr section.
michael@0 106 //
michael@0 107 // As an optimization, the GNU linker combines all the
michael@0 108 // compilation units into one, with a single N_UNDF at the
michael@0 109 // beginning. However, other linkers, like Gold, do not perform
michael@0 110 // this optimization.
michael@0 111 string_offset_ = next_cu_string_offset_;
michael@0 112 next_cu_string_offset_ = iterator_->value;
michael@0 113 ++iterator_;
michael@0 114 }
michael@0 115 #if defined(HAVE_MACH_O_NLIST_H)
michael@0 116 // Export symbols in Mach-O binaries look like this.
michael@0 117 // This is necessary in order to be able to dump symbols
michael@0 118 // from OS X system libraries.
michael@0 119 else if ((iterator_->type & N_STAB) == 0 &&
michael@0 120 (iterator_->type & N_TYPE) == N_SECT) {
michael@0 121 ProcessExtern();
michael@0 122 }
michael@0 123 #endif
michael@0 124 else {
michael@0 125 ++iterator_;
michael@0 126 }
michael@0 127 }
michael@0 128 return true;
michael@0 129 }
michael@0 130
michael@0 131 bool StabsReader::ProcessCompilationUnit() {
michael@0 132 assert(!iterator_->at_end && iterator_->type == N_SO);
michael@0 133
michael@0 134 // There may be an N_SO entry whose name ends with a slash,
michael@0 135 // indicating the directory in which the compilation occurred.
michael@0 136 // The build directory defaults to NULL.
michael@0 137 const char *build_directory = NULL;
michael@0 138 {
michael@0 139 const char *name = SymbolString();
michael@0 140 if (name[0] && name[strlen(name) - 1] == '/') {
michael@0 141 build_directory = name;
michael@0 142 ++iterator_;
michael@0 143 }
michael@0 144 }
michael@0 145
michael@0 146 // We expect to see an N_SO entry with a filename next, indicating
michael@0 147 // the start of the compilation unit.
michael@0 148 {
michael@0 149 if (iterator_->at_end || iterator_->type != N_SO)
michael@0 150 return true;
michael@0 151 const char *name = SymbolString();
michael@0 152 if (name[0] == '\0') {
michael@0 153 // This seems to be a stray end-of-compilation-unit marker;
michael@0 154 // consume it, but don't report the end, since we didn't see a
michael@0 155 // beginning.
michael@0 156 ++iterator_;
michael@0 157 return true;
michael@0 158 }
michael@0 159 current_source_file_ = name;
michael@0 160 }
michael@0 161
michael@0 162 if (! handler_->StartCompilationUnit(current_source_file_,
michael@0 163 iterator_->value,
michael@0 164 build_directory))
michael@0 165 return false;
michael@0 166
michael@0 167 ++iterator_;
michael@0 168
michael@0 169 // The STABS documentation says that some compilers may emit
michael@0 170 // additional N_SO entries with names immediately following the
michael@0 171 // first, and that they should be ignored. However, the original
michael@0 172 // Breakpad STABS reader doesn't ignore them, so we won't either.
michael@0 173
michael@0 174 // Process the body of the compilation unit, up to the next N_SO.
michael@0 175 while (!iterator_->at_end && iterator_->type != N_SO) {
michael@0 176 if (iterator_->type == N_FUN) {
michael@0 177 if (! ProcessFunction())
michael@0 178 return false;
michael@0 179 } else if (iterator_->type == N_SLINE) {
michael@0 180 // Mac OS X STABS place SLINE records before functions.
michael@0 181 Line line;
michael@0 182 // The value of an N_SLINE entry that appears outside a function is
michael@0 183 // the absolute address of the line.
michael@0 184 line.address = iterator_->value;
michael@0 185 line.filename = current_source_file_;
michael@0 186 // The n_desc of a N_SLINE entry is the line number. It's a
michael@0 187 // signed 16-bit field; line numbers from 32768 to 65535 are
michael@0 188 // stored as n-65536.
michael@0 189 line.number = (uint16_t) iterator_->descriptor;
michael@0 190 queued_lines_.push_back(line);
michael@0 191 ++iterator_;
michael@0 192 } else if (iterator_->type == N_SOL) {
michael@0 193 current_source_file_ = SymbolString();
michael@0 194 ++iterator_;
michael@0 195 } else {
michael@0 196 // Ignore anything else.
michael@0 197 ++iterator_;
michael@0 198 }
michael@0 199 }
michael@0 200
michael@0 201 // An N_SO with an empty name indicates the end of the compilation
michael@0 202 // unit. Default to zero.
michael@0 203 uint64_t ending_address = 0;
michael@0 204 if (!iterator_->at_end) {
michael@0 205 assert(iterator_->type == N_SO);
michael@0 206 const char *name = SymbolString();
michael@0 207 if (name[0] == '\0') {
michael@0 208 ending_address = iterator_->value;
michael@0 209 ++iterator_;
michael@0 210 }
michael@0 211 }
michael@0 212
michael@0 213 if (! handler_->EndCompilationUnit(ending_address))
michael@0 214 return false;
michael@0 215
michael@0 216 queued_lines_.clear();
michael@0 217
michael@0 218 return true;
michael@0 219 }
michael@0 220
michael@0 221 bool StabsReader::ProcessFunction() {
michael@0 222 assert(!iterator_->at_end && iterator_->type == N_FUN);
michael@0 223
michael@0 224 uint64_t function_address = iterator_->value;
michael@0 225 // The STABS string for an N_FUN entry is the name of the function,
michael@0 226 // followed by a colon, followed by type information for the
michael@0 227 // function. We want to pass the name alone to StartFunction.
michael@0 228 const char *stab_string = SymbolString();
michael@0 229 const char *name_end = strchr(stab_string, ':');
michael@0 230 if (! name_end)
michael@0 231 name_end = stab_string + strlen(stab_string);
michael@0 232 string name(stab_string, name_end - stab_string);
michael@0 233 if (! handler_->StartFunction(name, function_address))
michael@0 234 return false;
michael@0 235 ++iterator_;
michael@0 236
michael@0 237 // If there were any SLINE records given before the function, report them now.
michael@0 238 for (vector<Line>::const_iterator it = queued_lines_.begin();
michael@0 239 it != queued_lines_.end(); it++) {
michael@0 240 if (!handler_->Line(it->address, it->filename, it->number))
michael@0 241 return false;
michael@0 242 }
michael@0 243 queued_lines_.clear();
michael@0 244
michael@0 245 while (!iterator_->at_end) {
michael@0 246 if (iterator_->type == N_SO || iterator_->type == N_FUN)
michael@0 247 break;
michael@0 248 else if (iterator_->type == N_SLINE) {
michael@0 249 // The value of an N_SLINE entry is the offset of the line from
michael@0 250 // the function's start address.
michael@0 251 uint64_t line_address = function_address + iterator_->value;
michael@0 252 // The n_desc of a N_SLINE entry is the line number. It's a
michael@0 253 // signed 16-bit field; line numbers from 32768 to 65535 are
michael@0 254 // stored as n-65536.
michael@0 255 uint16_t line_number = iterator_->descriptor;
michael@0 256 if (! handler_->Line(line_address, current_source_file_, line_number))
michael@0 257 return false;
michael@0 258 ++iterator_;
michael@0 259 } else if (iterator_->type == N_SOL) {
michael@0 260 current_source_file_ = SymbolString();
michael@0 261 ++iterator_;
michael@0 262 } else
michael@0 263 // Ignore anything else.
michael@0 264 ++iterator_;
michael@0 265 }
michael@0 266
michael@0 267 // We've reached the end of the function. See if we can figure out its
michael@0 268 // ending address.
michael@0 269 uint64_t ending_address = 0;
michael@0 270 if (!iterator_->at_end) {
michael@0 271 assert(iterator_->type == N_SO || iterator_->type == N_FUN);
michael@0 272 if (iterator_->type == N_FUN) {
michael@0 273 const char *symbol_name = SymbolString();
michael@0 274 if (symbol_name[0] == '\0') {
michael@0 275 // An N_FUN entry with no name is a terminator for this function;
michael@0 276 // its value is the function's size.
michael@0 277 ending_address = function_address + iterator_->value;
michael@0 278 ++iterator_;
michael@0 279 } else {
michael@0 280 // An N_FUN entry with a name is the next function, and we can take
michael@0 281 // its value as our ending address. Don't advance the iterator, as
michael@0 282 // we'll use this symbol to start the next function as well.
michael@0 283 ending_address = iterator_->value;
michael@0 284 }
michael@0 285 } else {
michael@0 286 // An N_SO entry could be an end-of-compilation-unit marker, or the
michael@0 287 // start of the next compilation unit, but in either case, its value
michael@0 288 // is our ending address. We don't advance the iterator;
michael@0 289 // ProcessCompilationUnit will decide what to do with this symbol.
michael@0 290 ending_address = iterator_->value;
michael@0 291 }
michael@0 292 }
michael@0 293
michael@0 294 if (! handler_->EndFunction(ending_address))
michael@0 295 return false;
michael@0 296
michael@0 297 return true;
michael@0 298 }
michael@0 299
michael@0 300 bool StabsReader::ProcessExtern() {
michael@0 301 #if defined(HAVE_MACH_O_NLIST_H)
michael@0 302 assert(!iterator_->at_end &&
michael@0 303 (iterator_->type & N_STAB) == 0 &&
michael@0 304 (iterator_->type & N_TYPE) == N_SECT);
michael@0 305 #endif
michael@0 306
michael@0 307 // TODO(mark): only do symbols in the text section?
michael@0 308 if (!handler_->Extern(SymbolString(), iterator_->value))
michael@0 309 return false;
michael@0 310
michael@0 311 ++iterator_;
michael@0 312 return true;
michael@0 313 }
michael@0 314
michael@0 315 } // namespace google_breakpad

mercurial