mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-31 01:43:03 +08:00
032f1aecc2
Add direct includes for things provided transitively by logging.h (or by other headers including logging.h). This is in preparation for cleaning up unnecessary includes of logging.h in header files (so if something depends on logging.h, it needs include it explicitly), and for when Chromium's logging.h no longer includes check.h, check_op.h, and notreached.h. DEPS is also updated to roll mini_chromium to ae14a14ab4 which includes these new header files. Bug: chromium:1031540 Change-Id: I36f646d0a93854989dc602d0dc7139dd7a7b8621 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/2250251 Commit-Queue: Hans Wennborg <hans@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
295 lines
12 KiB
C++
295 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() {}
|
||
|
||
//! \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
|
||
|
||
DISALLOW_COPY_AND_ASSIGN(MachOImageSymbolTableReaderInitializer);
|
||
};
|
||
|
||
} // 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
|