mirror of
https://git.suyu.dev/suyu/breakpad.git
synced 2026-01-05 05:58:24 +01:00
Microdump processing implementation
According to design document: http://goo.gl/B3wIRN This is an initial implementation version, support ARM architecture only. BUG=chromium:410294 R=primiano@chromium.org Review URL: https://breakpad.appspot.com/5714003 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1403 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
e469f8cf4b
commit
6354cffeb0
12 changed files with 1091 additions and 30 deletions
262
src/processor/microdump.cc
Normal file
262
src/processor/microdump.cc
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
// Copyright (c) 2014 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.
|
||||
|
||||
// microdump.cc: A microdump reader.
|
||||
//
|
||||
// See microdump.h for documentation.
|
||||
|
||||
#include "google_breakpad/processor/microdump.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "google_breakpad/common/minidump_cpu_arm.h"
|
||||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "processor/basic_code_module.h"
|
||||
#include "processor/linked_ptr.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/range_map-inl.h"
|
||||
|
||||
namespace {
|
||||
static const char kGoogleBreakpadKey[] = "/google-breakpad(";
|
||||
static const char kMicrodumpBegin[] = "-----BEGIN BREAKPAD MICRODUMP-----";
|
||||
static const char kMicrodumpEnd[] = "-----END BREAKPAD MICRODUMP-----";
|
||||
static const char kOsKey[] = ": O ";
|
||||
static const char kCpuKey[] = ": C ";
|
||||
static const char kMmapKey[] = ": M ";
|
||||
static const char kStackKey[] = ": S ";
|
||||
static const char kStackFirstLineKey[] = ": S 0 ";
|
||||
static const char kArmArchitecture[] = "armv7l";
|
||||
|
||||
template<typename T>
|
||||
T HexStrToL(const string& str) {
|
||||
uint64_t res = 0;
|
||||
std::istringstream ss(str);
|
||||
ss >> std::hex >> res;
|
||||
return static_cast<T>(res);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ParseHexBuf(const string& str) {
|
||||
std::vector<uint8_t> buf;
|
||||
for (size_t i = 0; i < str.length(); i += 2) {
|
||||
buf.push_back(HexStrToL<uint8_t>(str.substr(i, 2)));
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
//
|
||||
// MicrodumpModules
|
||||
//
|
||||
|
||||
void MicrodumpModules::Add(const CodeModule* module) {
|
||||
linked_ptr<const CodeModule> module_ptr(module);
|
||||
if (!map_->StoreRange(module->base_address(), module->size(), module_ptr)) {
|
||||
BPLOG(ERROR) << "Module " << module->code_file() <<
|
||||
" could not be stored";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MicrodumpContext
|
||||
//
|
||||
|
||||
void MicrodumpContext::SetContextARM(MDRawContextARM* arm) {
|
||||
DumpContext::SetContextFlags(MD_CONTEXT_ARM);
|
||||
DumpContext::SetContextARM(arm);
|
||||
valid_ = true;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MicrodumpMemoryRegion
|
||||
//
|
||||
|
||||
MicrodumpMemoryRegion::MicrodumpMemoryRegion() : base_address_(0) { }
|
||||
|
||||
void MicrodumpMemoryRegion::Init(uint64_t base_address,
|
||||
const std::vector<uint8_t>& contents) {
|
||||
base_address_ = base_address;
|
||||
contents_ = contents;
|
||||
}
|
||||
|
||||
uint64_t MicrodumpMemoryRegion::GetBase() const { return base_address_; }
|
||||
|
||||
uint32_t MicrodumpMemoryRegion::GetSize() const { return contents_.size(); }
|
||||
|
||||
bool MicrodumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
|
||||
uint8_t* value) const {
|
||||
return GetMemoryLittleEndian(address, value);
|
||||
}
|
||||
|
||||
bool MicrodumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
|
||||
uint16_t* value) const {
|
||||
return GetMemoryLittleEndian(address, value);
|
||||
}
|
||||
|
||||
bool MicrodumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
|
||||
uint32_t* value) const {
|
||||
return GetMemoryLittleEndian(address, value);
|
||||
}
|
||||
|
||||
bool MicrodumpMemoryRegion::GetMemoryAtAddress(uint64_t address,
|
||||
uint64_t* value) const {
|
||||
return GetMemoryLittleEndian(address, value);
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
bool MicrodumpMemoryRegion::GetMemoryLittleEndian(uint64_t address,
|
||||
ValueType* value) const {
|
||||
if (address < base_address_ ||
|
||||
address - base_address_ + sizeof(ValueType) > contents_.size())
|
||||
return false;
|
||||
ValueType v = 0;
|
||||
uint64_t start = address - base_address_;
|
||||
// The loop condition is odd, but it's correct for size_t.
|
||||
for (size_t i = sizeof(ValueType) - 1; i < sizeof(ValueType); i--)
|
||||
v = (v << 8) | static_cast<uint8_t>(contents_[start + i]);
|
||||
*value = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MicrodumpMemoryRegion::Print() const {
|
||||
// Not reached, just needed to honor the base class contract.
|
||||
assert(false);
|
||||
}
|
||||
|
||||
//
|
||||
// Microdump
|
||||
//
|
||||
Microdump::Microdump(const string& contents)
|
||||
: context_(new MicrodumpContext()),
|
||||
stack_region_(new MicrodumpMemoryRegion()),
|
||||
modules_(new MicrodumpModules()) {
|
||||
assert(!contents.empty());
|
||||
|
||||
bool in_microdump = false;
|
||||
string line;
|
||||
uint64_t stack_start = 0;
|
||||
std::vector<uint8_t> stack_content;
|
||||
string arch;
|
||||
|
||||
std::istringstream stream(contents);
|
||||
while (std::getline(stream, line)) {
|
||||
if (line.find(kGoogleBreakpadKey) == string::npos) {
|
||||
continue;
|
||||
}
|
||||
if (line.find(kMicrodumpBegin) != string::npos) {
|
||||
in_microdump = true;
|
||||
continue;
|
||||
}
|
||||
if (line.find(kMicrodumpEnd) != string::npos) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!in_microdump) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t pos;
|
||||
if ((pos = line.find(kOsKey)) != string::npos) {
|
||||
string os_str(line, pos + strlen(kOsKey));
|
||||
std::istringstream os_tokens(os_str);
|
||||
string unused_id;
|
||||
os_tokens >> unused_id;
|
||||
os_tokens >> arch;
|
||||
arch = arch.substr(1, arch.length() - 2); // remove quotes
|
||||
// OS line also contains release and version for future use.
|
||||
} else if ((pos = line.find(kStackKey)) != string::npos) {
|
||||
if (line.find(kStackFirstLineKey) != string::npos) {
|
||||
// The first line of the stack (S 0 stack header) provides the value of
|
||||
// the stack pointer, the start address of the stack being dumped and
|
||||
// the length of the stack. We could use it in future to double check
|
||||
// that we received all the stack as expected.
|
||||
continue;
|
||||
}
|
||||
string stack_str(line, pos + strlen(kStackKey));
|
||||
std::istringstream stack_tokens(stack_str);
|
||||
string start_addr_str;
|
||||
string raw_content;
|
||||
stack_tokens >> start_addr_str;
|
||||
stack_tokens >> raw_content;
|
||||
uint64_t start_addr = HexStrToL<uint64_t>(start_addr_str);
|
||||
|
||||
if (stack_start != 0) {
|
||||
// Verify that the stack chunks in the microdump are contiguous.
|
||||
assert(start_addr == stack_start + stack_content.size());
|
||||
} else {
|
||||
stack_start = start_addr;
|
||||
}
|
||||
std::vector<uint8_t> chunk = ParseHexBuf(raw_content);
|
||||
stack_content.insert(stack_content.end(), chunk.begin(), chunk.end());
|
||||
|
||||
} else if ((pos = line.find(kCpuKey)) != string::npos) {
|
||||
string cpu_state_str(line, pos + strlen(kCpuKey));
|
||||
std::vector<uint8_t> cpu_state_raw = ParseHexBuf(cpu_state_str);
|
||||
if (strcmp(arch.c_str(), kArmArchitecture) == 0) {
|
||||
MDRawContextARM* arm = new MDRawContextARM();
|
||||
memcpy(arm, &cpu_state_raw[0], cpu_state_raw.size());
|
||||
context_->SetContextARM(arm);
|
||||
} else {
|
||||
std::cerr << "Unsupported architecture: " << arch << std::endl;
|
||||
}
|
||||
} else if ((pos = line.find(kMmapKey)) != string::npos) {
|
||||
string mmap_line(line, pos + strlen(kMmapKey));
|
||||
std::istringstream mmap_tokens(mmap_line);
|
||||
string addr, offset, size, identifier, filename;
|
||||
mmap_tokens >> addr;
|
||||
mmap_tokens >> offset;
|
||||
mmap_tokens >> size;
|
||||
mmap_tokens >> identifier;
|
||||
mmap_tokens >> filename;
|
||||
|
||||
modules_->Add(new BasicCodeModule(
|
||||
HexStrToL<uint64_t>(addr), // base_address
|
||||
HexStrToL<uint64_t>(size), // size
|
||||
filename, // code_file
|
||||
identifier, // code_identifier
|
||||
filename, // debug_file
|
||||
identifier, // debug_identifier
|
||||
"")); // version
|
||||
}
|
||||
}
|
||||
stack_region_->Init(stack_start, stack_content);
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue