Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Unified Diff: third_party/crashpad/crashpad/snapshot/mac/mach_o_image_symbol_table_reader.cc

Issue 1505213004: Copy Crashpad into the Chrome tree instead of importing it via DEPS (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address review comments, update README.chromium Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/crashpad/crashpad/snapshot/mac/mach_o_image_symbol_table_reader.cc
diff --git a/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_symbol_table_reader.cc b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_symbol_table_reader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..949e46088697241c5eebc77ab35199d9f9e13fd1
--- /dev/null
+++ b/third_party/crashpad/crashpad/snapshot/mac/mach_o_image_symbol_table_reader.cc
@@ -0,0 +1,292 @@
+// Copyright 2014 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "snapshot/mac/mach_o_image_symbol_table_reader.h"
+
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+
+#include <utility>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/stringprintf.h"
+#include "util/mac/checked_mach_address_range.h"
+#include "util/mach/task_memory.h"
+
+namespace crashpad {
+
+namespace internal {
+
+//! \brief The internal implementation for MachOImageSymbolTableReader.
+//!
+//! Initialization is broken into more than one function that needs to share
+//! data, so member variables are used. However, much of this data is irrelevant
+//! after initialization is completed, so rather than doing it in
+//! MachOImageSymbolTableReader, it’s handled by this class, which is a “friend”
+//! of MachOImageSymbolTableReader.
+class MachOImageSymbolTableReaderInitializer {
+ public:
+ MachOImageSymbolTableReaderInitializer(
+ ProcessReader* process_reader,
+ const MachOImageSegmentReader* linkedit_segment,
+ const std::string& module_info)
+ : module_info_(module_info),
+ linkedit_range_(),
+ process_reader_(process_reader),
+ linkedit_segment_(linkedit_segment) {
+ linkedit_range_.SetRange(process_reader_->Is64Bit(),
+ linkedit_segment->Address(),
+ linkedit_segment->Size());
+ DCHECK(linkedit_range_.IsValid());
+ }
+
+ ~MachOImageSymbolTableReaderInitializer() {}
+
+ //! \brief Reads the symbol table from another process.
+ //!
+ //! \sa MachOImageSymbolTableReader::Initialize()
+ bool Initialize(const process_types::symtab_command* symtab_command,
+ const process_types::dysymtab_command* dysymtab_command,
+ MachOImageSymbolTableReader::SymbolInformationMap*
+ external_defined_symbols) {
+ mach_vm_address_t symtab_address =
+ AddressForLinkEditComponent(symtab_command->symoff);
+ uint32_t symbol_count = symtab_command->nsyms;
+ size_t nlist_size = process_types::nlist::ExpectedSize(process_reader_);
+ mach_vm_size_t symtab_size = symbol_count * nlist_size;
+ if (!IsInLinkEditSegment(symtab_address, symtab_size, "symtab")) {
+ return false;
+ }
+
+ // If a dysymtab is present, use it to filter the symtab for just the
+ // portion used for extdefsym. If no dysymtab is present, the entire symtab
+ // will need to be consulted.
+ uint32_t skip_count = 0;
+ if (dysymtab_command) {
+ if (dysymtab_command->iextdefsym >= symtab_command->nsyms ||
+ dysymtab_command->iextdefsym + dysymtab_command->nextdefsym >
+ symtab_command->nsyms) {
+ LOG(WARNING) << base::StringPrintf(
+ "dysymtab extdefsym %u + %u > symtab nsyms %u",
+ dysymtab_command->iextdefsym,
+ dysymtab_command->nextdefsym,
+ symtab_command->nsyms) << module_info_;
+ return false;
+ }
+
+ skip_count = dysymtab_command->iextdefsym;
+ mach_vm_size_t skip_size = skip_count * nlist_size;
+ symtab_address += skip_size;
+ symtab_size -= skip_size;
+ symbol_count = dysymtab_command->nextdefsym;
+ }
+
+ mach_vm_address_t strtab_address =
+ AddressForLinkEditComponent(symtab_command->stroff);
+ mach_vm_size_t strtab_size = symtab_command->strsize;
+ if (!IsInLinkEditSegment(strtab_address, strtab_size, "strtab")) {
+ return false;
+ }
+
+ scoped_ptr<process_types::nlist[]> symbols(
+ new process_types::nlist[symtab_command->nsyms]);
+ if (!process_types::nlist::ReadArrayInto(
+ process_reader_, symtab_address, symbol_count, &symbols[0])) {
+ LOG(WARNING) << "could not read symbol table" << module_info_;
+ return false;
+ }
+
+ scoped_ptr<TaskMemory::MappedMemory> string_table;
+ for (size_t symbol_index = 0; symbol_index < symbol_count; ++symbol_index) {
+ const process_types::nlist& symbol = symbols[symbol_index];
+ std::string symbol_info = base::StringPrintf(", symbol index %zu%s",
+ skip_count + symbol_index,
+ module_info_.c_str());
+ bool valid_symbol = true;
+ if ((symbol.n_type & N_STAB) == 0 && (symbol.n_type & N_PEXT) == 0 &&
+ (symbol.n_type & N_EXT)) {
+ uint8_t symbol_type = symbol.n_type & N_TYPE;
+ if (symbol_type == N_ABS || symbol_type == N_SECT) {
+ if (symbol.n_strx >= strtab_size) {
+ LOG(WARNING) << base::StringPrintf(
+ "string at 0x%x out of bounds (0x%llx)",
+ symbol.n_strx,
+ strtab_size) << symbol_info;
+ return false;
+ }
+
+ if (!string_table) {
+ string_table = process_reader_->Memory()->ReadMapped(
+ strtab_address, strtab_size);
+ if (!string_table) {
+ LOG(WARNING) << "could not read string table" << module_info_;
+ return false;
+ }
+ }
+
+ std::string name;
+ if (!string_table->ReadCString(symbol.n_strx, &name)) {
+ LOG(WARNING) << "could not read string" << symbol_info;
+ return false;
+ }
+
+ if (symbol_type == N_ABS && symbol.n_sect != NO_SECT) {
+ LOG(WARNING) << base::StringPrintf("N_ABS symbol %s in section %u",
+ name.c_str(),
+ symbol.n_sect) << symbol_info;
+ return false;
+ }
+
+ if (symbol_type == N_SECT && symbol.n_sect == NO_SECT) {
+ LOG(WARNING) << base::StringPrintf(
+ "N_SECT symbol %s in section NO_SECT",
+ name.c_str()) << symbol_info;
+ return false;
+ }
+
+ MachOImageSymbolTableReader::SymbolInformation this_symbol_info;
+ this_symbol_info.value = symbol.n_value;
+ this_symbol_info.section = symbol.n_sect;
+ if (!external_defined_symbols->insert(
+ std::make_pair(name, this_symbol_info)).second) {
+ LOG(WARNING) << "duplicate symbol " << name << symbol_info;
+ return false;
+ }
+ } else {
+ // External indirect symbols may be found in the portion of the symbol
+ // table used for external symbols as opposed to indirect symbols when
+ // the indirect symbols are also external. These can be produced by
+ // Xcode 5.1 ld64-236.3/src/ld/LinkEditClassic.hpp
+ // ld::tool::SymbolTableAtom<>::addGlobal(). Indirect symbols are not
+ // currently supported by this symbol table reader, so ignore them
+ // without failing or logging a message when encountering them. See
+ // https://groups.google.com/a/chromium.org/d/topic/crashpad-dev/k7QkLwO71Zo
+ valid_symbol = symbol_type == N_INDR;
+ }
+ } else {
+ valid_symbol = false;
+ }
+ if (!valid_symbol && dysymtab_command) {
+ LOG(WARNING) << "non-external symbol with type " << symbol.n_type
+ << " in extdefsym" << symbol_info;
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private:
+ //! \brief Computes the address for data in the `__LINKEDIT` segment
+ //! identified by its file offset in a Mach-O image.
+ //!
+ //! \param[in] fileoff The file offset relative to the beginning of an image’s
+ //! `mach_header` or `mach_header_64` of the data in the `__LINKEDIT`
+ //! segment.
+ //!
+ //! \return The address, in the remote process’ address space, of the
+ //! requested data.
+ mach_vm_address_t AddressForLinkEditComponent(uint32_t fileoff) const {
+ return linkedit_range_.Base() + fileoff - linkedit_segment_->fileoff();
+ }
+
+ //! \brief Determines whether an address range is located within the
+ //! `__LINKEDIT` segment.
+ //!
+ //! \param[in] address The base address of the range to check.
+ //! \param[in] size The size of the range to check.
+ //! \param[in] tag A string that identifies the range being checked. This is
+ //! used only for logging.
+ //!
+ //! \return `true` if the range identified by \a address + \a size lies
+ //! entirely within the `__LINKEDIT` segment. `false` if that range is
+ //! invalid, or if that range is not contained by the `__LINKEDIT`
+ //! segment, with an appropriate message logged.
+ bool IsInLinkEditSegment(mach_vm_address_t address,
+ mach_vm_size_t size,
+ const char* tag) const {
+ CheckedMachAddressRange subrange(process_reader_->Is64Bit(), address, size);
+ if (!subrange.IsValid()) {
+ LOG(WARNING) << base::StringPrintf("invalid %s range (0x%llx + 0x%llx)",
+ tag,
+ address,
+ size) << module_info_;
+ return false;
+ }
+
+ if (!linkedit_range_.ContainsRange(subrange)) {
+ LOG(WARNING) << base::StringPrintf(
+ "%s at 0x%llx + 0x%llx outside of " SEG_LINKEDIT
+ " segment at 0x%llx + 0x%llx",
+ tag,
+ address,
+ size,
+ linkedit_range_.Base(),
+ linkedit_range_.Size()) << module_info_;
+ return false;
+ }
+
+ return true;
+ }
+
+ std::string module_info_;
+ CheckedMachAddressRange linkedit_range_;
+ ProcessReader* process_reader_; // weak
+ const MachOImageSegmentReader* linkedit_segment_; // weak
+
+ DISALLOW_COPY_AND_ASSIGN(MachOImageSymbolTableReaderInitializer);
+};
+
+} // namespace internal
+
+MachOImageSymbolTableReader::MachOImageSymbolTableReader()
+ : external_defined_symbols_(), initialized_() {
+}
+
+MachOImageSymbolTableReader::~MachOImageSymbolTableReader() {
+}
+
+bool MachOImageSymbolTableReader::Initialize(
+ ProcessReader* process_reader,
+ const process_types::symtab_command* symtab_command,
+ const process_types::dysymtab_command* dysymtab_command,
+ const MachOImageSegmentReader* linkedit_segment,
+ const std::string& module_info) {
+ INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
+
+ internal::MachOImageSymbolTableReaderInitializer initializer(process_reader,
+ linkedit_segment,
+ module_info);
+ if (!initializer.Initialize(
+ symtab_command, dysymtab_command, &external_defined_symbols_)) {
+ return false;
+ }
+
+ INITIALIZATION_STATE_SET_VALID(initialized_);
+ return true;
+}
+
+const MachOImageSymbolTableReader::SymbolInformation*
+MachOImageSymbolTableReader::LookUpExternalDefinedSymbol(
+ const std::string& name) const {
+ INITIALIZATION_STATE_DCHECK_VALID(initialized_);
+
+ const auto& iterator = external_defined_symbols_.find(name);
+ if (iterator == external_defined_symbols_.end()) {
+ return nullptr;
+ }
+ return &iterator->second;
+}
+
+} // namespace crashpad

Powered by Google App Engine
This is Rietveld 408576698