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:
parent
4458a5965a
commit
c472afe064
3 changed files with 65 additions and 62 deletions
|
@ -241,39 +241,59 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory(
|
|||
void BasicSourceLineResolver::Module::ConstructInlineFrames(
|
||||
StackFrame* frame,
|
||||
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 {
|
||||
linked_ptr<Inline> in;
|
||||
MemAddr inline_base;
|
||||
if (!inlines.RetrieveRange(address, &in, &inline_base, nullptr, nullptr))
|
||||
return;
|
||||
auto origin = inline_origins_.find(in->origin_id);
|
||||
if (origin == inline_origins_.end())
|
||||
vector<const linked_ptr<Inline>*> inlines;
|
||||
if (!inline_map.RetrieveRanges(address, inlines)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update parent frame's source line (and source file if it's the new format).
|
||||
frame->source_line = in->call_site_line;
|
||||
if (in->has_call_site_file_id) {
|
||||
auto file = files_.find(in->call_site_file_id);
|
||||
for (const linked_ptr<Inline>* const in : inlines) {
|
||||
unique_ptr<StackFrame> new_frame =
|
||||
unique_ptr<StackFrame>(new StackFrame(*frame));
|
||||
auto origin = inline_origins_.find(in->get()->origin_id);
|
||||
if (origin != inline_origins_.end()) {
|
||||
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()) {
|
||||
frame->source_file_name = file->second;
|
||||
new_frame->source_file_name = file->second;
|
||||
}
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
// 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(
|
||||
|
@ -312,14 +332,7 @@ void BasicSourceLineResolver::Module::LookupAddress(
|
|||
|
||||
// Check if this is inlined function call.
|
||||
if (inlined_frames) {
|
||||
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,
|
||||
&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.
|
||||
if (in->inline_nest_level > last_added_inline_nest_level + 1)
|
||||
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;
|
||||
recent_inlines[last_added_inline_nest_level] = in;
|
||||
|
||||
// Store all ranges into current level of inlines.
|
||||
for (auto range : in->inline_ranges)
|
||||
current_inlines->StoreRange(range.first, range.second, in);
|
||||
inlines.StoreRange(range.first, range.second, in);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,28 +61,26 @@ BasicSourceLineResolver::Function : public SourceLineResolverBase::Function {
|
|||
MemAddr function_address,
|
||||
MemAddr code_size,
|
||||
int set_parameter_size,
|
||||
bool is_mutiple) : Base(function_name,
|
||||
bool is_mutiple)
|
||||
: Base(function_name,
|
||||
function_address,
|
||||
code_size,
|
||||
set_parameter_size,
|
||||
is_mutiple),
|
||||
inlines(),
|
||||
lines(),
|
||||
inlines(true),
|
||||
last_added_inline_nest_level(0) {}
|
||||
|
||||
// Append inline into corresponding RangeMap.
|
||||
// This function assumes it's called in the order of reading INLINE records.
|
||||
bool AppendInline(linked_ptr<Inline> in);
|
||||
|
||||
RangeMap<MemAddr, linked_ptr<Inline>> inlines;
|
||||
ContainedRangeMap<MemAddr, linked_ptr<Inline>> inlines;
|
||||
RangeMap<MemAddr, linked_ptr<Line>> lines;
|
||||
|
||||
private:
|
||||
typedef SourceLineResolverBase::Function Base;
|
||||
|
||||
// A map from inline_nest_level to most recently added Inline* at that level.
|
||||
std::map<int, linked_ptr<Inline>> recent_inlines;
|
||||
|
||||
// The last added inline_nest_level in recent_inlines.
|
||||
// The last added inline_nest_level from INLINE record.
|
||||
int last_added_inline_nest_level;
|
||||
};
|
||||
|
||||
|
@ -110,14 +108,14 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module {
|
|||
StackFrame* frame,
|
||||
std::deque<std::unique_ptr<StackFrame>>* inlined_frame) const;
|
||||
|
||||
// Recursively 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|.
|
||||
// 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 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;
|
||||
|
||||
// If Windows stack walking information is available covering ADDRESS,
|
||||
|
|
|
@ -103,7 +103,6 @@ struct SourceLineResolverBase::Inline {
|
|||
int32_t call_site_file_id;
|
||||
int32_t origin_id;
|
||||
InlineRanges inline_ranges;
|
||||
RangeMap<MemAddr, linked_ptr<Inline>> child_inlines;
|
||||
};
|
||||
|
||||
struct SourceLineResolverBase::Line {
|
||||
|
|
Loading…
Reference in a new issue