mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-29 00:32:35 +08:00
1aa478d161
This change was partially scripted and partially done manually with vim regex + manually placing the deleted constructors. The script change looked for destructors in the public: section of a class, if that existed the deleted constructors would go before the destructor. For manual placement I looked for any constructor in the public: section of the corresponding class. If there wasn't one, then it would ideally have gone as the first entry except below enums, classes and typedefs. This may not have been perfect, but is hopefully good enough. Fingers crossed. #include "base/macros.h" is removed from files that don't use ignore_result, which is the only other thing defined in base/macros.h. Bug: chromium:1010217 Change-Id: I099526255a40b1ac1264904b4ece2f3f503c9418 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3171034 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Peter Boström <pbos@chromium.org>
298 lines
12 KiB
C++
298 lines
12 KiB
C++
// 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 <sys/types.h>
|
||
|
||
#include <memory>
|
||
#include <utility>
|
||
|
||
#include "base/logging.h"
|
||
#include "base/strings/stringprintf.h"
|
||
#include "util/mac/checked_mach_address_range.h"
|
||
#include "util/process/process_memory_mac.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(
|
||
ProcessReaderMac* 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(
|
||
const MachOImageSymbolTableReaderInitializer&) = delete;
|
||
MachOImageSymbolTableReaderInitializer& operator=(
|
||
const MachOImageSymbolTableReaderInitializer&) = delete;
|
||
|
||
~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;
|
||
}
|
||
|
||
std::unique_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;
|
||
}
|
||
|
||
std::unique_ptr<ProcessMemoryMac::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_;
|
||
ProcessReaderMac* process_reader_; // weak
|
||
const MachOImageSegmentReader* linkedit_segment_; // weak
|
||
};
|
||
|
||
} // namespace internal
|
||
|
||
MachOImageSymbolTableReader::MachOImageSymbolTableReader()
|
||
: external_defined_symbols_(), initialized_() {
|
||
}
|
||
|
||
MachOImageSymbolTableReader::~MachOImageSymbolTableReader() {
|
||
}
|
||
|
||
bool MachOImageSymbolTableReader::Initialize(
|
||
ProcessReaderMac* 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
|