mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-12-23 06:05:44 +00:00
Add serialization of inlines and inline origins for FastSourceLineResolver so that it can construct inlined frames later.
Bug: 1190878 Change-Id: Ie3b0f2f44e04e790501ea54680fe223974c750ab Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3294126 Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
c472afe064
commit
0ae29c99d1
|
@ -79,6 +79,8 @@ class FastSourceLineResolver : public SourceLineResolverBase {
|
||||||
// SourceLineResolverBase.
|
// SourceLineResolverBase.
|
||||||
struct Line;
|
struct Line;
|
||||||
struct Function;
|
struct Function;
|
||||||
|
struct Inline;
|
||||||
|
struct InlineOrigin;
|
||||||
struct PublicSymbol;
|
struct PublicSymbol;
|
||||||
class Module;
|
class Module;
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,8 @@
|
||||||
#include "processor/module_factory.h"
|
#include "processor/module_factory.h"
|
||||||
#include "processor/simple_serializer-inl.h"
|
#include "processor/simple_serializer-inl.h"
|
||||||
|
|
||||||
using std::map;
|
using std::deque;
|
||||||
using std::make_pair;
|
using std::unique_ptr;
|
||||||
using std::vector;
|
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
@ -101,6 +100,10 @@ void FastSourceLineResolver::Module::LookupAddress(
|
||||||
frame->source_line = line->line;
|
frame->source_line = line->line;
|
||||||
frame->source_line_base = frame->module->base_address() + line_base;
|
frame->source_line_base = frame->module->base_address() + line_base;
|
||||||
}
|
}
|
||||||
|
// Check if this is inlined function call.
|
||||||
|
if (inlined_frames) {
|
||||||
|
ConstructInlineFrames(frame, address, func->inlines, inlined_frames);
|
||||||
|
}
|
||||||
} else if (public_symbols_.Retrieve(address,
|
} else if (public_symbols_.Retrieve(address,
|
||||||
public_symbol_ptr, &public_address) &&
|
public_symbol_ptr, &public_address) &&
|
||||||
(!func_ptr || public_address > function_base)) {
|
(!func_ptr || public_address > function_base)) {
|
||||||
|
@ -110,6 +113,68 @@ void FastSourceLineResolver::Module::LookupAddress(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FastSourceLineResolver::Module::ConstructInlineFrames(
|
||||||
|
StackFrame* frame,
|
||||||
|
MemAddr address,
|
||||||
|
const StaticContainedRangeMap<MemAddr, char>& inline_map,
|
||||||
|
std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const {
|
||||||
|
std::vector<const char*> inline_ptrs;
|
||||||
|
if (!inline_map.RetrieveRanges(address, inline_ptrs)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const char* inline_ptr : inline_ptrs) {
|
||||||
|
scoped_ptr<Inline> in(new Inline);
|
||||||
|
in.get()->CopyFrom(inline_ptr);
|
||||||
|
unique_ptr<StackFrame> new_frame =
|
||||||
|
unique_ptr<StackFrame>(new StackFrame(*frame));
|
||||||
|
auto origin_iter = inline_origins_.find(in->origin_id);
|
||||||
|
if (origin_iter != inline_origins_.end()) {
|
||||||
|
scoped_ptr<InlineOrigin> origin(new InlineOrigin);
|
||||||
|
origin.get()->CopyFrom(origin_iter.GetValuePtr());
|
||||||
|
new_frame->function_name = origin->name;
|
||||||
|
} else {
|
||||||
|
new_frame->function_name = "<name omitted>";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store call site file and line in current frame, which will be updated
|
||||||
|
// later.
|
||||||
|
new_frame->source_line = in->call_site_line;
|
||||||
|
if (in->has_call_site_file_id) {
|
||||||
|
auto file_iter = files_.find(in->call_site_file_id);
|
||||||
|
if (file_iter != files_.end()) {
|
||||||
|
new_frame->source_file_name = file_iter.GetValuePtr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the starting adress of the inlined range as inlined function base.
|
||||||
|
new_frame->function_base = new_frame->module->base_address();
|
||||||
|
for (const auto& range : in->inline_ranges) {
|
||||||
|
if (address >= range.first && address < range.first + range.second) {
|
||||||
|
new_frame->function_base += range.first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_frame->trust = StackFrame::FRAME_TRUST_INLINE;
|
||||||
|
|
||||||
|
// The inlines vector has an order from innermost entry to outermost entry.
|
||||||
|
// By push_back, we will have inlined_frames with the same order.
|
||||||
|
inlined_frames->push_back(std::move(new_frame));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the source file and source line for each inlined frame.
|
||||||
|
if (!inlined_frames->empty()) {
|
||||||
|
string parent_frame_source_file_name = frame->source_file_name;
|
||||||
|
int parent_frame_source_line = frame->source_line;
|
||||||
|
frame->source_file_name = inlined_frames->back()->source_file_name;
|
||||||
|
frame->source_line = inlined_frames->back()->source_line;
|
||||||
|
for (unique_ptr<StackFrame>& inlined_frame : *inlined_frames) {
|
||||||
|
std::swap(inlined_frame->source_file_name, parent_frame_source_file_name);
|
||||||
|
std::swap(inlined_frame->source_line, parent_frame_source_line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// WFI: WindowsFrameInfo.
|
// WFI: WindowsFrameInfo.
|
||||||
// Returns a WFI object reading from a raw memory chunk of data
|
// Returns a WFI object reading from a raw memory chunk of data
|
||||||
WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char* raw) {
|
WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char* raw) {
|
||||||
|
@ -184,7 +249,7 @@ bool FastSourceLineResolver::Module::LoadMapFromMemory(
|
||||||
cfi_initial_rules_ =
|
cfi_initial_rules_ =
|
||||||
StaticRangeMap<MemAddr, char>(mem_buffer + offsets[map_id++]);
|
StaticRangeMap<MemAddr, char>(mem_buffer + offsets[map_id++]);
|
||||||
cfi_delta_rules_ = StaticMap<MemAddr, char>(mem_buffer + offsets[map_id++]);
|
cfi_delta_rules_ = StaticMap<MemAddr, char>(mem_buffer + offsets[map_id++]);
|
||||||
|
inline_origins_ = StaticMap<int, char>(mem_buffer + offsets[map_id++]);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#ifndef PROCESSOR_FAST_SOURCE_LINE_RESOLVER_TYPES_H__
|
#ifndef PROCESSOR_FAST_SOURCE_LINE_RESOLVER_TYPES_H__
|
||||||
#define PROCESSOR_FAST_SOURCE_LINE_RESOLVER_TYPES_H__
|
#define PROCESSOR_FAST_SOURCE_LINE_RESOLVER_TYPES_H__
|
||||||
|
|
||||||
|
#include "contained_range_map.h"
|
||||||
#include "google_breakpad/processor/fast_source_line_resolver.h"
|
#include "google_breakpad/processor/fast_source_line_resolver.h"
|
||||||
#include "processor/source_line_resolver_base_types.h"
|
#include "processor/source_line_resolver_base_types.h"
|
||||||
|
|
||||||
|
@ -53,6 +54,10 @@
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
#define DESERIALIZE(raw_ptr, field) \
|
||||||
|
field = *(reinterpret_cast<const decltype(field)*>(raw_ptr)); \
|
||||||
|
raw_ptr += sizeof(field);
|
||||||
|
|
||||||
struct FastSourceLineResolver::Line : public SourceLineResolverBase::Line {
|
struct FastSourceLineResolver::Line : public SourceLineResolverBase::Line {
|
||||||
void CopyFrom(const Line* line_ptr) {
|
void CopyFrom(const Line* line_ptr) {
|
||||||
const char* raw = reinterpret_cast<const char*>(line_ptr);
|
const char* raw = reinterpret_cast<const char*>(line_ptr);
|
||||||
|
@ -61,12 +66,10 @@ struct FastSourceLineResolver::Line : public SourceLineResolverBase::Line {
|
||||||
|
|
||||||
// De-serialize the memory data of a Line.
|
// De-serialize the memory data of a Line.
|
||||||
void CopyFrom(const char* raw) {
|
void CopyFrom(const char* raw) {
|
||||||
address = *(reinterpret_cast<const MemAddr*>(raw));
|
DESERIALIZE(raw, address);
|
||||||
size = *(reinterpret_cast<const MemAddr*>(raw + sizeof(address)));
|
DESERIALIZE(raw, size);
|
||||||
source_file_id = *(reinterpret_cast<const int32_t*>(
|
DESERIALIZE(raw, source_file_id);
|
||||||
raw + 2 * sizeof(address)));
|
DESERIALIZE(raw, line);
|
||||||
line = *(reinterpret_cast<const int32_t*>(
|
|
||||||
raw + 2 * sizeof(address) + sizeof(source_file_id)));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -81,18 +84,60 @@ public SourceLineResolverBase::Function {
|
||||||
void CopyFrom(const char* raw) {
|
void CopyFrom(const char* raw) {
|
||||||
size_t name_size = strlen(raw) + 1;
|
size_t name_size = strlen(raw) + 1;
|
||||||
name = raw;
|
name = raw;
|
||||||
address = *(reinterpret_cast<const MemAddr*>(raw + name_size));
|
raw += name_size;
|
||||||
size = *(reinterpret_cast<const MemAddr*>(
|
DESERIALIZE(raw, address);
|
||||||
raw + name_size + sizeof(MemAddr)));
|
DESERIALIZE(raw, size);
|
||||||
parameter_size = *(reinterpret_cast<const int32_t*>(
|
DESERIALIZE(raw, parameter_size);
|
||||||
raw + name_size + 2 * sizeof(MemAddr)));
|
DESERIALIZE(raw, is_multiple);
|
||||||
lines = StaticRangeMap<MemAddr, Line>(
|
int32_t inline_size;
|
||||||
raw + name_size + 2 * sizeof(MemAddr) + sizeof(int32_t));
|
DESERIALIZE(raw, inline_size);
|
||||||
|
inlines = StaticContainedRangeMap<MemAddr, char>(raw);
|
||||||
|
lines = StaticRangeMap<MemAddr, Line>(raw + inline_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StaticContainedRangeMap<MemAddr, char> inlines;
|
||||||
StaticRangeMap<MemAddr, Line> lines;
|
StaticRangeMap<MemAddr, Line> lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct FastSourceLineResolver::Inline : public SourceLineResolverBase::Inline {
|
||||||
|
void CopyFrom(const Inline* inline_ptr) {
|
||||||
|
const char* raw = reinterpret_cast<const char*>(inline_ptr);
|
||||||
|
CopyFrom(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// De-serialize the memory data of a Inline.
|
||||||
|
void CopyFrom(const char* raw) {
|
||||||
|
DESERIALIZE(raw, has_call_site_file_id);
|
||||||
|
DESERIALIZE(raw, inline_nest_level);
|
||||||
|
DESERIALIZE(raw, call_site_line);
|
||||||
|
DESERIALIZE(raw, call_site_file_id);
|
||||||
|
DESERIALIZE(raw, origin_id);
|
||||||
|
uint32_t inline_range_size;
|
||||||
|
DESERIALIZE(raw, inline_range_size);
|
||||||
|
for (size_t i = 0; i < inline_range_size; i += 2) {
|
||||||
|
std::pair<MemAddr, MemAddr> range;
|
||||||
|
DESERIALIZE(raw, range.first);
|
||||||
|
DESERIALIZE(raw, range.second);
|
||||||
|
inline_ranges.push_back(range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FastSourceLineResolver::InlineOrigin
|
||||||
|
: public SourceLineResolverBase::InlineOrigin {
|
||||||
|
void CopyFrom(const InlineOrigin* origin_ptr) {
|
||||||
|
const char* raw = reinterpret_cast<const char*>(origin_ptr);
|
||||||
|
CopyFrom(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
// De-serialize the memory data of a Line.
|
||||||
|
void CopyFrom(const char* raw) {
|
||||||
|
DESERIALIZE(raw, has_file_id);
|
||||||
|
DESERIALIZE(raw, source_file_id);
|
||||||
|
name = raw;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct FastSourceLineResolver::PublicSymbol :
|
struct FastSourceLineResolver::PublicSymbol :
|
||||||
public SourceLineResolverBase::PublicSymbol {
|
public SourceLineResolverBase::PublicSymbol {
|
||||||
void CopyFrom(const PublicSymbol* public_symbol_ptr) {
|
void CopyFrom(const PublicSymbol* public_symbol_ptr) {
|
||||||
|
@ -104,12 +149,15 @@ public SourceLineResolverBase::PublicSymbol {
|
||||||
void CopyFrom(const char* raw) {
|
void CopyFrom(const char* raw) {
|
||||||
size_t name_size = strlen(raw) + 1;
|
size_t name_size = strlen(raw) + 1;
|
||||||
name = raw;
|
name = raw;
|
||||||
address = *(reinterpret_cast<const MemAddr*>(raw + name_size));
|
raw += name_size;
|
||||||
parameter_size = *(reinterpret_cast<const int32_t*>(
|
DESERIALIZE(raw, address);
|
||||||
raw + name_size + sizeof(MemAddr)));
|
DESERIALIZE(raw, parameter_size);
|
||||||
|
DESERIALIZE(raw, is_multiple);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#undef DESERIALIZE
|
||||||
|
|
||||||
class FastSourceLineResolver::Module: public SourceLineResolverBase::Module {
|
class FastSourceLineResolver::Module: public SourceLineResolverBase::Module {
|
||||||
public:
|
public:
|
||||||
explicit Module(const string& name) : name_(name), is_corrupt_(false) { }
|
explicit Module(const string& name) : name_(name), is_corrupt_(false) { }
|
||||||
|
@ -121,6 +169,16 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module {
|
||||||
StackFrame* frame,
|
StackFrame* frame,
|
||||||
std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const;
|
std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const;
|
||||||
|
|
||||||
|
// Construct inlined frames for |frame| and store them in |inline_frames|.
|
||||||
|
// |frame|'s source line and source file name may be updated if an inlined
|
||||||
|
// frame is found inside |frame|. As a result, the innermost inlined frame
|
||||||
|
// will be the first one in |inline_frames|.
|
||||||
|
virtual void ConstructInlineFrames(
|
||||||
|
StackFrame* frame,
|
||||||
|
MemAddr address,
|
||||||
|
const StaticContainedRangeMap<MemAddr, char>& inline_map,
|
||||||
|
std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const;
|
||||||
|
|
||||||
// Loads a map from the given buffer in char* type.
|
// Loads a map from the given buffer in char* type.
|
||||||
virtual bool LoadMapFromMemory(char* memory_buffer,
|
virtual bool LoadMapFromMemory(char* memory_buffer,
|
||||||
size_t memory_buffer_size);
|
size_t memory_buffer_size);
|
||||||
|
@ -143,7 +201,7 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module {
|
||||||
virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame) const;
|
virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame) const;
|
||||||
|
|
||||||
// Number of serialized map components of Module.
|
// Number of serialized map components of Module.
|
||||||
static const int kNumberMaps_ = 5 + WindowsFrameInfo::STACK_INFO_LAST;
|
static const int kNumberMaps_ = 6 + WindowsFrameInfo::STACK_INFO_LAST;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class FastSourceLineResolver;
|
friend class FastSourceLineResolver;
|
||||||
|
@ -180,6 +238,10 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module {
|
||||||
// this map, or the end of the range as given by the cfi_initial_rules_
|
// this map, or the end of the range as given by the cfi_initial_rules_
|
||||||
// entry (which FindCFIFrameInfo looks up first).
|
// entry (which FindCFIFrameInfo looks up first).
|
||||||
StaticMap<MemAddr, char> cfi_delta_rules_;
|
StaticMap<MemAddr, char> cfi_delta_rules_;
|
||||||
|
|
||||||
|
// INLINE_ORIGIN records: used as a function name string pool for INLINE
|
||||||
|
// records.
|
||||||
|
StaticMap<int, char> inline_origins_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -408,6 +408,108 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
|
||||||
ASSERT_EQ(frame.function_name, "Public2_2");
|
ASSERT_EQ(frame.function_name, "Public2_2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test adapted from basic_source_line_resolver_unittest.
|
||||||
|
TEST_F(TestFastSourceLineResolver, TestLoadAndResolveOldInlines) {
|
||||||
|
TestCodeModule module("linux_inline");
|
||||||
|
ASSERT_TRUE(basic_resolver.LoadModule(
|
||||||
|
&module, testdata_dir +
|
||||||
|
"/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/"
|
||||||
|
"linux_inline.old.sym"));
|
||||||
|
ASSERT_TRUE(basic_resolver.HasModule(&module));
|
||||||
|
// Convert module1 to fast_module:
|
||||||
|
ASSERT_TRUE(serializer.ConvertOneModule(module.code_file(), &basic_resolver,
|
||||||
|
&fast_resolver));
|
||||||
|
ASSERT_TRUE(fast_resolver.HasModule(&module));
|
||||||
|
|
||||||
|
StackFrame frame;
|
||||||
|
std::deque<std::unique_ptr<StackFrame>> inlined_frames;
|
||||||
|
frame.instruction = 0x161b6;
|
||||||
|
frame.module = &module;
|
||||||
|
fast_resolver.FillSourceLineInfo(&frame, &inlined_frames);
|
||||||
|
|
||||||
|
// main frame.
|
||||||
|
ASSERT_EQ(frame.function_name, "main");
|
||||||
|
ASSERT_EQ(frame.function_base, 0x15b30U);
|
||||||
|
ASSERT_EQ(frame.source_file_name, "linux_inline.cpp");
|
||||||
|
ASSERT_EQ(frame.source_line, 42);
|
||||||
|
ASSERT_EQ(frame.source_line_base, 0x161b6U);
|
||||||
|
|
||||||
|
ASSERT_EQ(inlined_frames.size(), 3UL);
|
||||||
|
|
||||||
|
// Inlined frames inside main frame.
|
||||||
|
ASSERT_EQ(inlined_frames[2]->function_name, "foo()");
|
||||||
|
ASSERT_EQ(inlined_frames[2]->function_base, 0x15b45U);
|
||||||
|
ASSERT_EQ(inlined_frames[2]->source_file_name, "linux_inline.cpp");
|
||||||
|
ASSERT_EQ(inlined_frames[2]->source_line, 39);
|
||||||
|
ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U);
|
||||||
|
ASSERT_EQ(inlined_frames[2]->trust, StackFrame::FRAME_TRUST_INLINE);
|
||||||
|
|
||||||
|
ASSERT_EQ(inlined_frames[1]->function_name, "bar()");
|
||||||
|
ASSERT_EQ(inlined_frames[1]->function_base, 0x15b72U);
|
||||||
|
ASSERT_EQ(inlined_frames[1]->source_file_name, "linux_inline.cpp");
|
||||||
|
ASSERT_EQ(inlined_frames[1]->source_line, 32);
|
||||||
|
ASSERT_EQ(inlined_frames[1]->source_line_base, 0x161b6U);
|
||||||
|
ASSERT_EQ(inlined_frames[1]->trust, StackFrame::FRAME_TRUST_INLINE);
|
||||||
|
|
||||||
|
ASSERT_EQ(inlined_frames[0]->function_name, "func()");
|
||||||
|
ASSERT_EQ(inlined_frames[0]->function_base, 0x15b83U);
|
||||||
|
ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp");
|
||||||
|
ASSERT_EQ(inlined_frames[0]->source_line, 27);
|
||||||
|
ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U);
|
||||||
|
ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test adapted from basic_source_line_resolver_unittest.
|
||||||
|
TEST_F(TestFastSourceLineResolver, TestLoadAndResolveNewInlines) {
|
||||||
|
TestCodeModule module("linux_inline");
|
||||||
|
ASSERT_TRUE(basic_resolver.LoadModule(
|
||||||
|
&module, testdata_dir +
|
||||||
|
"/symbols/linux_inline/BBA6FA10B8AAB33D00000000000000000/"
|
||||||
|
"linux_inline.new.sym"));
|
||||||
|
ASSERT_TRUE(basic_resolver.HasModule(&module));
|
||||||
|
// Convert module1 to fast_module:
|
||||||
|
ASSERT_TRUE(serializer.ConvertOneModule(module.code_file(), &basic_resolver,
|
||||||
|
&fast_resolver));
|
||||||
|
ASSERT_TRUE(fast_resolver.HasModule(&module));
|
||||||
|
|
||||||
|
StackFrame frame;
|
||||||
|
std::deque<std::unique_ptr<StackFrame>> inlined_frames;
|
||||||
|
frame.instruction = 0x161b6;
|
||||||
|
frame.module = &module;
|
||||||
|
fast_resolver.FillSourceLineInfo(&frame, &inlined_frames);
|
||||||
|
|
||||||
|
// main frame.
|
||||||
|
ASSERT_EQ(frame.function_name, "main");
|
||||||
|
ASSERT_EQ(frame.function_base, 0x15b30U);
|
||||||
|
ASSERT_EQ(frame.source_file_name, "a.cpp");
|
||||||
|
ASSERT_EQ(frame.source_line, 42);
|
||||||
|
ASSERT_EQ(frame.source_line_base, 0x161b6U);
|
||||||
|
|
||||||
|
ASSERT_EQ(inlined_frames.size(), 3UL);
|
||||||
|
|
||||||
|
// Inlined frames inside main frame.
|
||||||
|
ASSERT_EQ(inlined_frames[2]->function_name, "foo()");
|
||||||
|
ASSERT_EQ(inlined_frames[2]->function_base, 0x15b45U);
|
||||||
|
ASSERT_EQ(inlined_frames[2]->source_file_name, "b.cpp");
|
||||||
|
ASSERT_EQ(inlined_frames[2]->source_line, 39);
|
||||||
|
ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U);
|
||||||
|
ASSERT_EQ(inlined_frames[2]->trust, StackFrame::FRAME_TRUST_INLINE);
|
||||||
|
|
||||||
|
ASSERT_EQ(inlined_frames[1]->function_name, "bar()");
|
||||||
|
ASSERT_EQ(inlined_frames[1]->function_base, 0x15b72U);
|
||||||
|
ASSERT_EQ(inlined_frames[1]->source_file_name, "c.cpp");
|
||||||
|
ASSERT_EQ(inlined_frames[1]->source_line, 32);
|
||||||
|
ASSERT_EQ(inlined_frames[1]->source_line_base, 0x161b6U);
|
||||||
|
ASSERT_EQ(inlined_frames[1]->trust, StackFrame::FRAME_TRUST_INLINE);
|
||||||
|
|
||||||
|
ASSERT_EQ(inlined_frames[0]->function_name, "func()");
|
||||||
|
ASSERT_EQ(inlined_frames[0]->function_base, 0x15b83U);
|
||||||
|
ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp");
|
||||||
|
ASSERT_EQ(inlined_frames[0]->source_line, 27);
|
||||||
|
ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U);
|
||||||
|
ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TestFastSourceLineResolver, TestInvalidLoads) {
|
TEST_F(TestFastSourceLineResolver, TestInvalidLoads) {
|
||||||
TestCodeModule module3("module3");
|
TestCodeModule module3("module3");
|
||||||
ASSERT_TRUE(basic_resolver.LoadModule(&module3,
|
ASSERT_TRUE(basic_resolver.LoadModule(&module3,
|
||||||
|
|
|
@ -43,10 +43,15 @@
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
// Definition of static member variable in SimplerSerializer<Funcion>, which
|
// Definition of static member variables in SimplerSerializer<Funcion> and
|
||||||
// is declared in file "simple_serializer-inl.h"
|
// SimplerSerializer<Inline>, which are declared in file
|
||||||
|
// "simple_serializer-inl.h"
|
||||||
RangeMapSerializer<MemAddr, linked_ptr<BasicSourceLineResolver::Line>>
|
RangeMapSerializer<MemAddr, linked_ptr<BasicSourceLineResolver::Line>>
|
||||||
SimpleSerializer<BasicSourceLineResolver::Function>::range_map_serializer_;
|
SimpleSerializer<BasicSourceLineResolver::Function>::range_map_serializer_;
|
||||||
|
ContainedRangeMapSerializer<MemAddr,
|
||||||
|
linked_ptr<BasicSourceLineResolver::Inline>>
|
||||||
|
SimpleSerializer<
|
||||||
|
BasicSourceLineResolver::Function>::inline_range_map_serializer_;
|
||||||
|
|
||||||
size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module& module) {
|
size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module& module) {
|
||||||
size_t total_size_alloc_ = 0;
|
size_t total_size_alloc_ = 0;
|
||||||
|
@ -66,6 +71,8 @@ size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module& module) {
|
||||||
module.cfi_initial_rules_);
|
module.cfi_initial_rules_);
|
||||||
map_sizes_[map_index++] = cfi_delta_rules_serializer_.SizeOf(
|
map_sizes_[map_index++] = cfi_delta_rules_serializer_.SizeOf(
|
||||||
module.cfi_delta_rules_);
|
module.cfi_delta_rules_);
|
||||||
|
map_sizes_[map_index++] =
|
||||||
|
inline_origin_serializer_.SizeOf(module.inline_origins_);
|
||||||
|
|
||||||
// Header size.
|
// Header size.
|
||||||
total_size_alloc_ += kNumberMaps_ * sizeof(uint32_t);
|
total_size_alloc_ += kNumberMaps_ * sizeof(uint32_t);
|
||||||
|
@ -95,6 +102,7 @@ char* ModuleSerializer::Write(const BasicSourceLineResolver::Module& module,
|
||||||
dest = wfi_serializer_.Write(&(module.windows_frame_info_[i]), dest);
|
dest = wfi_serializer_.Write(&(module.windows_frame_info_[i]), dest);
|
||||||
dest = cfi_init_rules_serializer_.Write(module.cfi_initial_rules_, dest);
|
dest = cfi_init_rules_serializer_.Write(module.cfi_initial_rules_, dest);
|
||||||
dest = cfi_delta_rules_serializer_.Write(module.cfi_delta_rules_, dest);
|
dest = cfi_delta_rules_serializer_.Write(module.cfi_delta_rules_, dest);
|
||||||
|
dest = inline_origin_serializer_.Write(module.inline_origins_, dest);
|
||||||
// Write a null terminator.
|
// Write a null terminator.
|
||||||
dest = SimpleSerializer<char>::Write(0, dest);
|
dest = SimpleSerializer<char>::Write(0, dest);
|
||||||
return dest;
|
return dest;
|
||||||
|
|
|
@ -99,6 +99,7 @@ class ModuleSerializer {
|
||||||
typedef BasicSourceLineResolver::Line Line;
|
typedef BasicSourceLineResolver::Line Line;
|
||||||
typedef BasicSourceLineResolver::Function Function;
|
typedef BasicSourceLineResolver::Function Function;
|
||||||
typedef BasicSourceLineResolver::PublicSymbol PublicSymbol;
|
typedef BasicSourceLineResolver::PublicSymbol PublicSymbol;
|
||||||
|
typedef BasicSourceLineResolver::InlineOrigin InlineOrigin;
|
||||||
|
|
||||||
// Internal implementation for ConvertOneModule and ConvertAllModules methods.
|
// Internal implementation for ConvertOneModule and ConvertAllModules methods.
|
||||||
bool SerializeModuleAndLoadIntoFastResolver(
|
bool SerializeModuleAndLoadIntoFastResolver(
|
||||||
|
@ -120,6 +121,7 @@ class ModuleSerializer {
|
||||||
linked_ptr<WindowsFrameInfo> > wfi_serializer_;
|
linked_ptr<WindowsFrameInfo> > wfi_serializer_;
|
||||||
RangeMapSerializer<MemAddr, string> cfi_init_rules_serializer_;
|
RangeMapSerializer<MemAddr, string> cfi_init_rules_serializer_;
|
||||||
StdMapSerializer<MemAddr, string> cfi_delta_rules_serializer_;
|
StdMapSerializer<MemAddr, string> cfi_delta_rules_serializer_;
|
||||||
|
StdMapSerializer<int, linked_ptr<InlineOrigin>> inline_origin_serializer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -113,6 +113,25 @@ class SimpleSerializer<BasicSourceLineResolver::Line> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Specializations of SimpleSerializer: InlineOrigin
|
||||||
|
template <>
|
||||||
|
class SimpleSerializer<BasicSourceLineResolver::InlineOrigin> {
|
||||||
|
typedef BasicSourceLineResolver::InlineOrigin InlineOrigin;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static size_t SizeOf(const InlineOrigin& origin) {
|
||||||
|
return SimpleSerializer<bool>::SizeOf(origin.has_file_id) +
|
||||||
|
SimpleSerializer<int32_t>::SizeOf(origin.source_file_id) +
|
||||||
|
SimpleSerializer<string>::SizeOf(origin.name);
|
||||||
|
}
|
||||||
|
static char* Write(const InlineOrigin& origin, char* dest) {
|
||||||
|
dest = SimpleSerializer<bool>::Write(origin.has_file_id, dest);
|
||||||
|
dest = SimpleSerializer<int32_t>::Write(origin.source_file_id, dest);
|
||||||
|
dest = SimpleSerializer<string>::Write(origin.name, dest);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Specializations of SimpleSerializer: PublicSymbol
|
// Specializations of SimpleSerializer: PublicSymbol
|
||||||
template<>
|
template<>
|
||||||
class SimpleSerializer<BasicSourceLineResolver::PublicSymbol> {
|
class SimpleSerializer<BasicSourceLineResolver::PublicSymbol> {
|
||||||
|
@ -165,7 +184,7 @@ class SimpleSerializer<WindowsFrameInfo> {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Specializations of SimpleSerializer: Linked_ptr version of
|
// Specializations of SimpleSerializer: Linked_ptr version of
|
||||||
// Line, Function, PublicSymbol, WindowsFrameInfo.
|
// Line, InlineOrigin, Inline, Function, PublicSymbol, WindowsFrameInfo.
|
||||||
template<>
|
template<>
|
||||||
class SimpleSerializer< linked_ptr<BasicSourceLineResolver::Line> > {
|
class SimpleSerializer< linked_ptr<BasicSourceLineResolver::Line> > {
|
||||||
typedef BasicSourceLineResolver::Line Line;
|
typedef BasicSourceLineResolver::Line Line;
|
||||||
|
@ -181,11 +200,86 @@ class SimpleSerializer< linked_ptr<BasicSourceLineResolver::Line> > {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class SimpleSerializer<linked_ptr<BasicSourceLineResolver::InlineOrigin>> {
|
||||||
|
typedef BasicSourceLineResolver::InlineOrigin InlineOrigin;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static size_t SizeOf(const linked_ptr<InlineOrigin>& origin_ptr) {
|
||||||
|
if (origin_ptr.get() == NULL)
|
||||||
|
return 0;
|
||||||
|
return SimpleSerializer<InlineOrigin>::SizeOf(*(origin_ptr.get()));
|
||||||
|
}
|
||||||
|
static char* Write(const linked_ptr<InlineOrigin>& origin_ptr, char* dest) {
|
||||||
|
if (origin_ptr.get())
|
||||||
|
dest = SimpleSerializer<InlineOrigin>::Write(*(origin_ptr.get()), dest);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specializations of SimpleSerializer: Inline
|
||||||
|
template <>
|
||||||
|
class SimpleSerializer<linked_ptr<BasicSourceLineResolver::Inline>>;
|
||||||
|
template <>
|
||||||
|
class SimpleSerializer<BasicSourceLineResolver::Inline> {
|
||||||
|
typedef BasicSourceLineResolver::Inline Inline;
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline static size_t SizeOf(const Inline& in);
|
||||||
|
inline static char* Write(const Inline& in, char* dest);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class SimpleSerializer<linked_ptr<BasicSourceLineResolver::Inline>> {
|
||||||
|
typedef BasicSourceLineResolver::Inline Inline;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static size_t SizeOf(const linked_ptr<Inline>& inline_ptr) {
|
||||||
|
if (inline_ptr.get() == NULL)
|
||||||
|
return 0;
|
||||||
|
return SimpleSerializer<Inline>::SizeOf(*(inline_ptr.get()));
|
||||||
|
}
|
||||||
|
static char* Write(const linked_ptr<Inline>& inline_ptr, char* dest) {
|
||||||
|
if (inline_ptr.get())
|
||||||
|
dest = SimpleSerializer<Inline>::Write(*(inline_ptr.get()), dest);
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t SimpleSerializer<BasicSourceLineResolver::Inline>::SizeOf(
|
||||||
|
const Inline& in) {
|
||||||
|
return SimpleSerializer<bool>::SizeOf(in.has_call_site_file_id) +
|
||||||
|
SimpleSerializer<int32_t>::SizeOf(in.inline_nest_level) +
|
||||||
|
SimpleSerializer<int32_t>::SizeOf(in.call_site_line) +
|
||||||
|
SimpleSerializer<int32_t>::SizeOf(in.call_site_file_id) +
|
||||||
|
SimpleSerializer<int32_t>::SizeOf(in.origin_id) +
|
||||||
|
sizeof(uint32_t) + // This is to store the size of inline_ranges.
|
||||||
|
(in.inline_ranges.size() * sizeof(MemAddr) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* SimpleSerializer<BasicSourceLineResolver::Inline>::Write(const Inline& in,
|
||||||
|
char* dest) {
|
||||||
|
dest = SimpleSerializer<bool>::Write(in.has_call_site_file_id, dest);
|
||||||
|
dest = SimpleSerializer<int32_t>::Write(in.inline_nest_level, dest);
|
||||||
|
dest = SimpleSerializer<int32_t>::Write(in.call_site_line, dest);
|
||||||
|
dest = SimpleSerializer<int32_t>::Write(in.call_site_file_id, dest);
|
||||||
|
dest = SimpleSerializer<int32_t>::Write(in.origin_id, dest);
|
||||||
|
// Write the size of inline_ranges.
|
||||||
|
dest = SimpleSerializer<int32_t>::Write(in.inline_ranges.size(), dest);
|
||||||
|
for (const std::pair<MemAddr, MemAddr>& range : in.inline_ranges) {
|
||||||
|
dest = SimpleSerializer<MemAddr>::Write(range.first, dest);
|
||||||
|
dest = SimpleSerializer<MemAddr>::Write(range.second, dest);
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
class SimpleSerializer<BasicSourceLineResolver::Function> {
|
class SimpleSerializer<BasicSourceLineResolver::Function> {
|
||||||
// Convenient type names.
|
// Convenient type names.
|
||||||
typedef BasicSourceLineResolver::Function Function;
|
typedef BasicSourceLineResolver::Function Function;
|
||||||
typedef BasicSourceLineResolver::Line Line;
|
typedef BasicSourceLineResolver::Line Line;
|
||||||
|
typedef BasicSourceLineResolver::Inline Inline;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static size_t SizeOf(const Function& func) {
|
static size_t SizeOf(const Function& func) {
|
||||||
unsigned int size = 0;
|
unsigned int size = 0;
|
||||||
|
@ -193,6 +287,11 @@ class SimpleSerializer<BasicSourceLineResolver::Function> {
|
||||||
size += SimpleSerializer<MemAddr>::SizeOf(func.address);
|
size += SimpleSerializer<MemAddr>::SizeOf(func.address);
|
||||||
size += SimpleSerializer<MemAddr>::SizeOf(func.size);
|
size += SimpleSerializer<MemAddr>::SizeOf(func.size);
|
||||||
size += SimpleSerializer<int32_t>::SizeOf(func.parameter_size);
|
size += SimpleSerializer<int32_t>::SizeOf(func.parameter_size);
|
||||||
|
size += SimpleSerializer<bool>::SizeOf(func.is_multiple);
|
||||||
|
// This extra size is used to store the size of serialized func.inlines, so
|
||||||
|
// we know where to start de-serialize func.lines.
|
||||||
|
size += sizeof(int32_t);
|
||||||
|
size += inline_range_map_serializer_.SizeOf(&func.inlines);
|
||||||
size += range_map_serializer_.SizeOf(func.lines);
|
size += range_map_serializer_.SizeOf(func.lines);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
@ -202,12 +301,22 @@ class SimpleSerializer<BasicSourceLineResolver::Function> {
|
||||||
dest = SimpleSerializer<MemAddr>::Write(func.address, dest);
|
dest = SimpleSerializer<MemAddr>::Write(func.address, dest);
|
||||||
dest = SimpleSerializer<MemAddr>::Write(func.size, dest);
|
dest = SimpleSerializer<MemAddr>::Write(func.size, dest);
|
||||||
dest = SimpleSerializer<int32_t>::Write(func.parameter_size, dest);
|
dest = SimpleSerializer<int32_t>::Write(func.parameter_size, dest);
|
||||||
|
dest = SimpleSerializer<bool>::Write(func.is_multiple, dest);
|
||||||
|
char* old_dest = dest;
|
||||||
|
dest += sizeof(int32_t);
|
||||||
|
dest = inline_range_map_serializer_.Write(&func.inlines, dest);
|
||||||
|
// Write the size of serialized func.inlines. The size doesn't include size
|
||||||
|
// field itself.
|
||||||
|
SimpleSerializer<MemAddr>::Write(dest - old_dest - sizeof(int32_t),
|
||||||
|
old_dest);
|
||||||
dest = range_map_serializer_.Write(func.lines, dest);
|
dest = range_map_serializer_.Write(func.lines, dest);
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
// This static member is defined in module_serializer.cc.
|
// This static member is defined in module_serializer.cc.
|
||||||
static RangeMapSerializer<MemAddr, linked_ptr<Line>> range_map_serializer_;
|
static RangeMapSerializer<MemAddr, linked_ptr<Line>> range_map_serializer_;
|
||||||
|
static ContainedRangeMapSerializer<MemAddr, linked_ptr<Inline>>
|
||||||
|
inline_range_map_serializer_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
@ -71,6 +71,7 @@ class SourceLineResolverBase::AutoFileCloser {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SourceLineResolverBase::InlineOrigin {
|
struct SourceLineResolverBase::InlineOrigin {
|
||||||
|
InlineOrigin() {}
|
||||||
InlineOrigin(bool has_file_id, int32_t source_file_id, const string& name)
|
InlineOrigin(bool has_file_id, int32_t source_file_id, const string& name)
|
||||||
: has_file_id(has_file_id),
|
: has_file_id(has_file_id),
|
||||||
source_file_id(source_file_id),
|
source_file_id(source_file_id),
|
||||||
|
@ -84,6 +85,7 @@ struct SourceLineResolverBase::InlineOrigin {
|
||||||
struct SourceLineResolverBase::Inline {
|
struct SourceLineResolverBase::Inline {
|
||||||
// A vector of (address, size) pair for a INLINE record.
|
// A vector of (address, size) pair for a INLINE record.
|
||||||
using InlineRanges = std::vector<std::pair<MemAddr, MemAddr>>;
|
using InlineRanges = std::vector<std::pair<MemAddr, MemAddr>>;
|
||||||
|
Inline() {}
|
||||||
Inline(bool has_call_site_file_id,
|
Inline(bool has_call_site_file_id,
|
||||||
int32_t inline_nest_level,
|
int32_t inline_nest_level,
|
||||||
int32_t call_site_line,
|
int32_t call_site_line,
|
||||||
|
|
Loading…
Reference in a new issue