Change Inlines in Function to be ContainedRangeMap that is easier to serialize.

Change-Id: I565d41f7d629d7ea9b66cec6760686ca201994b3
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3294125
Reviewed-by: Ivan Penkov <ivanpe@chromium.org>
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Zequan Wu 2021-11-30 13:54:24 -08:00 committed by Joshua Peraza
parent 4458a5965a
commit c472afe064
3 changed files with 65 additions and 62 deletions

View file

@ -241,39 +241,59 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory(
void BasicSourceLineResolver::Module::ConstructInlineFrames( void BasicSourceLineResolver::Module::ConstructInlineFrames(
StackFrame* frame, StackFrame* frame,
MemAddr address, MemAddr address,
const RangeMap<uint64_t, linked_ptr<Inline>>& inlines, const ContainedRangeMap<uint64_t, linked_ptr<Inline>>& inline_map,
deque<unique_ptr<StackFrame>>* inlined_frames) const { deque<unique_ptr<StackFrame>>* inlined_frames) const {
linked_ptr<Inline> in; vector<const linked_ptr<Inline>*> inlines;
MemAddr inline_base; if (!inline_map.RetrieveRanges(address, inlines)) {
if (!inlines.RetrieveRange(address, &in, &inline_base, nullptr, nullptr))
return;
auto origin = inline_origins_.find(in->origin_id);
if (origin == inline_origins_.end())
return; return;
}
// Update parent frame's source line (and source file if it's the new format). for (const linked_ptr<Inline>* const in : inlines) {
frame->source_line = in->call_site_line; unique_ptr<StackFrame> new_frame =
if (in->has_call_site_file_id) { unique_ptr<StackFrame>(new StackFrame(*frame));
auto file = files_.find(in->call_site_file_id); auto origin = inline_origins_.find(in->get()->origin_id);
if (file != files_.end()) { if (origin != inline_origins_.end()) {
frame->source_file_name = file->second; new_frame->function_name = origin->second->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->get()->call_site_line;
if (in->get()->has_call_site_file_id) {
auto file = files_.find(in->get()->call_site_file_id);
if (file != files_.end()) {
new_frame->source_file_name = file->second;
}
}
// Use the starting address of the inlined range as inlined function base.
new_frame->function_base = new_frame->module->base_address();
for (const auto& range : in->get()->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);
} }
} }
StackFrame new_frame = StackFrame(*frame);
new_frame.function_name = origin->second->name;
if (origin->second->has_file_id) {
auto file = files_.find(origin->second->source_file_id);
if (file != files_.end())
new_frame.source_file_name = file->second;
}
// Use the starting adress of the inlined range as inlined function base.
new_frame.function_base = new_frame.module->base_address() + inline_base;
new_frame.trust = StackFrame::FRAME_TRUST_INLINE;
ConstructInlineFrames(&new_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(new_frame)));
} }
void BasicSourceLineResolver::Module::LookupAddress( void BasicSourceLineResolver::Module::LookupAddress(
@ -312,14 +332,7 @@ void BasicSourceLineResolver::Module::LookupAddress(
// Check if this is inlined function call. // Check if this is inlined function call.
if (inlined_frames) { if (inlined_frames) {
int source_line = frame->source_line;
string source_file_name = frame->source_file_name;
ConstructInlineFrames(frame, address, func->inlines, inlined_frames); 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, } else if (public_symbols_.Retrieve(address,
&public_symbol, &public_address) && &public_symbol, &public_address) &&
@ -606,19 +619,12 @@ bool BasicSourceLineResolver::Function::AppendInline(linked_ptr<Inline> in) {
// This happends if in's parent wasn't added due to a malformed INLINE record. // This happends if in's parent wasn't added due to a malformed INLINE record.
if (in->inline_nest_level > last_added_inline_nest_level + 1) if (in->inline_nest_level > last_added_inline_nest_level + 1)
return false; return false;
RangeMap<MemAddr, linked_ptr<Inline>>* current_inlines = &this->inlines;
auto iter = recent_inlines.find(in->inline_nest_level - 1);
if (iter != recent_inlines.end())
current_inlines = &iter->second->child_inlines;
else
assert(in->inline_nest_level == 0);
last_added_inline_nest_level = in->inline_nest_level; last_added_inline_nest_level = in->inline_nest_level;
recent_inlines[last_added_inline_nest_level] = in;
// Store all ranges into current level of inlines. // Store all ranges into current level of inlines.
for (auto range : in->inline_ranges) for (auto range : in->inline_ranges)
current_inlines->StoreRange(range.first, range.second, in); inlines.StoreRange(range.first, range.second, in);
return true; return true;
} }

View file

@ -61,28 +61,26 @@ BasicSourceLineResolver::Function : public SourceLineResolverBase::Function {
MemAddr function_address, MemAddr function_address,
MemAddr code_size, MemAddr code_size,
int set_parameter_size, int set_parameter_size,
bool is_mutiple) : Base(function_name, bool is_mutiple)
function_address, : Base(function_name,
code_size, function_address,
set_parameter_size, code_size,
is_mutiple), set_parameter_size,
inlines(), is_mutiple),
lines(), inlines(true),
last_added_inline_nest_level(0) { } last_added_inline_nest_level(0) {}
// Append inline into corresponding RangeMap. // Append inline into corresponding RangeMap.
// This function assumes it's called in the order of reading INLINE records. // This function assumes it's called in the order of reading INLINE records.
bool AppendInline(linked_ptr<Inline> in); bool AppendInline(linked_ptr<Inline> in);
RangeMap<MemAddr, linked_ptr<Inline>> inlines; ContainedRangeMap<MemAddr, linked_ptr<Inline>> inlines;
RangeMap<MemAddr, linked_ptr<Line>> lines; RangeMap<MemAddr, linked_ptr<Line>> lines;
private: private:
typedef SourceLineResolverBase::Function Base; typedef SourceLineResolverBase::Function Base;
// A map from inline_nest_level to most recently added Inline* at that level. // The last added inline_nest_level from INLINE record.
std::map<int, linked_ptr<Inline>> recent_inlines;
// The last added inline_nest_level in recent_inlines.
int last_added_inline_nest_level; int last_added_inline_nest_level;
}; };
@ -110,14 +108,14 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module {
StackFrame* frame, StackFrame* frame,
std::deque<std::unique_ptr<StackFrame>>* inlined_frame) const; std::deque<std::unique_ptr<StackFrame>>* inlined_frame) const;
// Recursively construct inlined frames for |frame| and store them in // Construct inlined frames for |frame| and store them in |inline_frames|.
// |inline_frames|. |frame|'s source line and source file name may be updated // |frame|'s source line and source file name may be updated if an inlined
// if an inlined frame is found inside |frame|. As a result, the innermost // frame is found inside |frame|. As a result, the innermost inlined frame
// inlined frame will be the first one in |inline_frames|. // will be the first one in |inline_frames|.
virtual void ConstructInlineFrames( virtual void ConstructInlineFrames(
StackFrame* frame, StackFrame* frame,
MemAddr address, MemAddr address,
const RangeMap<uint64_t, linked_ptr<Inline>>& inlines, const ContainedRangeMap<uint64_t, linked_ptr<Inline>>& inline_map,
std::deque<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, // If Windows stack walking information is available covering ADDRESS,

View file

@ -103,7 +103,6 @@ struct SourceLineResolverBase::Inline {
int32_t call_site_file_id; int32_t call_site_file_id;
int32_t origin_id; int32_t origin_id;
InlineRanges inline_ranges; InlineRanges inline_ranges;
RangeMap<MemAddr, linked_ptr<Inline>> child_inlines;
}; };
struct SourceLineResolverBase::Line { struct SourceLineResolverBase::Line {