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:
Zequan Wu 2021-10-20 14:07:55 -07:00 committed by Joshua Peraza
parent 71387fc200
commit 54d878abcb
18 changed files with 223 additions and 214 deletions

View file

@ -38,6 +38,7 @@
#ifndef COMMON_LINUX_MODULE_H__
#define COMMON_LINUX_MODULE_H__
#include <functional>
#include <iostream>
#include <limits>
#include <map>
@ -131,7 +132,7 @@ class Module {
};
struct InlineOrigin {
explicit InlineOrigin(StringView name): id(-1), name(name), file(nullptr) {}
explicit InlineOrigin(StringView name) : id(-1), name(name) {}
// A unique id for each InlineOrigin object. INLINE records use the id to
// refer to its INLINE_ORIGIN record.
@ -139,10 +140,6 @@ class Module {
// The inlined function's name.
StringView name;
File* file;
int getFileID() const { return file ? file->source_id : -1; }
};
// A inlined call site.
@ -150,11 +147,14 @@ class Module {
Inline(InlineOrigin* origin,
const vector<Range>& ranges,
int call_site_line,
int call_site_file_id,
int inline_nest_level,
vector<std::unique_ptr<Inline>> child_inlines)
: origin(origin),
ranges(ranges),
call_site_line(call_site_line),
call_site_file_id(call_site_file_id),
call_site_file(nullptr),
inline_nest_level(inline_nest_level),
child_inlines(std::move(child_inlines)) {}
@ -165,10 +165,29 @@ class Module {
int call_site_line;
// The id is only meanful inside a CU. It's only used for looking up real
// File* after scanning a CU.
int call_site_file_id;
File* call_site_file;
int inline_nest_level;
// A list of inlines which are children of this inline.
vector<std::unique_ptr<Inline>> child_inlines;
int getCallSiteFileID() const {
return call_site_file ? call_site_file->source_id : -1;
}
static void InlineDFS(
vector<std::unique_ptr<Module::Inline>>& inlines,
std::function<void(std::unique_ptr<Module::Inline>&)> const& forEach) {
for (std::unique_ptr<Module::Inline>& in : inlines) {
forEach(in);
InlineDFS(in->child_inlines, forEach);
}
}
};
typedef map<uint64_t, InlineOrigin*> InlineOriginByOffset;
@ -182,9 +201,7 @@ class Module {
// value of its DW_AT_specification or equals to offset if
// DW_AT_specification doesn't exist in that DIE.
void SetReference(uint64_t offset, uint64_t specification_offset);
void AssignFilesToInlineOrigins(
const vector<uint64_t>& inline_origin_offsets,
File* file);
~InlineOriginMap() {
for (const auto& iter : inline_origins_) {
delete iter.second;
@ -261,10 +278,8 @@ class Module {
};
struct InlineOriginCompare {
bool operator() (const InlineOrigin* lhs, const InlineOrigin* rhs) const {
if (lhs->getFileID() == rhs->getFileID())
return lhs->name < rhs->name;
return lhs->getFileID() < rhs->getFileID();
bool operator()(const InlineOrigin* lhs, const InlineOrigin* rhs) const {
return lhs->name < rhs->name;
}
};