mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2025-11-13 09:04:59 +00:00
ELF modules are loaded in memory in several, possibly discontiguous, segments. If the holes between segments are large enough, other things, possibly other ELF modules may be mapped in that space. Crashpad records the range of modules as the base address of the lowest mapped segment to the high address of the highest mapped segment. This means that when one module is mapped into a hole in another, it appears to the Breakpad processor as overlapping modules. Module ranges are relevant to the Breakpad processor during stackwalking for identifying which module a particular program counter belongs to (i.e. mapping the address to a module's text segment). This patch addresses this issue of overlapping modules by truncating the range of the module with the lower base address. A typical module's text segment is the first loaded segment which would leave the text segment range unaffected. Module producers can restrict the size of holes in their ELF modules with the flag "-Wl,-z,max-page-size=4096", preventing other modules from being mapped in their address range. Properly contemplating ELF module address ranges would require extensions to the minidump format to encode any holes. crbug.com/crashpad/298 This patch also renames the concept of "shrinking down" (which truncated the upper of two overlapping ranges) to "truncate upper". Change-Id: I4599201f1e43918db036c390961f8b39e3af1849 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/1646932 Reviewed-by: Mark Mentovai <mark@chromium.org>
1350 lines
49 KiB
C++
1350 lines
49 KiB
C++
// Copyright (c) 2010 Google Inc.
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
// minidump.h: A minidump reader.
|
|
//
|
|
// The basic structure of this module tracks the structure of the minidump
|
|
// file itself. At the top level, a minidump file is represented by a
|
|
// Minidump object. Like most other classes in this module, Minidump
|
|
// provides a Read method that initializes the object with information from
|
|
// the file. Most of the classes in this file are wrappers around the
|
|
// "raw" structures found in the minidump file itself, and defined in
|
|
// minidump_format.h. For example, each thread is represented by a
|
|
// MinidumpThread object, whose parameters are specified in an MDRawThread
|
|
// structure. A properly byte-swapped MDRawThread can be obtained from a
|
|
// MinidumpThread easily by calling its thread() method.
|
|
//
|
|
// Most of the module lazily reads only the portion of the minidump file
|
|
// necessary to fulfill the user's request. Calling Minidump::Read
|
|
// only reads the minidump's directory. The thread list is not read until
|
|
// it is needed, and even once it's read, the memory regions for each
|
|
// thread's stack aren't read until they're needed. This strategy avoids
|
|
// unnecessary file input, and allocating memory for data in which the user
|
|
// has no interest. Note that although memory allocations for a typical
|
|
// minidump file are not particularly large, it is possible for legitimate
|
|
// minidumps to be sizable. A full-memory minidump, for example, contains
|
|
// a snapshot of the entire mapped memory space. Even a normal minidump,
|
|
// with stack memory only, can be large if, for example, the dump was
|
|
// generated in response to a crash that occurred due to an infinite-
|
|
// recursion bug that caused the stack's limits to be exceeded. Finally,
|
|
// some users of this library will unfortunately find themselves in the
|
|
// position of having to process potentially-hostile minidumps that might
|
|
// attempt to cause problems by forcing the minidump processor to over-
|
|
// allocate memory.
|
|
//
|
|
// Memory management in this module is based on a strict
|
|
// you-don't-own-anything policy. The only object owned by the user is
|
|
// the top-level Minidump object, the creation and destruction of which
|
|
// must be the user's own responsibility. All other objects obtained
|
|
// through interaction with this module are ultimately owned by the
|
|
// Minidump object, and will be freed upon the Minidump object's destruction.
|
|
// Because memory regions can potentially involve large allocations, a
|
|
// FreeMemory method is provided by MinidumpMemoryRegion, allowing the user
|
|
// to release data when it is no longer needed. Use of this method is
|
|
// optional but recommended. If freed data is later required, it will
|
|
// be read back in from the minidump file again.
|
|
//
|
|
// There is one exception to this memory management policy:
|
|
// Minidump::ReadString will return a string object to the user, and the user
|
|
// is responsible for its deletion.
|
|
//
|
|
// Author: Mark Mentovai
|
|
|
|
#ifndef GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_H__
|
|
#define GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_H__
|
|
|
|
#include <stdint.h>
|
|
|
|
#ifndef _WIN32
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "common/basictypes.h"
|
|
#include "common/using_std_string.h"
|
|
#include "google_breakpad/processor/code_module.h"
|
|
#include "google_breakpad/processor/code_modules.h"
|
|
#include "google_breakpad/processor/dump_context.h"
|
|
#include "google_breakpad/processor/dump_object.h"
|
|
#include "google_breakpad/processor/memory_region.h"
|
|
#include "google_breakpad/processor/proc_maps_linux.h"
|
|
|
|
|
|
namespace google_breakpad {
|
|
|
|
|
|
using std::map;
|
|
using std::vector;
|
|
|
|
|
|
class Minidump;
|
|
template<typename AddressType, typename EntryType> class RangeMap;
|
|
|
|
|
|
// MinidumpObject is the base of all Minidump* objects except for Minidump
|
|
// itself.
|
|
class MinidumpObject : public DumpObject {
|
|
public:
|
|
virtual ~MinidumpObject() {}
|
|
|
|
protected:
|
|
explicit MinidumpObject(Minidump* minidump);
|
|
|
|
// Refers to the Minidump object that is the ultimate parent of this
|
|
// Some MinidumpObjects are owned by other MinidumpObjects, but at the
|
|
// root of the ownership tree is always a Minidump. The Minidump object
|
|
// is kept here for access to its seeking and reading facilities, and
|
|
// for access to data about the minidump file itself, such as whether
|
|
// it should be byte-swapped.
|
|
Minidump* minidump_;
|
|
};
|
|
|
|
|
|
// This class exists primarily to provide a virtual destructor in a base
|
|
// class common to all objects that might be stored in
|
|
// Minidump::mStreamObjects. Some object types will never be stored in
|
|
// Minidump::mStreamObjects, but are represented as streams and adhere to the
|
|
// same interface, and may be derived from this class.
|
|
class MinidumpStream : public MinidumpObject {
|
|
public:
|
|
virtual ~MinidumpStream() {}
|
|
|
|
protected:
|
|
explicit MinidumpStream(Minidump* minidump);
|
|
|
|
private:
|
|
// Populate (and validate) the MinidumpStream. minidump_ is expected
|
|
// to be positioned at the beginning of the stream, so that the next
|
|
// read from the minidump will be at the beginning of the stream.
|
|
// expected_size should be set to the stream's length as contained in
|
|
// the MDRawDirectory record or other identifying record. A class
|
|
// that implements MinidumpStream can compare expected_size to a
|
|
// known size as an integrity check.
|
|
virtual bool Read(uint32_t expected_size) = 0;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpStream);
|
|
};
|
|
|
|
|
|
// MinidumpContext carries a CPU-specific MDRawContext structure, which
|
|
// contains CPU context such as register states. Each thread has its
|
|
// own context, and the exception record, if present, also has its own
|
|
// context. Note that if the exception record is present, the context it
|
|
// refers to is probably what the user wants to use for the exception
|
|
// thread, instead of that thread's own context. The exception thread's
|
|
// context (as opposed to the exception record's context) will contain
|
|
// context for the exception handler (which performs minidump generation),
|
|
// and not the context that caused the exception (which is probably what the
|
|
// user wants).
|
|
class MinidumpContext : public DumpContext {
|
|
public:
|
|
virtual ~MinidumpContext();
|
|
|
|
protected:
|
|
explicit MinidumpContext(Minidump* minidump);
|
|
|
|
private:
|
|
friend class MinidumpThread;
|
|
friend class MinidumpException;
|
|
|
|
bool Read(uint32_t expected_size);
|
|
|
|
// If the minidump contains a SYSTEM_INFO_STREAM, makes sure that the
|
|
// system info stream gives an appropriate CPU type matching the context
|
|
// CPU type in context_cpu_type. Returns false if the CPU type does not
|
|
// match. Returns true if the CPU type matches or if the minidump does
|
|
// not contain a system info stream.
|
|
bool CheckAgainstSystemInfo(uint32_t context_cpu_type);
|
|
|
|
// Refers to the Minidump object that is the ultimate parent of this
|
|
// Some MinidumpObjects are owned by other MinidumpObjects, but at the
|
|
// root of the ownership tree is always a Minidump. The Minidump object
|
|
// is kept here for access to its seeking and reading facilities, and
|
|
// for access to data about the minidump file itself, such as whether
|
|
// it should be byte-swapped.
|
|
Minidump* minidump_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpContext);
|
|
};
|
|
|
|
|
|
// MinidumpMemoryRegion does not wrap any MDRaw structure, and only contains
|
|
// a reference to an MDMemoryDescriptor. This object is intended to wrap
|
|
// portions of a minidump file that contain memory dumps. In normal
|
|
// minidumps, each MinidumpThread owns a MinidumpMemoryRegion corresponding
|
|
// to the thread's stack memory. MinidumpMemoryList also gives access to
|
|
// memory regions in its list as MinidumpMemoryRegions. This class
|
|
// adheres to MemoryRegion so that it may be used as a data provider to
|
|
// the Stackwalker family of classes.
|
|
class MinidumpMemoryRegion : public MinidumpObject,
|
|
public MemoryRegion {
|
|
public:
|
|
virtual ~MinidumpMemoryRegion();
|
|
|
|
static void set_max_bytes(uint32_t max_bytes) { max_bytes_ = max_bytes; }
|
|
static uint32_t max_bytes() { return max_bytes_; }
|
|
|
|
// Returns a pointer to the base of the memory region. Returns the
|
|
// cached value if available, otherwise, reads the minidump file and
|
|
// caches the memory region.
|
|
const uint8_t* GetMemory() const;
|
|
|
|
// The address of the base of the memory region.
|
|
uint64_t GetBase() const;
|
|
|
|
// The size, in bytes, of the memory region.
|
|
uint32_t GetSize() const;
|
|
|
|
// Frees the cached memory region, if cached.
|
|
void FreeMemory();
|
|
|
|
// Obtains the value of memory at the pointer specified by address.
|
|
bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const;
|
|
bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const;
|
|
bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const;
|
|
bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const;
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print() const;
|
|
void SetPrintMode(bool hexdump, unsigned int width);
|
|
|
|
protected:
|
|
explicit MinidumpMemoryRegion(Minidump* minidump);
|
|
|
|
private:
|
|
friend class MinidumpThread;
|
|
friend class MinidumpMemoryList;
|
|
|
|
// Identify the base address and size of the memory region, and the
|
|
// location it may be found in the minidump file.
|
|
void SetDescriptor(MDMemoryDescriptor* descriptor);
|
|
|
|
// Implementation for GetMemoryAtAddress
|
|
template<typename T> bool GetMemoryAtAddressInternal(uint64_t address,
|
|
T* value) const;
|
|
|
|
// Knobs for controlling display of memory printing.
|
|
bool hexdump_;
|
|
unsigned int hexdump_width_;
|
|
|
|
// The largest memory region that will be read from a minidump.
|
|
static uint32_t max_bytes_;
|
|
|
|
// Base address and size of the memory region, and its position in the
|
|
// minidump file.
|
|
MDMemoryDescriptor* descriptor_;
|
|
|
|
// Cached memory.
|
|
mutable vector<uint8_t>* memory_;
|
|
};
|
|
|
|
|
|
// MinidumpThread contains information about a thread of execution,
|
|
// including a snapshot of the thread's stack and CPU context. For
|
|
// the thread that caused an exception, the context carried by
|
|
// MinidumpException is probably desired instead of the CPU context
|
|
// provided here.
|
|
// Note that a MinidumpThread may be valid() even if it does not
|
|
// contain a memory region or context.
|
|
class MinidumpThread : public MinidumpObject {
|
|
public:
|
|
virtual ~MinidumpThread();
|
|
|
|
const MDRawThread* thread() const { return valid_ ? &thread_ : NULL; }
|
|
// GetMemory may return NULL even if the MinidumpThread is valid,
|
|
// if the thread memory cannot be read.
|
|
virtual MinidumpMemoryRegion* GetMemory();
|
|
// GetContext may return NULL even if the MinidumpThread is valid.
|
|
virtual MinidumpContext* GetContext();
|
|
|
|
// The thread ID is used to determine if a thread is the exception thread,
|
|
// so a special getter is provided to retrieve this data from the
|
|
// MDRawThread structure. Returns false if the thread ID cannot be
|
|
// determined.
|
|
virtual bool GetThreadID(uint32_t *thread_id) const;
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
// Returns the start address of the thread stack memory region. Returns 0 if
|
|
// MinidumpThread is invalid. Note that this method can be called even when
|
|
// the thread memory cannot be read and GetMemory returns NULL.
|
|
virtual uint64_t GetStartOfStackMemoryRange() const;
|
|
|
|
protected:
|
|
explicit MinidumpThread(Minidump* minidump);
|
|
|
|
private:
|
|
// These objects are managed by MinidumpThreadList.
|
|
friend class MinidumpThreadList;
|
|
|
|
// This works like MinidumpStream::Read, but is driven by
|
|
// MinidumpThreadList. No size checking is done, because
|
|
// MinidumpThreadList handles that directly.
|
|
bool Read();
|
|
|
|
MDRawThread thread_;
|
|
MinidumpMemoryRegion* memory_;
|
|
MinidumpContext* context_;
|
|
};
|
|
|
|
|
|
// MinidumpThreadList contains all of the threads (as MinidumpThreads) in
|
|
// a process.
|
|
class MinidumpThreadList : public MinidumpStream {
|
|
public:
|
|
virtual ~MinidumpThreadList();
|
|
|
|
static void set_max_threads(uint32_t max_threads) {
|
|
max_threads_ = max_threads;
|
|
}
|
|
static uint32_t max_threads() { return max_threads_; }
|
|
|
|
virtual unsigned int thread_count() const {
|
|
return valid_ ? thread_count_ : 0;
|
|
}
|
|
|
|
// Sequential access to threads.
|
|
virtual MinidumpThread* GetThreadAtIndex(unsigned int index) const;
|
|
|
|
// Random access to threads.
|
|
MinidumpThread* GetThreadByID(uint32_t thread_id);
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
protected:
|
|
explicit MinidumpThreadList(Minidump* aMinidump);
|
|
|
|
private:
|
|
friend class Minidump;
|
|
|
|
typedef map<uint32_t, MinidumpThread*> IDToThreadMap;
|
|
typedef vector<MinidumpThread> MinidumpThreads;
|
|
|
|
static const uint32_t kStreamType = MD_THREAD_LIST_STREAM;
|
|
|
|
bool Read(uint32_t aExpectedSize) override;
|
|
|
|
// The largest number of threads that will be read from a minidump. The
|
|
// default is 256.
|
|
static uint32_t max_threads_;
|
|
|
|
// Access to threads using the thread ID as the key.
|
|
IDToThreadMap id_to_thread_map_;
|
|
|
|
// The list of threads.
|
|
MinidumpThreads* threads_;
|
|
uint32_t thread_count_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpThreadList);
|
|
};
|
|
|
|
|
|
// MinidumpModule wraps MDRawModule, which contains information about loaded
|
|
// code modules. Access is provided to various data referenced indirectly
|
|
// by MDRawModule, such as the module's name and a specification for where
|
|
// to locate debugging information for the module.
|
|
class MinidumpModule : public MinidumpObject,
|
|
public CodeModule {
|
|
public:
|
|
virtual ~MinidumpModule();
|
|
|
|
static void set_max_cv_bytes(uint32_t max_cv_bytes) {
|
|
max_cv_bytes_ = max_cv_bytes;
|
|
}
|
|
static uint32_t max_cv_bytes() { return max_cv_bytes_; }
|
|
|
|
static void set_max_misc_bytes(uint32_t max_misc_bytes) {
|
|
max_misc_bytes_ = max_misc_bytes;
|
|
}
|
|
static uint32_t max_misc_bytes() { return max_misc_bytes_; }
|
|
|
|
const MDRawModule* module() const { return valid_ ? &module_ : NULL; }
|
|
|
|
// CodeModule implementation
|
|
virtual uint64_t base_address() const {
|
|
return valid_ ? module_.base_of_image : static_cast<uint64_t>(-1);
|
|
}
|
|
virtual uint64_t size() const { return valid_ ? module_.size_of_image : 0; }
|
|
virtual string code_file() const;
|
|
virtual string code_identifier() const;
|
|
virtual string debug_file() const;
|
|
virtual string debug_identifier() const;
|
|
virtual string version() const;
|
|
virtual CodeModule* Copy() const;
|
|
virtual bool is_unloaded() const { return false; }
|
|
|
|
// Getter and setter for shrink_down_delta. This is used when the address
|
|
// range for a module is shrunk down due to address range conflicts with
|
|
// other modules. The base_address and size fields are not updated and they
|
|
// should always reflect the original values (reported in the minidump).
|
|
virtual uint64_t shrink_down_delta() const;
|
|
virtual void SetShrinkDownDelta(uint64_t shrink_down_delta);
|
|
|
|
// The CodeView record, which contains information to locate the module's
|
|
// debugging information (pdb). This is returned as uint8_t* because
|
|
// the data can be of types MDCVInfoPDB20* or MDCVInfoPDB70*, or it may be
|
|
// of a type unknown to Breakpad, in which case the raw data will still be
|
|
// returned but no byte-swapping will have been performed. Check the
|
|
// record's signature in the first four bytes to differentiate between
|
|
// the various types. Current toolchains generate modules which carry
|
|
// MDCVInfoPDB70 by default. Returns a pointer to the CodeView record on
|
|
// success, and NULL on failure. On success, the optional |size| argument
|
|
// is set to the size of the CodeView record.
|
|
const uint8_t* GetCVRecord(uint32_t* size);
|
|
|
|
// The miscellaneous debug record, which is obsolete. Current toolchains
|
|
// do not generate this type of debugging information (dbg), and this
|
|
// field is not expected to be present. Returns a pointer to the debugging
|
|
// record on success, and NULL on failure. On success, the optional |size|
|
|
// argument is set to the size of the debugging record.
|
|
const MDImageDebugMisc* GetMiscRecord(uint32_t* size);
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
private:
|
|
// These objects are managed by MinidumpModuleList.
|
|
friend class MinidumpModuleList;
|
|
|
|
explicit MinidumpModule(Minidump* minidump);
|
|
|
|
// This works like MinidumpStream::Read, but is driven by
|
|
// MinidumpModuleList. No size checking is done, because
|
|
// MinidumpModuleList handles that directly.
|
|
bool Read();
|
|
|
|
// Reads indirectly-referenced data, including the module name, CodeView
|
|
// record, and miscellaneous debugging record. This is necessary to allow
|
|
// MinidumpModuleList to fully construct MinidumpModule objects without
|
|
// requiring seeks to read a contiguous set of MinidumpModule objects.
|
|
// All auxiliary data should be available when Read is called, in order to
|
|
// allow the CodeModule getters to be const methods.
|
|
bool ReadAuxiliaryData();
|
|
|
|
// The largest number of bytes that will be read from a minidump for a
|
|
// CodeView record or miscellaneous debugging record, respectively. The
|
|
// default for each is 1024.
|
|
static uint32_t max_cv_bytes_;
|
|
static uint32_t max_misc_bytes_;
|
|
|
|
// True after a successful Read. This is different from valid_, which is
|
|
// not set true until ReadAuxiliaryData also completes successfully.
|
|
// module_valid_ is only used by ReadAuxiliaryData and the functions it
|
|
// calls to determine whether the object is ready for auxiliary data to
|
|
// be read.
|
|
bool module_valid_;
|
|
|
|
// True if debug info was read from the module. Certain modules
|
|
// may contain debug records in formats we don't support,
|
|
// so we can just set this to false to ignore them.
|
|
bool has_debug_info_;
|
|
|
|
MDRawModule module_;
|
|
|
|
// Cached module name.
|
|
const string* name_;
|
|
|
|
// Cached CodeView record - this is MDCVInfoPDB20 or (likely)
|
|
// MDCVInfoPDB70, or possibly something else entirely. Stored as a uint8_t
|
|
// because the structure contains a variable-sized string and its exact
|
|
// size cannot be known until it is processed.
|
|
vector<uint8_t>* cv_record_;
|
|
|
|
// If cv_record_ is present, cv_record_signature_ contains a copy of the
|
|
// CodeView record's first four bytes, for ease of determinining the
|
|
// type of structure that cv_record_ contains.
|
|
uint32_t cv_record_signature_;
|
|
|
|
// Cached MDImageDebugMisc (usually not present), stored as uint8_t
|
|
// because the structure contains a variable-sized string and its exact
|
|
// size cannot be known until it is processed.
|
|
vector<uint8_t>* misc_record_;
|
|
};
|
|
|
|
|
|
// MinidumpModuleList contains all of the loaded code modules for a process
|
|
// in the form of MinidumpModules. It maintains a map of these modules
|
|
// so that it may easily provide a code module corresponding to a specific
|
|
// address.
|
|
class MinidumpModuleList : public MinidumpStream,
|
|
public CodeModules {
|
|
public:
|
|
virtual ~MinidumpModuleList();
|
|
|
|
static void set_max_modules(uint32_t max_modules) {
|
|
max_modules_ = max_modules;
|
|
}
|
|
static uint32_t max_modules() { return max_modules_; }
|
|
|
|
// CodeModules implementation.
|
|
virtual unsigned int module_count() const {
|
|
return valid_ ? module_count_ : 0;
|
|
}
|
|
virtual const MinidumpModule* GetModuleForAddress(uint64_t address) const;
|
|
virtual const MinidumpModule* GetMainModule() const;
|
|
virtual const MinidumpModule* GetModuleAtSequence(
|
|
unsigned int sequence) const;
|
|
virtual const MinidumpModule* GetModuleAtIndex(unsigned int index) const;
|
|
virtual const CodeModules* Copy() const;
|
|
|
|
// Returns a vector of all modules which address ranges needed to be shrunk
|
|
// down due to address range conflicts with other modules.
|
|
virtual vector<linked_ptr<const CodeModule> > GetShrunkRangeModules() const;
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
protected:
|
|
explicit MinidumpModuleList(Minidump* minidump);
|
|
|
|
private:
|
|
friend class Minidump;
|
|
|
|
typedef vector<MinidumpModule> MinidumpModules;
|
|
|
|
static const uint32_t kStreamType = MD_MODULE_LIST_STREAM;
|
|
|
|
bool Read(uint32_t expected_size);
|
|
|
|
bool StoreRange(const MinidumpModule& module,
|
|
uint64_t base_address,
|
|
uint32_t module_index,
|
|
uint32_t module_count,
|
|
bool is_android);
|
|
|
|
// The largest number of modules that will be read from a minidump. The
|
|
// default is 1024.
|
|
static uint32_t max_modules_;
|
|
|
|
// Access to modules using addresses as the key.
|
|
RangeMap<uint64_t, unsigned int> *range_map_;
|
|
|
|
MinidumpModules *modules_;
|
|
uint32_t module_count_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpModuleList);
|
|
};
|
|
|
|
|
|
// MinidumpMemoryList corresponds to a minidump's MEMORY_LIST_STREAM stream,
|
|
// which references the snapshots of all of the memory regions contained
|
|
// within the minidump. For a normal minidump, this includes stack memory
|
|
// (also referenced by each MinidumpThread, in fact, the MDMemoryDescriptors
|
|
// here and in MDRawThread both point to exactly the same data in a
|
|
// minidump file, conserving space), as well as a 256-byte snapshot of memory
|
|
// surrounding the instruction pointer in the case of an exception. Other
|
|
// types of minidumps may contain significantly more memory regions. Full-
|
|
// memory minidumps contain all of a process' mapped memory.
|
|
class MinidumpMemoryList : public MinidumpStream {
|
|
public:
|
|
virtual ~MinidumpMemoryList();
|
|
|
|
static void set_max_regions(uint32_t max_regions) {
|
|
max_regions_ = max_regions;
|
|
}
|
|
static uint32_t max_regions() { return max_regions_; }
|
|
|
|
unsigned int region_count() const { return valid_ ? region_count_ : 0; }
|
|
|
|
// Sequential access to memory regions.
|
|
MinidumpMemoryRegion* GetMemoryRegionAtIndex(unsigned int index);
|
|
|
|
// Random access to memory regions. Returns the region encompassing
|
|
// the address identified by address.
|
|
virtual MinidumpMemoryRegion* GetMemoryRegionForAddress(uint64_t address);
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
private:
|
|
friend class Minidump;
|
|
friend class MockMinidumpMemoryList;
|
|
|
|
typedef vector<MDMemoryDescriptor> MemoryDescriptors;
|
|
typedef vector<MinidumpMemoryRegion> MemoryRegions;
|
|
|
|
static const uint32_t kStreamType = MD_MEMORY_LIST_STREAM;
|
|
|
|
explicit MinidumpMemoryList(Minidump* minidump);
|
|
|
|
bool Read(uint32_t expected_size) override;
|
|
|
|
// The largest number of memory regions that will be read from a minidump.
|
|
// The default is 256.
|
|
static uint32_t max_regions_;
|
|
|
|
// Access to memory regions using addresses as the key.
|
|
RangeMap<uint64_t, unsigned int> *range_map_;
|
|
|
|
// The list of descriptors. This is maintained separately from the list
|
|
// of regions, because MemoryRegion doesn't own its MemoryDescriptor, it
|
|
// maintains a pointer to it. descriptors_ provides the storage for this
|
|
// purpose.
|
|
MemoryDescriptors *descriptors_;
|
|
|
|
// The list of regions.
|
|
MemoryRegions *regions_;
|
|
uint32_t region_count_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpMemoryList);
|
|
};
|
|
|
|
|
|
// MinidumpException wraps MDRawExceptionStream, which contains information
|
|
// about the exception that caused the minidump to be generated, if the
|
|
// minidump was generated in an exception handler called as a result of an
|
|
// exception. It also provides access to a MinidumpContext object, which
|
|
// contains the CPU context for the exception thread at the time the exception
|
|
// occurred.
|
|
class MinidumpException : public MinidumpStream {
|
|
public:
|
|
virtual ~MinidumpException();
|
|
|
|
const MDRawExceptionStream* exception() const {
|
|
return valid_ ? &exception_ : NULL;
|
|
}
|
|
|
|
// The thread ID is used to determine if a thread is the exception thread,
|
|
// so a special getter is provided to retrieve this data from the
|
|
// MDRawExceptionStream structure. Returns false if the thread ID cannot
|
|
// be determined.
|
|
bool GetThreadID(uint32_t *thread_id) const;
|
|
|
|
MinidumpContext* GetContext();
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
private:
|
|
friend class Minidump;
|
|
|
|
static const uint32_t kStreamType = MD_EXCEPTION_STREAM;
|
|
|
|
explicit MinidumpException(Minidump* minidump);
|
|
|
|
bool Read(uint32_t expected_size) override;
|
|
|
|
MDRawExceptionStream exception_;
|
|
MinidumpContext* context_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpException);
|
|
};
|
|
|
|
// MinidumpAssertion wraps MDRawAssertionInfo, which contains information
|
|
// about an assertion that caused the minidump to be generated.
|
|
class MinidumpAssertion : public MinidumpStream {
|
|
public:
|
|
virtual ~MinidumpAssertion();
|
|
|
|
const MDRawAssertionInfo* assertion() const {
|
|
return valid_ ? &assertion_ : NULL;
|
|
}
|
|
|
|
string expression() const {
|
|
return valid_ ? expression_ : "";
|
|
}
|
|
|
|
string function() const {
|
|
return valid_ ? function_ : "";
|
|
}
|
|
|
|
string file() const {
|
|
return valid_ ? file_ : "";
|
|
}
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
private:
|
|
friend class Minidump;
|
|
|
|
static const uint32_t kStreamType = MD_ASSERTION_INFO_STREAM;
|
|
|
|
explicit MinidumpAssertion(Minidump* minidump);
|
|
|
|
bool Read(uint32_t expected_size) override;
|
|
|
|
MDRawAssertionInfo assertion_;
|
|
string expression_;
|
|
string function_;
|
|
string file_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpAssertion);
|
|
};
|
|
|
|
|
|
// MinidumpSystemInfo wraps MDRawSystemInfo and provides information about
|
|
// the system on which the minidump was generated. See also MinidumpMiscInfo.
|
|
class MinidumpSystemInfo : public MinidumpStream {
|
|
public:
|
|
virtual ~MinidumpSystemInfo();
|
|
|
|
const MDRawSystemInfo* system_info() const {
|
|
return valid_ ? &system_info_ : NULL;
|
|
}
|
|
|
|
// GetOS and GetCPU return textual representations of the operating system
|
|
// and CPU that produced the minidump. Unlike most other Minidump* methods,
|
|
// they return string objects, not weak pointers. Defined values for
|
|
// GetOS() are "mac", "windows", and "linux". Defined values for GetCPU
|
|
// are "x86" and "ppc". These methods return an empty string when their
|
|
// values are unknown.
|
|
string GetOS();
|
|
string GetCPU();
|
|
|
|
// I don't know what CSD stands for, but this field is documented as
|
|
// returning a textual representation of the OS service pack. On other
|
|
// platforms, this provides additional information about an OS version
|
|
// level beyond major.minor.micro. Returns NULL if unknown.
|
|
const string* GetCSDVersion();
|
|
|
|
// If a CPU vendor string can be determined, returns a pointer to it,
|
|
// otherwise, returns NULL. CPU vendor strings can be determined from
|
|
// x86 CPUs with CPUID 0.
|
|
const string* GetCPUVendor();
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
protected:
|
|
explicit MinidumpSystemInfo(Minidump* minidump);
|
|
MDRawSystemInfo system_info_;
|
|
|
|
// Textual representation of the OS service pack, for minidumps produced
|
|
// by MiniDumpWriteDump on Windows.
|
|
const string* csd_version_;
|
|
|
|
private:
|
|
friend class Minidump;
|
|
|
|
static const uint32_t kStreamType = MD_SYSTEM_INFO_STREAM;
|
|
|
|
bool Read(uint32_t expected_size) override;
|
|
|
|
// A string identifying the CPU vendor, if known.
|
|
const string* cpu_vendor_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpSystemInfo);
|
|
};
|
|
|
|
|
|
// MinidumpUnloadedModule wraps MDRawUnloadedModule
|
|
class MinidumpUnloadedModule : public MinidumpObject,
|
|
public CodeModule {
|
|
public:
|
|
~MinidumpUnloadedModule() override;
|
|
|
|
const MDRawUnloadedModule* module() const {
|
|
return valid_ ? &unloaded_module_ : NULL;
|
|
}
|
|
|
|
// CodeModule implementation
|
|
uint64_t base_address() const override {
|
|
return valid_ ? unloaded_module_.base_of_image : 0;
|
|
}
|
|
uint64_t size() const override {
|
|
return valid_ ? unloaded_module_.size_of_image : 0;
|
|
}
|
|
string code_file() const override;
|
|
string code_identifier() const override;
|
|
string debug_file() const override;
|
|
string debug_identifier() const override;
|
|
string version() const override;
|
|
CodeModule* Copy() const override;
|
|
bool is_unloaded() const override { return true; }
|
|
uint64_t shrink_down_delta() const override;
|
|
void SetShrinkDownDelta(uint64_t shrink_down_delta) override;
|
|
|
|
protected:
|
|
explicit MinidumpUnloadedModule(Minidump* minidump);
|
|
|
|
private:
|
|
// These objects are managed by MinidumpUnloadedModuleList
|
|
friend class MinidumpUnloadedModuleList;
|
|
|
|
// This works like MinidumpStream::Read, but is driven by
|
|
// MinidumpUnloadedModuleList.
|
|
bool Read(uint32_t expected_size);
|
|
|
|
// Reads the module name. This is done separately from Read to
|
|
// allow contiguous reading of code modules by MinidumpUnloadedModuleList.
|
|
bool ReadAuxiliaryData();
|
|
|
|
// True after a successful Read. This is different from valid_, which
|
|
// is not set true until ReadAuxiliaryData also completes successfully.
|
|
// module_valid_ is only used by ReadAuxiliaryData and the functions it
|
|
// calls to determine whether the object is ready for auxiliary data to
|
|
// be read.
|
|
bool module_valid_;
|
|
|
|
MDRawUnloadedModule unloaded_module_;
|
|
|
|
// Cached module name
|
|
const string* name_;
|
|
};
|
|
|
|
|
|
// MinidumpUnloadedModuleList contains all the unloaded code modules for a
|
|
// process in the form of MinidumpUnloadedModules. It maintains a map of
|
|
// these modules so that it may easily provide a code module corresponding
|
|
// to a specific address. If multiple modules in the list have identical
|
|
// ranges, only the first module encountered is recorded in the range map.
|
|
class MinidumpUnloadedModuleList : public MinidumpStream,
|
|
public CodeModules {
|
|
public:
|
|
~MinidumpUnloadedModuleList() override;
|
|
|
|
static void set_max_modules(uint32_t max_modules) {
|
|
max_modules_ = max_modules;
|
|
}
|
|
static uint32_t max_modules() { return max_modules_; }
|
|
|
|
// CodeModules implementation.
|
|
unsigned int module_count() const override {
|
|
return valid_ ? module_count_ : 0;
|
|
}
|
|
const MinidumpUnloadedModule*
|
|
GetModuleForAddress(uint64_t address) const override;
|
|
const MinidumpUnloadedModule* GetMainModule() const override;
|
|
const MinidumpUnloadedModule*
|
|
GetModuleAtSequence(unsigned int sequence) const override;
|
|
const MinidumpUnloadedModule*
|
|
GetModuleAtIndex(unsigned int index) const override;
|
|
const CodeModules* Copy() const override;
|
|
vector<linked_ptr<const CodeModule>> GetShrunkRangeModules() const override;
|
|
|
|
protected:
|
|
explicit MinidumpUnloadedModuleList(Minidump* minidump_);
|
|
|
|
private:
|
|
friend class Minidump;
|
|
|
|
typedef vector<MinidumpUnloadedModule> MinidumpUnloadedModules;
|
|
|
|
static const uint32_t kStreamType = MD_UNLOADED_MODULE_LIST_STREAM;
|
|
|
|
bool Read(uint32_t expected_size_) override;
|
|
|
|
// The largest number of modules that will be read from a minidump. The
|
|
// default is 1024.
|
|
static uint32_t max_modules_;
|
|
|
|
// Access to module indices using addresses as the key.
|
|
RangeMap<uint64_t, unsigned int> *range_map_;
|
|
|
|
MinidumpUnloadedModules *unloaded_modules_;
|
|
uint32_t module_count_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpUnloadedModuleList);
|
|
};
|
|
|
|
|
|
// MinidumpMiscInfo wraps MDRawMiscInfo and provides information about
|
|
// the process that generated the minidump, and optionally additional system
|
|
// information. See also MinidumpSystemInfo.
|
|
class MinidumpMiscInfo : public MinidumpStream {
|
|
public:
|
|
const MDRawMiscInfo* misc_info() const {
|
|
return valid_ ? &misc_info_ : NULL;
|
|
}
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
private:
|
|
friend class Minidump;
|
|
friend class TestMinidumpMiscInfo;
|
|
|
|
static const uint32_t kStreamType = MD_MISC_INFO_STREAM;
|
|
|
|
explicit MinidumpMiscInfo(Minidump* minidump_);
|
|
|
|
bool Read(uint32_t expected_size_) override;
|
|
|
|
MDRawMiscInfo misc_info_;
|
|
|
|
// Populated by Read. Contains the converted strings from the corresponding
|
|
// UTF-16 fields in misc_info_
|
|
string standard_name_;
|
|
string daylight_name_;
|
|
string build_string_;
|
|
string dbg_bld_str_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpMiscInfo);
|
|
};
|
|
|
|
|
|
// MinidumpBreakpadInfo wraps MDRawBreakpadInfo, which is an optional stream in
|
|
// a minidump that provides additional information about the process state
|
|
// at the time the minidump was generated.
|
|
class MinidumpBreakpadInfo : public MinidumpStream {
|
|
public:
|
|
const MDRawBreakpadInfo* breakpad_info() const {
|
|
return valid_ ? &breakpad_info_ : NULL;
|
|
}
|
|
|
|
// These thread IDs are used to determine if threads deserve special
|
|
// treatment, so special getters are provided to retrieve this data from
|
|
// the MDRawBreakpadInfo structure. The getters return false if the thread
|
|
// IDs cannot be determined.
|
|
bool GetDumpThreadID(uint32_t *thread_id) const;
|
|
bool GetRequestingThreadID(uint32_t *thread_id) const;
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
private:
|
|
friend class Minidump;
|
|
|
|
static const uint32_t kStreamType = MD_BREAKPAD_INFO_STREAM;
|
|
|
|
explicit MinidumpBreakpadInfo(Minidump* minidump_);
|
|
|
|
bool Read(uint32_t expected_size_) override;
|
|
|
|
MDRawBreakpadInfo breakpad_info_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpBreakpadInfo);
|
|
};
|
|
|
|
// MinidumpMemoryInfo wraps MDRawMemoryInfo, which provides information
|
|
// about mapped memory regions in a process, including their ranges
|
|
// and protection.
|
|
class MinidumpMemoryInfo : public MinidumpObject {
|
|
public:
|
|
const MDRawMemoryInfo* info() const { return valid_ ? &memory_info_ : NULL; }
|
|
|
|
// The address of the base of the memory region.
|
|
uint64_t GetBase() const { return valid_ ? memory_info_.base_address : 0; }
|
|
|
|
// The size, in bytes, of the memory region.
|
|
uint64_t GetSize() const { return valid_ ? memory_info_.region_size : 0; }
|
|
|
|
// Return true if the memory protection allows execution.
|
|
bool IsExecutable() const;
|
|
|
|
// Return true if the memory protection allows writing.
|
|
bool IsWritable() const;
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
private:
|
|
// These objects are managed by MinidumpMemoryInfoList.
|
|
friend class MinidumpMemoryInfoList;
|
|
|
|
explicit MinidumpMemoryInfo(Minidump* minidump_);
|
|
|
|
// This works like MinidumpStream::Read, but is driven by
|
|
// MinidumpMemoryInfoList. No size checking is done, because
|
|
// MinidumpMemoryInfoList handles that directly.
|
|
bool Read();
|
|
|
|
MDRawMemoryInfo memory_info_;
|
|
};
|
|
|
|
// MinidumpMemoryInfoList contains a list of information about
|
|
// mapped memory regions for a process in the form of MDRawMemoryInfo.
|
|
// It maintains a map of these structures so that it may easily provide
|
|
// info corresponding to a specific address.
|
|
class MinidumpMemoryInfoList : public MinidumpStream {
|
|
public:
|
|
virtual ~MinidumpMemoryInfoList();
|
|
|
|
unsigned int info_count() const { return valid_ ? info_count_ : 0; }
|
|
|
|
const MinidumpMemoryInfo* GetMemoryInfoForAddress(uint64_t address) const;
|
|
const MinidumpMemoryInfo* GetMemoryInfoAtIndex(unsigned int index) const;
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
private:
|
|
friend class Minidump;
|
|
|
|
typedef vector<MinidumpMemoryInfo> MinidumpMemoryInfos;
|
|
|
|
static const uint32_t kStreamType = MD_MEMORY_INFO_LIST_STREAM;
|
|
|
|
explicit MinidumpMemoryInfoList(Minidump* minidump_);
|
|
|
|
bool Read(uint32_t expected_size) override;
|
|
|
|
// Access to memory info using addresses as the key.
|
|
RangeMap<uint64_t, unsigned int> *range_map_;
|
|
|
|
MinidumpMemoryInfos* infos_;
|
|
uint32_t info_count_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpMemoryInfoList);
|
|
};
|
|
|
|
// MinidumpLinuxMaps wraps information about a single mapped memory region
|
|
// from /proc/self/maps.
|
|
class MinidumpLinuxMaps : public MinidumpObject {
|
|
public:
|
|
// The memory address of the base of the mapped region.
|
|
uint64_t GetBase() const { return valid_ ? region_.start : 0; }
|
|
// The size of the mapped region.
|
|
uint64_t GetSize() const { return valid_ ? region_.end - region_.start : 0; }
|
|
|
|
// The permissions of the mapped region.
|
|
bool IsReadable() const {
|
|
return valid_ ? region_.permissions & MappedMemoryRegion::READ : false;
|
|
}
|
|
bool IsWriteable() const {
|
|
return valid_ ? region_.permissions & MappedMemoryRegion::WRITE : false;
|
|
}
|
|
bool IsExecutable() const {
|
|
return valid_ ? region_.permissions & MappedMemoryRegion::EXECUTE : false;
|
|
}
|
|
bool IsPrivate() const {
|
|
return valid_ ? region_.permissions & MappedMemoryRegion::PRIVATE : false;
|
|
}
|
|
|
|
// The offset of the mapped region.
|
|
uint64_t GetOffset() const { return valid_ ? region_.offset : 0; }
|
|
|
|
// The major device number.
|
|
uint8_t GetMajorDevice() const { return valid_ ? region_.major_device : 0; }
|
|
// The minor device number.
|
|
uint8_t GetMinorDevice() const { return valid_ ? region_.minor_device : 0; }
|
|
|
|
// The inode of the mapped region.
|
|
uint64_t GetInode() const { return valid_ ? region_.inode : 0; }
|
|
|
|
// The pathname of the mapped region.
|
|
const string GetPathname() const { return valid_ ? region_.path : ""; }
|
|
|
|
// Print the contents of this mapping.
|
|
void Print() const;
|
|
|
|
private:
|
|
// These objects are managed by MinidumpLinuxMapsList.
|
|
friend class MinidumpLinuxMapsList;
|
|
|
|
// This caller owns the pointer.
|
|
explicit MinidumpLinuxMaps(Minidump *minidump);
|
|
|
|
// The memory region struct that this class wraps.
|
|
MappedMemoryRegion region_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpLinuxMaps);
|
|
};
|
|
|
|
// MinidumpLinuxMapsList corresponds to the Linux-exclusive MD_LINUX_MAPS
|
|
// stream, which contains the contents of /prod/self/maps, which contains
|
|
// the mapped memory regions and their access permissions.
|
|
class MinidumpLinuxMapsList : public MinidumpStream {
|
|
public:
|
|
virtual ~MinidumpLinuxMapsList();
|
|
|
|
// Get number of mappings.
|
|
unsigned int get_maps_count() const { return valid_ ? maps_count_ : 0; }
|
|
|
|
// Get mapping at the given memory address. The caller owns the pointer.
|
|
const MinidumpLinuxMaps *GetLinuxMapsForAddress(uint64_t address) const;
|
|
// Get mapping at the given index. The caller owns the pointer.
|
|
const MinidumpLinuxMaps *GetLinuxMapsAtIndex(unsigned int index) const;
|
|
|
|
// Print the contents of /proc/self/maps to stdout.
|
|
void Print() const;
|
|
|
|
private:
|
|
friend class Minidump;
|
|
|
|
typedef vector<MinidumpLinuxMaps *> MinidumpLinuxMappings;
|
|
|
|
static const uint32_t kStreamType = MD_LINUX_MAPS;
|
|
|
|
// The caller owns the pointer.
|
|
explicit MinidumpLinuxMapsList(Minidump *minidump);
|
|
|
|
// Read and load the contents of the process mapping data.
|
|
// The stream should have data in the form of /proc/self/maps.
|
|
// This method returns whether the stream was read successfully.
|
|
bool Read(uint32_t expected_size) override;
|
|
|
|
// The list of individual mappings.
|
|
MinidumpLinuxMappings *maps_;
|
|
// The number of mappings.
|
|
uint32_t maps_count_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(MinidumpLinuxMapsList);
|
|
};
|
|
|
|
// MinidumpCrashpadInfo wraps MDRawCrashpadInfo, which is an optional stream in
|
|
// a minidump that provides additional information about the process state
|
|
// at the time the minidump was generated.
|
|
class MinidumpCrashpadInfo : public MinidumpStream {
|
|
public:
|
|
const MDRawCrashpadInfo* crashpad_info() const {
|
|
return valid_ ? &crashpad_info_ : NULL;
|
|
}
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
private:
|
|
friend class Minidump;
|
|
|
|
static const uint32_t kStreamType = MD_CRASHPAD_INFO_STREAM;
|
|
|
|
explicit MinidumpCrashpadInfo(Minidump* minidump_);
|
|
|
|
bool Read(uint32_t expected_size);
|
|
|
|
MDRawCrashpadInfo crashpad_info_;
|
|
std::vector<uint32_t> module_crashpad_info_links_;
|
|
std::vector<MDRawModuleCrashpadInfo> module_crashpad_info_;
|
|
std::vector<std::vector<std::string>> module_crashpad_info_list_annotations_;
|
|
std::vector<std::map<std::string, std::string>>
|
|
module_crashpad_info_simple_annotations_;
|
|
std::map<std::string, std::string> simple_annotations_;
|
|
};
|
|
|
|
|
|
// Minidump is the user's interface to a minidump file. It wraps MDRawHeader
|
|
// and provides access to the minidump's top-level stream directory.
|
|
class Minidump {
|
|
public:
|
|
// path is the pathname of a file containing the minidump.
|
|
explicit Minidump(const string& path,
|
|
bool hexdump=false,
|
|
unsigned int hexdump_width=16);
|
|
// input is an istream wrapping minidump data. Minidump holds a
|
|
// weak pointer to input, and the caller must ensure that the stream
|
|
// is valid as long as the Minidump object is.
|
|
explicit Minidump(std::istream& input);
|
|
|
|
virtual ~Minidump();
|
|
|
|
// path may be empty if the minidump was not opened from a file
|
|
virtual string path() const {
|
|
return path_;
|
|
}
|
|
static void set_max_streams(uint32_t max_streams) {
|
|
max_streams_ = max_streams;
|
|
}
|
|
static uint32_t max_streams() { return max_streams_; }
|
|
|
|
static void set_max_string_length(uint32_t max_string_length) {
|
|
max_string_length_ = max_string_length;
|
|
}
|
|
static uint32_t max_string_length() { return max_string_length_; }
|
|
|
|
virtual const MDRawHeader* header() const { return valid_ ? &header_ : NULL; }
|
|
|
|
// Reads the CPU information from the system info stream and generates the
|
|
// appropriate CPU flags. The returned context_cpu_flags are the same as
|
|
// if the CPU type bits were set in the context_flags of a context record.
|
|
// On success, context_cpu_flags will have the flags that identify the CPU.
|
|
// If a system info stream is missing, context_cpu_flags will be 0.
|
|
// Returns true if the current position in the stream was not changed.
|
|
// Returns false when the current location in the stream was changed and the
|
|
// attempt to restore the original position failed.
|
|
bool GetContextCPUFlagsFromSystemInfo(uint32_t* context_cpu_flags);
|
|
|
|
// Reads the minidump file's header and top-level stream directory.
|
|
// The minidump is expected to be positioned at the beginning of the
|
|
// header. Read() sets up the stream list and map, and validates the
|
|
// Minidump object.
|
|
virtual bool Read();
|
|
|
|
// The next set of methods are stubs that call GetStream. They exist to
|
|
// force code generation of the templatized API within the module, and
|
|
// to avoid exposing an ugly API (GetStream needs to accept a garbage
|
|
// parameter).
|
|
virtual MinidumpThreadList* GetThreadList();
|
|
virtual MinidumpModuleList* GetModuleList();
|
|
virtual MinidumpMemoryList* GetMemoryList();
|
|
virtual MinidumpException* GetException();
|
|
virtual MinidumpAssertion* GetAssertion();
|
|
virtual MinidumpSystemInfo* GetSystemInfo();
|
|
virtual MinidumpUnloadedModuleList* GetUnloadedModuleList();
|
|
virtual MinidumpMiscInfo* GetMiscInfo();
|
|
virtual MinidumpBreakpadInfo* GetBreakpadInfo();
|
|
virtual MinidumpMemoryInfoList* GetMemoryInfoList();
|
|
MinidumpCrashpadInfo* GetCrashpadInfo();
|
|
|
|
// The next method also calls GetStream, but is exclusive for Linux dumps.
|
|
virtual MinidumpLinuxMapsList *GetLinuxMapsList();
|
|
|
|
// The next set of methods are provided for users who wish to access
|
|
// data in minidump files directly, while leveraging the rest of
|
|
// this class and related classes to handle the basic minidump
|
|
// structure and known stream types.
|
|
|
|
unsigned int GetDirectoryEntryCount() const {
|
|
return valid_ ? header_.stream_count : 0;
|
|
}
|
|
const MDRawDirectory* GetDirectoryEntryAtIndex(unsigned int index) const;
|
|
|
|
// The next 2 methods are lower-level I/O routines. They use fd_.
|
|
|
|
// Reads count bytes from the minidump at the current position into
|
|
// the storage area pointed to by bytes. bytes must be of sufficient
|
|
// size. After the read, the file position is advanced by count.
|
|
bool ReadBytes(void* bytes, size_t count);
|
|
|
|
// Sets the position of the minidump file to offset.
|
|
bool SeekSet(off_t offset);
|
|
|
|
// Returns the current position of the minidump file.
|
|
off_t Tell();
|
|
|
|
// Medium-level I/O routines.
|
|
|
|
// ReadString returns a string which is owned by the caller! offset
|
|
// specifies the offset that a length-encoded string is stored at in the
|
|
// minidump file.
|
|
string* ReadString(off_t offset);
|
|
|
|
bool ReadUTF8String(off_t offset, string* string_utf8);
|
|
|
|
bool ReadStringList(off_t offset, std::vector<std::string>* string_list);
|
|
|
|
bool ReadSimpleStringDictionary(
|
|
off_t offset,
|
|
std::map<std::string, std::string>* simple_string_dictionary);
|
|
|
|
// SeekToStreamType positions the file at the beginning of a stream
|
|
// identified by stream_type, and informs the caller of the stream's
|
|
// length by setting *stream_length. Because stream_map maps each stream
|
|
// type to only one stream in the file, this might mislead the user into
|
|
// thinking that the stream that this seeks to is the only stream with
|
|
// type stream_type. That can't happen for streams that these classes
|
|
// deal with directly, because they're only supposed to be present in the
|
|
// file singly, and that's verified when stream_map_ is built. Users who
|
|
// are looking for other stream types should be aware of this
|
|
// possibility, and consider using GetDirectoryEntryAtIndex (possibly
|
|
// with GetDirectoryEntryCount) if expecting multiple streams of the same
|
|
// type in a single minidump file.
|
|
bool SeekToStreamType(uint32_t stream_type, uint32_t* stream_length);
|
|
|
|
bool swap() const { return valid_ ? swap_ : false; }
|
|
|
|
bool is_big_endian() const { return valid_ ? is_big_endian_ : false; }
|
|
|
|
// Print a human-readable representation of the object to stdout.
|
|
void Print();
|
|
|
|
// Is the OS Android.
|
|
bool IsAndroid();
|
|
|
|
// Determines the platform where the minidump was produced. |platform| is
|
|
// valid iff this method returns true.
|
|
bool GetPlatform(MDOSPlatform* platform);
|
|
|
|
// Get current hexdump display settings.
|
|
unsigned int HexdumpMode() const { return hexdump_ ? hexdump_width_ : 0; }
|
|
|
|
private:
|
|
// MinidumpStreamInfo is used in the MinidumpStreamMap. It lets
|
|
// the Minidump object locate interesting streams quickly, and
|
|
// provides a convenient place to stash MinidumpStream objects.
|
|
struct MinidumpStreamInfo {
|
|
MinidumpStreamInfo() : stream_index(0), stream(NULL) {}
|
|
~MinidumpStreamInfo() { delete stream; }
|
|
|
|
// Index into the MinidumpDirectoryEntries vector
|
|
unsigned int stream_index;
|
|
|
|
// Pointer to the stream if cached, or NULL if not yet populated
|
|
MinidumpStream* stream;
|
|
};
|
|
|
|
typedef vector<MDRawDirectory> MinidumpDirectoryEntries;
|
|
typedef map<uint32_t, MinidumpStreamInfo> MinidumpStreamMap;
|
|
|
|
template<typename T> T* GetStream(T** stream);
|
|
|
|
// Opens the minidump file, or if already open, seeks to the beginning.
|
|
bool Open();
|
|
|
|
// The largest number of top-level streams that will be read from a minidump.
|
|
// Note that streams are only read (and only consume memory) as needed,
|
|
// when directed by the caller. The default is 128.
|
|
static uint32_t max_streams_;
|
|
|
|
// The maximum length of a UTF-16 string that will be read from a minidump
|
|
// in 16-bit words. The default is 1024. UTF-16 strings are converted
|
|
// to UTF-8 when stored in memory, and each UTF-16 word will be represented
|
|
// by as many as 3 bytes in UTF-8.
|
|
static unsigned int max_string_length_;
|
|
|
|
MDRawHeader header_;
|
|
|
|
// The list of streams.
|
|
MinidumpDirectoryEntries* directory_;
|
|
|
|
// Access to streams using the stream type as the key.
|
|
MinidumpStreamMap* stream_map_;
|
|
|
|
// The pathname of the minidump file to process, set in the constructor.
|
|
// This may be empty if the minidump was opened directly from a stream.
|
|
const string path_;
|
|
|
|
// The stream for all file I/O. Used by ReadBytes and SeekSet.
|
|
// Set based on the path in Open, or directly in the constructor.
|
|
std::istream* stream_;
|
|
|
|
// swap_ is true if the minidump file should be byte-swapped. If the
|
|
// minidump was produced by a CPU that is other-endian than the CPU
|
|
// processing the minidump, this will be true. If the two CPUs are
|
|
// same-endian, this will be false.
|
|
bool swap_;
|
|
|
|
// true if the minidump was produced by a big-endian cpu.
|
|
bool is_big_endian_;
|
|
|
|
// Validity of the Minidump structure, false immediately after
|
|
// construction or after a failed Read(); true following a successful
|
|
// Read().
|
|
bool valid_;
|
|
|
|
// Knobs for controlling display of memory printing.
|
|
bool hexdump_;
|
|
unsigned int hexdump_width_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(Minidump);
|
|
};
|
|
|
|
|
|
} // namespace google_breakpad
|
|
|
|
|
|
#endif // GOOGLE_BREAKPAD_PROCESSOR_MINIDUMP_H__
|