mirror of
https://git.suyu.dev/suyu/breakpad.git
synced 2025-12-25 00:35:04 +01:00
Fix incorrect source file name for inlined frames
Processor shows incorrect source file name if a frame have an inlined frame and their source files are different. Consider this example: FILE 0 /tmp/a.h FILE 1 /tmp/a.cpp INLINE_ORIGIN 0 0 foo() FUNC 1110 a 0 main INLINE 0 22 0 1110 7 1110 7 3 0 1117 3 23 1 When querying the address 0x1110, we know this line 0x1110 corresponds to /tmp/a.h line 3 and it's inside a inlined function foo() which is defined at /tmp/a.h and called at line 22. But we don't know at which file it's being called at line 22. So, we will get stacks like this: void foo() /tmp/a.h:3 int main() /tmp/a.h:22 The correct stacks should be this: void foo() /tmp/a.h:3 int main() /tmp/a.cpp:22 In this change: 1. Remove file_id field for INLINE_ORIGIN record. 2. Add call_site_file_id for INLINE record to represents the file where this call being inlined. After adding call_site_file_id to it (as third field), it looks like this: FILE 0 /tmp/a.h FILE 1 /tmp/a.cpp INLINE_ORIGIN 0 foo() FUNC 1110 a 0 main INLINE 0 22 1 0 1110 7 1110 7 3 0 1117 3 23 1 Bug: 1190878 Change-Id: Ibbb697d2f7e1b6ac3208cac6fae4353c8743198d Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3232838 Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
71387fc200
commit
54d878abcb
18 changed files with 223 additions and 214 deletions
|
|
@ -50,10 +50,11 @@
|
|||
|
||||
#include "processor/tokenize.h"
|
||||
|
||||
using std::map;
|
||||
using std::vector;
|
||||
using std::deque;
|
||||
using std::make_pair;
|
||||
using std::map;
|
||||
using std::unique_ptr;
|
||||
using std::vector;
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
|
|
@ -237,42 +238,43 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory(
|
|||
return true;
|
||||
}
|
||||
|
||||
int BasicSourceLineResolver::Module::ConstructInlineFrames(
|
||||
void BasicSourceLineResolver::Module::ConstructInlineFrames(
|
||||
StackFrame* frame,
|
||||
MemAddr address,
|
||||
const RangeMap<uint64_t, linked_ptr<Inline>>& inlines,
|
||||
vector<unique_ptr<StackFrame>>* inlined_frames) const {
|
||||
deque<unique_ptr<StackFrame>>* inlined_frames) const {
|
||||
linked_ptr<Inline> in;
|
||||
MemAddr inline_base;
|
||||
if (!inlines.RetrieveRange(address, &in, &inline_base, nullptr, nullptr))
|
||||
return -1;
|
||||
return;
|
||||
auto origin = inline_origins_.find(in->origin_id);
|
||||
if (origin == inline_origins_.end())
|
||||
return -1;
|
||||
return;
|
||||
|
||||
StackFrame new_frame = StackFrame(*frame);
|
||||
new_frame.function_name = origin->second->name;
|
||||
// Use the starting adress of the inlined range as inlined function base.
|
||||
new_frame.function_base = new_frame.module->base_address() + inline_base;
|
||||
auto it = files_.find(origin->second->source_file_id);
|
||||
if (it != files_.end())
|
||||
new_frame.source_file_name = it->second;
|
||||
|
||||
new_frame.trust = StackFrame::FRAME_TRUST_INLINE;
|
||||
// Must add frames before calling ConstructInlineFrames to get correct order.
|
||||
int current_idx = inlined_frames->size();
|
||||
inlined_frames->push_back(unique_ptr<StackFrame>(new StackFrame(new_frame)));
|
||||
int source_line = ConstructInlineFrames(&new_frame, address,
|
||||
in->child_inlines, inlined_frames);
|
||||
if (source_line != -1) {
|
||||
(*inlined_frames)[current_idx]->source_line = source_line;
|
||||
// Update parent frame's source line and source file.
|
||||
frame->source_line = in->call_site_line;
|
||||
auto file = files_.find(in->call_site_file_id);
|
||||
if (file != files_.end()) {
|
||||
frame->source_file_name = file->second;
|
||||
}
|
||||
return in->call_site_line;
|
||||
|
||||
// Create a child frame of `frame`.
|
||||
StackFrame child_frame = StackFrame(*frame);
|
||||
child_frame.function_name = origin->second->name;
|
||||
// Use the starting adress of the inlined range as inlined function base.
|
||||
child_frame.function_base = child_frame.module->base_address() + inline_base;
|
||||
child_frame.trust = StackFrame::FRAME_TRUST_INLINE;
|
||||
ConstructInlineFrames(&child_frame, address, in->child_inlines,
|
||||
inlined_frames);
|
||||
// Add child_frame after ConstructInlineFrames so that the innermost frame is
|
||||
// the first frame inside inlined_frames.
|
||||
inlined_frames->push_back(
|
||||
unique_ptr<StackFrame>(new StackFrame(child_frame)));
|
||||
}
|
||||
|
||||
void BasicSourceLineResolver::Module::LookupAddress(
|
||||
StackFrame* frame,
|
||||
vector<unique_ptr<StackFrame>>* inlined_frames) const {
|
||||
deque<unique_ptr<StackFrame>>* inlined_frames) const {
|
||||
MemAddr address = frame->instruction - frame->module->base_address();
|
||||
|
||||
// First, look for a FUNC record that covers address. Use
|
||||
|
|
@ -306,10 +308,13 @@ void BasicSourceLineResolver::Module::LookupAddress(
|
|||
|
||||
// Check if this is inlined function call.
|
||||
if (inlined_frames) {
|
||||
int source_line =
|
||||
ConstructInlineFrames(frame, address, func->inlines, inlined_frames);
|
||||
if (source_line != -1) {
|
||||
frame->source_line = source_line;
|
||||
int source_line = frame->source_line;
|
||||
string source_file_name = frame->source_file_name;
|
||||
ConstructInlineFrames(frame, address, func->inlines, inlined_frames);
|
||||
if (!inlined_frames->empty()) {
|
||||
// Update the inner most frame's source line and source file name.
|
||||
inlined_frames->front()->source_line = source_line;
|
||||
inlined_frames->front()->source_file_name = source_file_name;
|
||||
}
|
||||
}
|
||||
} else if (public_symbols_.Retrieve(address,
|
||||
|
|
@ -416,12 +421,10 @@ bool BasicSourceLineResolver::Module::ParseFile(char* file_line) {
|
|||
bool BasicSourceLineResolver::Module::ParseInlineOrigin(
|
||||
char* inline_origin_line) {
|
||||
long origin_id;
|
||||
long source_file_id;
|
||||
char* origin_name;
|
||||
if (SymbolParseHelper::ParseInlineOrigin(inline_origin_line, &origin_id,
|
||||
&source_file_id, &origin_name)) {
|
||||
inline_origins_.insert(
|
||||
make_pair(origin_id, new InlineOrigin(source_file_id, origin_name)));
|
||||
&origin_name)) {
|
||||
inline_origins_.insert(make_pair(origin_id, new InlineOrigin(origin_name)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -431,12 +434,14 @@ linked_ptr<BasicSourceLineResolver::Inline>
|
|||
BasicSourceLineResolver::Module::ParseInline(char* inline_line) {
|
||||
long inline_nest_level;
|
||||
long call_site_line;
|
||||
long call_site_file_id;
|
||||
long origin_id;
|
||||
vector<std::pair<MemAddr, MemAddr>> ranges;
|
||||
if (SymbolParseHelper::ParseInline(inline_line, &inline_nest_level,
|
||||
&call_site_line, &origin_id, &ranges)) {
|
||||
return linked_ptr<Inline>(
|
||||
new Inline(inline_nest_level, call_site_line, origin_id, ranges));
|
||||
&call_site_line, &call_site_file_id,
|
||||
&origin_id, &ranges)) {
|
||||
return linked_ptr<Inline>(new Inline(inline_nest_level, call_site_line,
|
||||
call_site_file_id, origin_id, ranges));
|
||||
}
|
||||
return linked_ptr<Inline>();
|
||||
}
|
||||
|
|
@ -636,13 +641,12 @@ bool SymbolParseHelper::ParseFile(char* file_line, long* index,
|
|||
// static
|
||||
bool SymbolParseHelper::ParseInlineOrigin(char* inline_origin_line,
|
||||
long* origin_id,
|
||||
long* file_id,
|
||||
char** name) {
|
||||
// INLINE_ORIGIN <origin_id> <file_id> <name>
|
||||
// INLINE_ORIGIN <origin_id> <name>
|
||||
assert(strncmp(inline_origin_line, "INLINE_ORIGIN ", 14) == 0);
|
||||
inline_origin_line += 14; // skip prefix
|
||||
vector<char*> tokens;
|
||||
if (!Tokenize(inline_origin_line, kWhitespace, 3, &tokens)) {
|
||||
if (!Tokenize(inline_origin_line, kWhitespace, 2, &tokens)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -653,15 +657,7 @@ bool SymbolParseHelper::ParseInlineOrigin(char* inline_origin_line,
|
|||
return false;
|
||||
}
|
||||
|
||||
*file_id = strtol(tokens[1], &after_number, 10);
|
||||
// If the file id is -1, it might be an artificial function that doesn't have
|
||||
// file id. So, we consider -1 as a valid special case.
|
||||
if (!IsValidAfterNumber(after_number) ||
|
||||
*file_id < -1 | *origin_id == std::numeric_limits<long>::max()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*name = tokens[2];
|
||||
*name = tokens[1];
|
||||
if (!*name) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -674,18 +670,19 @@ bool SymbolParseHelper::ParseInline(
|
|||
char* inline_line,
|
||||
long* inline_nest_level,
|
||||
long* call_site_line,
|
||||
long* call_site_file_id,
|
||||
long* origin_id,
|
||||
vector<std::pair<MemAddr, MemAddr>>* ranges) {
|
||||
// INLINE <inline_nest_level> <call_site_line> <origin_id> <address> <size>
|
||||
// ...
|
||||
// INLINE <inline_nest_level> <call_site_line> <call_site_file_id> <origin_id>
|
||||
// [<address> <size>]+
|
||||
assert(strncmp(inline_line, "INLINE ", 7) == 0);
|
||||
inline_line += 7; // skip prefix
|
||||
|
||||
vector<char*> tokens;
|
||||
Tokenize(inline_line, kWhitespace, std::numeric_limits<int>::max(), &tokens);
|
||||
|
||||
// The length of the vector should be at least 5 and an odd number.
|
||||
if (tokens.size() < 5 && tokens.size() % 2 == 0)
|
||||
// The length of the vector should be at least 6 and an even number.
|
||||
if (tokens.size() < 6 || tokens.size() % 2 != 0)
|
||||
return false;
|
||||
|
||||
char* after_number;
|
||||
|
|
@ -701,13 +698,21 @@ bool SymbolParseHelper::ParseInline(
|
|||
return false;
|
||||
}
|
||||
|
||||
*origin_id = strtol(tokens[2], &after_number, 10);
|
||||
*call_site_file_id = strtol(tokens[2], &after_number, 10);
|
||||
// If the file id is -1, it might be an artificial function that doesn't have
|
||||
// file id. So, we consider -1 as a valid special case.
|
||||
if (!IsValidAfterNumber(after_number) || *call_site_file_id < -1 ||
|
||||
*call_site_file_id == std::numeric_limits<long>::max()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*origin_id = strtol(tokens[3], &after_number, 10);
|
||||
if (!IsValidAfterNumber(after_number) || *origin_id < 0 ||
|
||||
*origin_id == std::numeric_limits<long>::max()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 3; i < tokens.size();) {
|
||||
for (size_t i = 4; i < tokens.size();) {
|
||||
MemAddr address = strtoull(tokens[i++], &after_number, 16);
|
||||
if (!IsValidAfterNumber(after_number) ||
|
||||
address == std::numeric_limits<unsigned long long>::max()) {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#ifndef PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_TYPES_H__
|
||||
#define PROCESSOR_BASIC_SOURCE_LINE_RESOLVER_TYPES_H__
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
|
@ -108,15 +109,18 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module {
|
|||
// with the result.
|
||||
virtual void LookupAddress(
|
||||
StackFrame* frame,
|
||||
std::vector<std::unique_ptr<StackFrame>>* inlined_frame) const;
|
||||
std::deque<std::unique_ptr<StackFrame>>* inlined_frame) const;
|
||||
|
||||
// Construct inlined frame for frame and return inlined function call site
|
||||
// source line. If failed to construct inlined frame, return -1.
|
||||
virtual int ConstructInlineFrames(
|
||||
// Construct inlined frames for frame. Return true on success.
|
||||
// If successfully construct inlined frames for `frame`, `inline_frames` will
|
||||
// be filled with lined frames and frame->source_file_name and
|
||||
// frame->source_line will be update to represents the outermost frame.
|
||||
// If failed, `inline_frames` will be empty and frame remains unchanged.
|
||||
virtual void ConstructInlineFrames(
|
||||
StackFrame* frame,
|
||||
MemAddr address,
|
||||
const RangeMap<uint64_t, linked_ptr<Inline>>& inlines,
|
||||
std::vector<std::unique_ptr<StackFrame>>* inline_frames) const;
|
||||
std::deque<std::unique_ptr<StackFrame>>* inline_frames) const;
|
||||
|
||||
// If Windows stack walking information is available covering ADDRESS,
|
||||
// return a WindowsFrameInfo structure describing it. If the information
|
||||
|
|
|
|||
|
|
@ -421,40 +421,40 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolveInlines) {
|
|||
"linux_inline.sym"));
|
||||
ASSERT_TRUE(resolver.HasModule(&module));
|
||||
StackFrame frame;
|
||||
std::vector<std::unique_ptr<StackFrame>> inlined_frames;
|
||||
std::deque<std::unique_ptr<StackFrame>> inlined_frames;
|
||||
frame.instruction = 0x161b6;
|
||||
frame.module = &module;
|
||||
// main frame.
|
||||
resolver.FillSourceLineInfo(&frame, &inlined_frames);
|
||||
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_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[0]->function_name, "foo()");
|
||||
ASSERT_EQ(inlined_frames[0]->function_base, 0x15b45U);
|
||||
ASSERT_EQ(inlined_frames[0]->source_file_name, "linux_inline.cpp");
|
||||
ASSERT_EQ(inlined_frames[0]->source_line, 39);
|
||||
ASSERT_EQ(inlined_frames[0]->source_line_base, 0x161b6U);
|
||||
ASSERT_EQ(inlined_frames[0]->trust, StackFrame::FRAME_TRUST_INLINE);
|
||||
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, "linux_inline.cpp");
|
||||
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[2]->function_name, "func()");
|
||||
ASSERT_EQ(inlined_frames[2]->function_base, 0x15b83U);
|
||||
ASSERT_EQ(inlined_frames[2]->source_file_name, "linux_inline.cpp");
|
||||
ASSERT_EQ(inlined_frames[2]->source_line, 27);
|
||||
ASSERT_EQ(inlined_frames[2]->source_line_base, 0x161b6U);
|
||||
ASSERT_EQ(inlined_frames[2]->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 parsing of valid FILE lines. The format is:
|
||||
|
|
@ -781,25 +781,15 @@ TEST(SymbolParseHelper, ParsePublicSymbolInvalid) {
|
|||
}
|
||||
|
||||
// Test parsing of valid INLINE_ORIGIN lines. The format is:
|
||||
// INLINE_ORIGIN <origin_id> <file_id> <name>
|
||||
// INLINE_ORIGIN <origin_id> <name>
|
||||
TEST(SymbolParseHelper, ParseInlineOriginValid) {
|
||||
long origin_id;
|
||||
long file_id;
|
||||
char* name;
|
||||
|
||||
char kTestLine[] = "INLINE_ORIGIN 1 1 function name";
|
||||
ASSERT_TRUE(SymbolParseHelper::ParseInlineOrigin(kTestLine, &origin_id,
|
||||
&file_id, &name));
|
||||
char kTestLine[] = "INLINE_ORIGIN 1 function name";
|
||||
ASSERT_TRUE(
|
||||
SymbolParseHelper::ParseInlineOrigin(kTestLine, &origin_id, &name));
|
||||
EXPECT_EQ(1, origin_id);
|
||||
EXPECT_EQ(1, file_id);
|
||||
EXPECT_EQ("function name", string(name));
|
||||
|
||||
// -1 is a file id, which is used when the function is artifical.
|
||||
char kTestLine1[] = "INLINE_ORIGIN 0 -1 function name";
|
||||
ASSERT_TRUE(SymbolParseHelper::ParseInlineOrigin(kTestLine1, &origin_id,
|
||||
&file_id, &name));
|
||||
EXPECT_EQ(0, origin_id);
|
||||
EXPECT_EQ(-1, file_id);
|
||||
EXPECT_EQ("function name", string(name));
|
||||
}
|
||||
|
||||
|
|
@ -807,28 +797,27 @@ TEST(SymbolParseHelper, ParseInlineOriginValid) {
|
|||
// INLINE_ORIGIN <origin_id> <file_id> <name>
|
||||
TEST(SymbolParseHelper, ParseInlineOriginInvalid) {
|
||||
long origin_id;
|
||||
long file_id;
|
||||
char* name;
|
||||
|
||||
// Test missing function name.
|
||||
char kTestLine[] = "INLINE_ORIGIN 1 1";
|
||||
ASSERT_FALSE(SymbolParseHelper::ParseInlineOrigin(kTestLine, &origin_id,
|
||||
&file_id, &name));
|
||||
char kTestLine[] = "INLINE_ORIGIN 1";
|
||||
ASSERT_FALSE(
|
||||
SymbolParseHelper::ParseInlineOrigin(kTestLine, &origin_id, &name));
|
||||
|
||||
// Test bad origin id.
|
||||
char kTestLine1[] = "INLINE_ORIGIN x1 1 function name";
|
||||
ASSERT_FALSE(SymbolParseHelper::ParseInlineOrigin(kTestLine1, &origin_id,
|
||||
&file_id, &name));
|
||||
char kTestLine1[] = "INLINE_ORIGIN x1 function name";
|
||||
ASSERT_FALSE(
|
||||
SymbolParseHelper::ParseInlineOrigin(kTestLine1, &origin_id, &name));
|
||||
|
||||
// Test large origin id.
|
||||
char kTestLine2[] = "INLINE_ORIGIN 123123123123123123123123 1 function name";
|
||||
ASSERT_FALSE(SymbolParseHelper::ParseInlineOrigin(kTestLine2, &origin_id,
|
||||
&file_id, &name));
|
||||
char kTestLine2[] = "INLINE_ORIGIN 123123123123123123123123 function name";
|
||||
ASSERT_FALSE(
|
||||
SymbolParseHelper::ParseInlineOrigin(kTestLine2, &origin_id, &name));
|
||||
|
||||
// Test negative origin id.
|
||||
char kTestLine3[] = "INLINE_ORIGIN -1 1 function name";
|
||||
ASSERT_FALSE(SymbolParseHelper::ParseInlineOrigin(kTestLine3, &origin_id,
|
||||
&file_id, &name));
|
||||
char kTestLine3[] = "INLINE_ORIGIN -1 function name";
|
||||
ASSERT_FALSE(
|
||||
SymbolParseHelper::ParseInlineOrigin(kTestLine3, &origin_id, &name));
|
||||
}
|
||||
|
||||
// Test parsing of valid INLINE lines. The format is:
|
||||
|
|
@ -836,26 +825,31 @@ TEST(SymbolParseHelper, ParseInlineOriginInvalid) {
|
|||
TEST(SymbolParseHelper, ParseInlineValid) {
|
||||
long inline_nest_level;
|
||||
long call_site_line;
|
||||
long call_site_file_id;
|
||||
long origin_id;
|
||||
std::vector<std::pair<uint64_t, uint64_t>> ranges;
|
||||
|
||||
char kTestLine[] = "INLINE 0 1 2 3 4";
|
||||
char kTestLine[] = "INLINE 0 1 2 3 4 5";
|
||||
ASSERT_TRUE(SymbolParseHelper::ParseInline(
|
||||
kTestLine, &inline_nest_level, &call_site_line, &origin_id, &ranges));
|
||||
kTestLine, &inline_nest_level, &call_site_line, &call_site_file_id,
|
||||
&origin_id, &ranges));
|
||||
EXPECT_EQ(0, inline_nest_level);
|
||||
EXPECT_EQ(1, call_site_line);
|
||||
EXPECT_EQ(2, origin_id);
|
||||
EXPECT_EQ(0x3ULL, ranges[0].first);
|
||||
EXPECT_EQ(0x4ULL, ranges[0].second);
|
||||
EXPECT_EQ(2, call_site_file_id);
|
||||
EXPECT_EQ(3, origin_id);
|
||||
EXPECT_EQ(0x4ULL, ranges[0].first);
|
||||
EXPECT_EQ(0x5ULL, ranges[0].second);
|
||||
ranges.clear();
|
||||
|
||||
// Test hex and discontinuous ranges.
|
||||
char kTestLine1[] = "INLINE 0 1 2 a b 1a 1b";
|
||||
char kTestLine1[] = "INLINE 0 1 2 3 a b 1a 1b";
|
||||
ASSERT_TRUE(SymbolParseHelper::ParseInline(
|
||||
kTestLine1, &inline_nest_level, &call_site_line, &origin_id, &ranges));
|
||||
kTestLine1, &inline_nest_level, &call_site_line, &call_site_file_id,
|
||||
&origin_id, &ranges));
|
||||
EXPECT_EQ(0, inline_nest_level);
|
||||
EXPECT_EQ(1, call_site_line);
|
||||
EXPECT_EQ(2, origin_id);
|
||||
EXPECT_EQ(2, call_site_file_id);
|
||||
EXPECT_EQ(3, origin_id);
|
||||
EXPECT_EQ(0xaULL, ranges[0].first);
|
||||
EXPECT_EQ(0xbULL, ranges[0].second);
|
||||
EXPECT_EQ(0x1aULL, ranges[1].first);
|
||||
|
|
@ -867,33 +861,39 @@ TEST(SymbolParseHelper, ParseInlineValid) {
|
|||
TEST(SymbolParseHelper, ParseInlineInvalid) {
|
||||
long inline_nest_level;
|
||||
long call_site_line;
|
||||
long call_site_file_id;
|
||||
long origin_id;
|
||||
std::vector<std::pair<uint64_t, uint64_t>> ranges;
|
||||
|
||||
// Test negative inline_nest_level.
|
||||
char kTestLine[] = "INLINE -1 1 2 3 4";
|
||||
char kTestLine[] = "INLINE -1 1 2 3 4 5";
|
||||
ASSERT_FALSE(SymbolParseHelper::ParseInline(
|
||||
kTestLine, &inline_nest_level, &call_site_line, &origin_id, &ranges));
|
||||
kTestLine, &inline_nest_level, &call_site_line, &call_site_file_id,
|
||||
&origin_id, &ranges));
|
||||
|
||||
// Test negative call_site_line.
|
||||
char kTestLine1[] = "INLINE 0 -1 2 3 4";
|
||||
char kTestLine1[] = "INLINE 0 -1 2 3 4 5";
|
||||
ASSERT_FALSE(SymbolParseHelper::ParseInline(
|
||||
kTestLine1, &inline_nest_level, &call_site_line, &origin_id, &ranges));
|
||||
kTestLine1, &inline_nest_level, &call_site_line, &call_site_file_id,
|
||||
&origin_id, &ranges));
|
||||
|
||||
// Test negative origin_id.
|
||||
char kTestLine2[] = "INLINE 0 1 -2 3 4";
|
||||
char kTestLine2[] = "INLINE 0 1 2 -3 4 5";
|
||||
ASSERT_FALSE(SymbolParseHelper::ParseInline(
|
||||
kTestLine2, &inline_nest_level, &call_site_line, &origin_id, &ranges));
|
||||
kTestLine2, &inline_nest_level, &call_site_line, &call_site_file_id,
|
||||
&origin_id, &ranges));
|
||||
|
||||
// Test missing ranges.
|
||||
char kTestLine3[] = "INLINE 0 1 -2";
|
||||
char kTestLine3[] = "INLINE 0 1 2 -2";
|
||||
ASSERT_FALSE(SymbolParseHelper::ParseInline(
|
||||
kTestLine3, &inline_nest_level, &call_site_line, &origin_id, &ranges));
|
||||
kTestLine3, &inline_nest_level, &call_site_line, &call_site_file_id,
|
||||
&origin_id, &ranges));
|
||||
|
||||
// Test missing size for range.
|
||||
char kTestLine4[] = "INLINE 0 1 -2 3";
|
||||
char kTestLine4[] = "INLINE 0 1 -2 3 4";
|
||||
ASSERT_FALSE(SymbolParseHelper::ParseInline(
|
||||
kTestLine4, &inline_nest_level, &call_site_line, &origin_id, &ranges));
|
||||
kTestLine4, &inline_nest_level, &call_site_line, &call_site_file_id,
|
||||
&origin_id, &ranges));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ bool FastSourceLineResolver::ShouldDeleteMemoryBufferAfterLoadModule() {
|
|||
|
||||
void FastSourceLineResolver::Module::LookupAddress(
|
||||
StackFrame* frame,
|
||||
vector<std::unique_ptr<StackFrame>>* inlined_frames) const {
|
||||
std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const {
|
||||
MemAddr address = frame->instruction - frame->module->base_address();
|
||||
|
||||
// First, look for a FUNC record that covers address. Use
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module {
|
|||
// with the result.
|
||||
virtual void LookupAddress(
|
||||
StackFrame* frame,
|
||||
std::vector<std::unique_ptr<StackFrame>>* inlined_frames) const;
|
||||
std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const;
|
||||
|
||||
// Loads a map from the given buffer in char* type.
|
||||
virtual bool LoadMapFromMemory(char* memory_buffer,
|
||||
|
|
|
|||
|
|
@ -297,7 +297,7 @@ bool SourceLineResolverBase::IsModuleCorrupt(const CodeModule* module) {
|
|||
|
||||
void SourceLineResolverBase::FillSourceLineInfo(
|
||||
StackFrame* frame,
|
||||
std::vector<std::unique_ptr<StackFrame>>* inlined_frames) {
|
||||
std::deque<std::unique_ptr<StackFrame>>* inlined_frames) {
|
||||
if (frame->module) {
|
||||
ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
|
||||
if (it != modules_->end()) {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
|
@ -70,10 +71,7 @@ class SourceLineResolverBase::AutoFileCloser {
|
|||
};
|
||||
|
||||
struct SourceLineResolverBase::InlineOrigin {
|
||||
InlineOrigin(int32_t source_file_id, const string& name)
|
||||
: source_file_id(source_file_id), name(name) {}
|
||||
|
||||
int32_t source_file_id;
|
||||
explicit InlineOrigin(const string& name) : name(name) {}
|
||||
string name;
|
||||
};
|
||||
|
||||
|
|
@ -82,15 +80,18 @@ struct SourceLineResolverBase::Inline {
|
|||
using InlineRanges = std::vector<std::pair<MemAddr, MemAddr>>;
|
||||
Inline(int32_t inline_nest_level,
|
||||
int32_t call_site_line,
|
||||
int32_t call_site_file_id,
|
||||
int32_t origin_id,
|
||||
InlineRanges inline_ranges)
|
||||
: inline_nest_level(inline_nest_level),
|
||||
call_site_line(call_site_line),
|
||||
call_site_file_id(call_site_file_id),
|
||||
origin_id(origin_id),
|
||||
inline_ranges(inline_ranges) {}
|
||||
|
||||
int32_t inline_nest_level;
|
||||
int32_t call_site_line;
|
||||
int32_t call_site_file_id;
|
||||
int32_t origin_id;
|
||||
InlineRanges inline_ranges;
|
||||
RangeMap<MemAddr, linked_ptr<Inline>> child_inlines;
|
||||
|
|
@ -174,7 +175,7 @@ class SourceLineResolverBase::Module {
|
|||
// with the result.
|
||||
virtual void LookupAddress(
|
||||
StackFrame* frame,
|
||||
std::vector<std::unique_ptr<StackFrame>>* inlined_frames) const = 0;
|
||||
std::deque<std::unique_ptr<StackFrame>>* inlined_frames) const = 0;
|
||||
|
||||
// If Windows stack walking information is available covering ADDRESS,
|
||||
// return a WindowsFrameInfo structure describing it. If the information
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo(
|
|||
const CodeModules* unloaded_modules,
|
||||
const SystemInfo* system_info,
|
||||
StackFrame* frame,
|
||||
std::vector<std::unique_ptr<StackFrame>>* inlined_frames) {
|
||||
std::deque<std::unique_ptr<StackFrame>>* inlined_frames) {
|
||||
assert(frame);
|
||||
|
||||
const CodeModule* module = NULL;
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ static void PrintStackContents(const string& indent,
|
|||
modules->GetModuleForAddress(pointee_frame.instruction);
|
||||
|
||||
// Try to look up the function name.
|
||||
vector<unique_ptr<StackFrame>> inlined_frames;
|
||||
std::deque<unique_ptr<StackFrame>> inlined_frames;
|
||||
if (pointee_frame.module)
|
||||
resolver->FillSourceLineInfo(&pointee_frame, &inlined_frames);
|
||||
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ bool Stackwalker::Walk(
|
|||
// frame_pointer fields. The frame structure comes from either the
|
||||
// context frame (above) or a caller frame (below).
|
||||
|
||||
vector<std::unique_ptr<StackFrame>> inlined_frames;
|
||||
std::deque<std::unique_ptr<StackFrame>> inlined_frames;
|
||||
// Resolve the module information, if a module map was provided.
|
||||
StackFrameSymbolizer::SymbolizerResult symbolizer_result =
|
||||
frame_symbolizer_->FillSourceLineInfo(modules_, unloaded_modules_,
|
||||
|
|
@ -174,10 +174,10 @@ bool Stackwalker::Walk(
|
|||
default:
|
||||
break;
|
||||
}
|
||||
// Add all nested inlined frames belonging to this frame in reverse order.
|
||||
// Add all nested inlined frames belonging to this frame from left to right.
|
||||
while (!inlined_frames.empty()) {
|
||||
stack->frames_.push_back(inlined_frames.back().release());
|
||||
inlined_frames.pop_back();
|
||||
stack->frames_.push_back(inlined_frames.front().release());
|
||||
inlined_frames.pop_front();
|
||||
}
|
||||
// Add the frame to the call stack. Relinquish the ownership claim
|
||||
// over the frame, because the stack now owns it.
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
MODULE Linux x86_64 BBA6FA10B8AAB33D00000000000000000 linux_inline
|
||||
INFO CODE_ID 10FAA6BBAAB83DB3
|
||||
FILE 0 linux_inline.cpp
|
||||
INLINE_ORIGIN 0 0 bar()
|
||||
INLINE_ORIGIN 1 0 foo()
|
||||
INLINE_ORIGIN 2 0 func()
|
||||
FILE 1 a.cpp
|
||||
FILE 2 b.cpp
|
||||
FILE 3 c.cpp
|
||||
INLINE_ORIGIN 0 bar()
|
||||
INLINE_ORIGIN 1 foo()
|
||||
INLINE_ORIGIN 2 func()
|
||||
FUNC 15b30 6cf 0 main
|
||||
INLINE 0 42 1 15b45 6b1
|
||||
INLINE 1 39 0 15b72 684
|
||||
INLINE 2 32 2 15b83 673
|
||||
INLINE 0 42 1 1 15b45 6b1
|
||||
INLINE 1 39 2 0 15b72 684
|
||||
INLINE 2 32 3 2 15b83 673
|
||||
15b30 15 41 0
|
||||
15b45 11 36 0
|
||||
15b56 a 37 0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue