Index: util/mac/mach_o_image_reader.h |
diff --git a/util/mac/mach_o_image_reader.h b/util/mac/mach_o_image_reader.h |
index eb2435486361172dc7def5e4aa240768e724bda3..fc7be578335ddc79981b2741737a012c13c3e13b 100644 |
--- a/util/mac/mach_o_image_reader.h |
+++ b/util/mac/mach_o_image_reader.h |
@@ -31,6 +31,7 @@ |
namespace crashpad { |
class MachOImageSegmentReader; |
+class MachOImageSymbolTableReader; |
class ProcessReader; |
//! \brief A reader for Mach-O images mapped into another process. |
@@ -106,30 +107,13 @@ class MachOImageReader { |
//! |
//! \param[in] segment_name The name of the segment to search for, for |
//! example, `"__TEXT"`. |
- //! \param[out] address The actual address that the segment was loaded at in |
- //! memory, taking any “slide” into account if the segment did not load at |
- //! its preferred address as stored in the Mach-O image file. This |
- //! parameter can be `NULL`. |
- //! \param[out] size The actual size of the segment as loaded at in memory. |
- //! This value takes any expansion of the segment into account, which |
- //! occurs when a nonsliding segment in a sliding image loads at its |
- //! preferred address but grows by the value of the slide. This parameter |
- //! can be `NULL`. |
//! |
//! \return A pointer to the segment information if it was found, or `NULL` if |
- //! it was not found. |
- //! |
- //! \note The \a address parameter takes “slide” into account, and the \a size |
- //! parameter takes growth into account for non-sliding segments, so that |
- //! these parameters reflect the actual address and size of the segment as |
- //! loaded into a process’ address space. This is distinct from the |
- //! segment’s preferred load address and size, which may be obtained by |
- //! calling MachOImageSegmentReader::vmaddr() and |
- //! MachOImageSegmentReader::vmsize(), respectively. |
+ //! it was not found. The caller does not take ownership; the lifetime of |
+ //! the returned object is scoped to the lifetime of this MachOImageReader |
+ //! object. |
const MachOImageSegmentReader* GetSegmentByName( |
- const std::string& segment_name, |
- mach_vm_address_t* address, |
- mach_vm_size_t* size) const; |
+ const std::string& segment_name) const; |
//! \brief Obtain section information by segment and section name. |
//! |
@@ -143,7 +127,9 @@ class MachOImageReader { |
//! parameter can be `NULL`. |
//! |
//! \return A pointer to the section information if it was found, or `NULL` if |
- //! it was not found. |
+ //! it was not found. The caller does not take ownership; the lifetime of |
+ //! the returned object is scoped to the lifetime of this MachOImageReader |
+ //! object. |
//! |
//! No parameter is provided for the section’s size, because it can be |
//! obtained from the returned process_types::section::size field. |
@@ -162,13 +148,19 @@ class MachOImageReader { |
//! \param[in] index The index of the section to return, in the order that it |
//! appears in the segment load commands. This is a 1-based index, |
//! matching the section number values used for `nlist::n_sect`. |
+ //! \param[out] containing_segment The segment that contains the section. |
+ //! This parameter can be `NULL`. The caller does not take ownership; |
+ //! the lifetime of the returned object is scoped to the lifetime of this |
+ //! MachOImageReader object. |
//! \param[out] address The actual address that the section was loaded at in |
//! memory, taking any “slide” into account if the section did not load at |
//! its preferred address as stored in the Mach-O image file. This |
//! parameter can be `NULL`. |
//! |
//! \return A pointer to the section information. If \a index is out of range, |
- //! logs a warning and returns `NULL`. |
+ //! logs a warning and returns `NULL`. The caller does not take ownership; |
+ //! the lifetime of the returned object is scoped to the lifetime of this |
+ //! MachOImageReader object. |
//! |
//! No parameter is provided for the section’s size, because it can be |
//! obtained from the returned process_types::section::size field. |
@@ -186,8 +178,52 @@ class MachOImageReader { |
//! and handled non-fatally by reporting the error to the caller. |
const process_types::section* GetSectionAtIndex( |
size_t index, |
+ const MachOImageSegmentReader** containing_segment, |
mach_vm_address_t* address) const; |
+ //! \brief Looks up a symbol in the image’s symbol table. |
+ //! |
+ //! This method is capable of locating external defined symbols. Specifically, |
+ //! this method can look up symbols that have these charcteristics: |
+ //! - `N_STAB` (debugging) and `N_PEXT` (private external) must not be set. |
+ //! - `N_EXT` (external) must be set. |
+ //! - The type must be `N_ABS` (absolute) or `N_SECT` (defined in section). |
+ //! |
+ //! `N_INDR` (indirect), `N_UNDF` (undefined), and `N_PBUD` (prebound |
+ //! undefined) symbols cannot be located through this mechanism. |
+ //! |
+ //! \param[in] name The name of the symbol to look up, “mangled” or |
+ //! “decorated” appropriately. For example, use `"_main"` to look up the |
+ //! symbol for the C `main()` function, and use `"__Z4Funcv"` to look up |
+ //! the symbol for the C++ `Func()` function. Contrary to `dlsym()`, the |
+ //! leading underscore must not be stripped when using this interface. |
+ //! \param[out] value If the lookup was successful, this will be set to the |
+ //! value of the symbol, adjusted for any “slide” as needed. The value can |
+ //! be used as an address in the remote process’ address space where the |
+ //! pointee of the symbol exists in memory. |
+ //! |
+ //! \return `true` if the symbol lookup was successful and the symbol was |
+ //! found. `false` otherwise, including error conditions (for which a |
+ //! warning message will be logged), modules without symbol tables, and |
+ //! symbol names not found in the symbol table. |
+ //! |
+ //! \note Symbol values returned via this interface are adjusted for “slide” |
+ //! as appropriate, in contrast to the underlying implementation, |
+ //! MachOImageSymbolTableReader::LookUpExternalDefinedSymbol(). |
+ //! |
+ //! \warning Symbols that are resolved by running symbol resolvers |
+ //! (`.symbol_resolver`) are not properly handled by this interface. The |
+ //! address of the symbol resolver is returned because that’s what shows |
+ //! up in the symbol table, rather than the effective address of the |
+ //! resolved symbol as used by dyld after running the resolver. The only |
+ //! way to detect this situation would be to read the `LC_DYLD_INFO` or |
+ //! `LC_DYLD_INFO_ONLY` load command if present and looking for the |
+ //! `EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER` flag, but that would just be |
+ //! able to detect symbols with a resolver, it would not be able to |
+ //! resolve them from out-of-process, so it’s not currently done. |
+ bool LookUpExternalDefinedSymbol(const std::string& name, |
+ mach_vm_address_t* value) const; |
+ |
//! \brief Returns a Mach-O dylib image’s current version. |
//! |
//! This information comes from the `dylib_current_version` field of a dylib’s |
@@ -255,6 +291,19 @@ class MachOImageReader { |
bool ReadUnexpectedCommand(mach_vm_address_t load_command_address, |
const std::string& load_command_info); |
+ // Performs deferred initialization of the symbol table. Because a module’s |
+ // symbol table is often not needed, this is not handled in Initialize(), but |
+ // is done lazily, on-demand as needed. |
+ // |
+ // symbol_table_initialized_ will be transitioned to the appropriate state. If |
+ // initialization completes successfully, this will be the valid state. |
+ // Otherwise, it will be left in the invalid state and a warning message will |
+ // be logged. |
+ // |
+ // Note that if the object contains no symbol table, symbol_table_initialized_ |
+ // will be set to the valid state, but symbol_table_ will be NULL. |
+ void InitializeSymbolTable() const; |
+ |
PointerVector<MachOImageSegmentReader> segments_; |
std::map<std::string, size_t> segment_map_; |
std::string module_info_; |
@@ -266,11 +315,25 @@ class MachOImageReader { |
uint64_t source_version_; |
scoped_ptr<process_types::symtab_command> symtab_command_; |
scoped_ptr<process_types::dysymtab_command> dysymtab_command_; |
+ |
+ // symbol_table_ (and symbol_table_initialized_) are mutable in order to |
+ // maintain LookUpExternalDefinedSymbol() as a const interface while allowing |
+ // lazy initialization via InitializeSymbolTable(). This is logical |
+ // const-ness, not physical const-ness. |
+ mutable scoped_ptr<MachOImageSymbolTableReader> symbol_table_; |
+ |
scoped_ptr<process_types::dylib_command> id_dylib_command_; |
ProcessReader* process_reader_; // weak |
uint32_t file_type_; |
InitializationStateDcheck initialized_; |
+ // symbol_table_initialized_ protects symbol_table_: symbol_table_ can only |
+ // be used when symbol_table_initialized_ is valid, although |
+ // symbol_table_initialized_ being valid doesn’t imply that symbol_table_ is |
+ // set. symbol_table_initialized_ will be valid without symbol_table_ being |
+ // set in modules that have no symbol table. |
+ mutable InitializationState symbol_table_initialized_; |
+ |
DISALLOW_COPY_AND_ASSIGN(MachOImageReader); |
}; |