From 0ae29c99d1a0abed797ad78e5e061f4e2cb9c1cb Mon Sep 17 00:00:00 2001 From: Zequan Wu Date: Tue, 30 Nov 2021 16:29:00 -0800 Subject: [PATCH] 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 --- .../processor/fast_source_line_resolver.h | 2 + src/processor/fast_source_line_resolver.cc | 73 ++++++++++- .../fast_source_line_resolver_types.h | 96 ++++++++++++--- .../fast_source_line_resolver_unittest.cc | 102 ++++++++++++++++ src/processor/module_serializer.cc | 16 ++- src/processor/module_serializer.h | 2 + src/processor/simple_serializer-inl.h | 113 +++++++++++++++++- .../source_line_resolver_base_types.h | 2 + 8 files changed, 379 insertions(+), 27 deletions(-) diff --git a/src/google_breakpad/processor/fast_source_line_resolver.h b/src/google_breakpad/processor/fast_source_line_resolver.h index fdf91077..535fc106 100644 --- a/src/google_breakpad/processor/fast_source_line_resolver.h +++ b/src/google_breakpad/processor/fast_source_line_resolver.h @@ -79,6 +79,8 @@ class FastSourceLineResolver : public SourceLineResolverBase { // SourceLineResolverBase. struct Line; struct Function; + struct Inline; + struct InlineOrigin; struct PublicSymbol; class Module; diff --git a/src/processor/fast_source_line_resolver.cc b/src/processor/fast_source_line_resolver.cc index 31786460..374b06cf 100644 --- a/src/processor/fast_source_line_resolver.cc +++ b/src/processor/fast_source_line_resolver.cc @@ -49,9 +49,8 @@ #include "processor/module_factory.h" #include "processor/simple_serializer-inl.h" -using std::map; -using std::make_pair; -using std::vector; +using std::deque; +using std::unique_ptr; namespace google_breakpad { @@ -101,6 +100,10 @@ void FastSourceLineResolver::Module::LookupAddress( frame->source_line = line->line; 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, public_symbol_ptr, &public_address) && (!func_ptr || public_address > function_base)) { @@ -110,6 +113,68 @@ void FastSourceLineResolver::Module::LookupAddress( } } +void FastSourceLineResolver::Module::ConstructInlineFrames( + StackFrame* frame, + MemAddr address, + const StaticContainedRangeMap& inline_map, + std::deque>* inlined_frames) const { + std::vector inline_ptrs; + if (!inline_map.RetrieveRanges(address, inline_ptrs)) { + return; + } + + for (const char* inline_ptr : inline_ptrs) { + scoped_ptr in(new Inline); + in.get()->CopyFrom(inline_ptr); + unique_ptr new_frame = + unique_ptr(new StackFrame(*frame)); + auto origin_iter = inline_origins_.find(in->origin_id); + if (origin_iter != inline_origins_.end()) { + scoped_ptr origin(new InlineOrigin); + origin.get()->CopyFrom(origin_iter.GetValuePtr()); + new_frame->function_name = origin->name; + } else { + new_frame->function_name = ""; + } + + // 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& 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. // Returns a WFI object reading from a raw memory chunk of data WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char* raw) { @@ -184,7 +249,7 @@ bool FastSourceLineResolver::Module::LoadMapFromMemory( cfi_initial_rules_ = StaticRangeMap(mem_buffer + offsets[map_id++]); cfi_delta_rules_ = StaticMap(mem_buffer + offsets[map_id++]); - + inline_origins_ = StaticMap(mem_buffer + offsets[map_id++]); return true; } diff --git a/src/processor/fast_source_line_resolver_types.h b/src/processor/fast_source_line_resolver_types.h index 2d1bcfcb..577b98e6 100644 --- a/src/processor/fast_source_line_resolver_types.h +++ b/src/processor/fast_source_line_resolver_types.h @@ -37,6 +37,7 @@ #ifndef 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 "processor/source_line_resolver_base_types.h" @@ -53,6 +54,10 @@ namespace google_breakpad { +#define DESERIALIZE(raw_ptr, field) \ + field = *(reinterpret_cast(raw_ptr)); \ + raw_ptr += sizeof(field); + struct FastSourceLineResolver::Line : public SourceLineResolverBase::Line { void CopyFrom(const Line* line_ptr) { const char* raw = reinterpret_cast(line_ptr); @@ -61,12 +66,10 @@ struct FastSourceLineResolver::Line : public SourceLineResolverBase::Line { // De-serialize the memory data of a Line. void CopyFrom(const char* raw) { - address = *(reinterpret_cast(raw)); - size = *(reinterpret_cast(raw + sizeof(address))); - source_file_id = *(reinterpret_cast( - raw + 2 * sizeof(address))); - line = *(reinterpret_cast( - raw + 2 * sizeof(address) + sizeof(source_file_id))); + DESERIALIZE(raw, address); + DESERIALIZE(raw, size); + DESERIALIZE(raw, source_file_id); + DESERIALIZE(raw, line); } }; @@ -81,18 +84,60 @@ public SourceLineResolverBase::Function { void CopyFrom(const char* raw) { size_t name_size = strlen(raw) + 1; name = raw; - address = *(reinterpret_cast(raw + name_size)); - size = *(reinterpret_cast( - raw + name_size + sizeof(MemAddr))); - parameter_size = *(reinterpret_cast( - raw + name_size + 2 * sizeof(MemAddr))); - lines = StaticRangeMap( - raw + name_size + 2 * sizeof(MemAddr) + sizeof(int32_t)); + raw += name_size; + DESERIALIZE(raw, address); + DESERIALIZE(raw, size); + DESERIALIZE(raw, parameter_size); + DESERIALIZE(raw, is_multiple); + int32_t inline_size; + DESERIALIZE(raw, inline_size); + inlines = StaticContainedRangeMap(raw); + lines = StaticRangeMap(raw + inline_size); } + StaticContainedRangeMap inlines; StaticRangeMap lines; }; +struct FastSourceLineResolver::Inline : public SourceLineResolverBase::Inline { + void CopyFrom(const Inline* inline_ptr) { + const char* raw = reinterpret_cast(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 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(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 : public SourceLineResolverBase::PublicSymbol { void CopyFrom(const PublicSymbol* public_symbol_ptr) { @@ -104,12 +149,15 @@ public SourceLineResolverBase::PublicSymbol { void CopyFrom(const char* raw) { size_t name_size = strlen(raw) + 1; name = raw; - address = *(reinterpret_cast(raw + name_size)); - parameter_size = *(reinterpret_cast( - raw + name_size + sizeof(MemAddr))); + raw += name_size; + DESERIALIZE(raw, address); + DESERIALIZE(raw, parameter_size); + DESERIALIZE(raw, is_multiple); } }; +#undef DESERIALIZE + class FastSourceLineResolver::Module: public SourceLineResolverBase::Module { public: explicit Module(const string& name) : name_(name), is_corrupt_(false) { } @@ -121,6 +169,16 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module { StackFrame* frame, std::deque>* 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& inline_map, + std::deque>* inlined_frames) const; + // Loads a map from the given buffer in char* type. virtual bool LoadMapFromMemory(char* memory_buffer, size_t memory_buffer_size); @@ -143,7 +201,7 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module { virtual CFIFrameInfo* FindCFIFrameInfo(const StackFrame* frame) const; // 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: 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_ // entry (which FindCFIFrameInfo looks up first). StaticMap cfi_delta_rules_; + + // INLINE_ORIGIN records: used as a function name string pool for INLINE + // records. + StaticMap inline_origins_; }; } // namespace google_breakpad diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor/fast_source_line_resolver_unittest.cc index 5109e4f1..a8e22408 100644 --- a/src/processor/fast_source_line_resolver_unittest.cc +++ b/src/processor/fast_source_line_resolver_unittest.cc @@ -408,6 +408,108 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) { 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> 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> 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) { TestCodeModule module3("module3"); ASSERT_TRUE(basic_resolver.LoadModule(&module3, diff --git a/src/processor/module_serializer.cc b/src/processor/module_serializer.cc index 04cadc80..8ad0d589 100644 --- a/src/processor/module_serializer.cc +++ b/src/processor/module_serializer.cc @@ -43,10 +43,15 @@ namespace google_breakpad { -// Definition of static member variable in SimplerSerializer, which -// is declared in file "simple_serializer-inl.h" -RangeMapSerializer< MemAddr, linked_ptr > -SimpleSerializer::range_map_serializer_; +// Definition of static member variables in SimplerSerializer and +// SimplerSerializer, which are declared in file +// "simple_serializer-inl.h" +RangeMapSerializer> + SimpleSerializer::range_map_serializer_; +ContainedRangeMapSerializer> + SimpleSerializer< + BasicSourceLineResolver::Function>::inline_range_map_serializer_; size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module& module) { size_t total_size_alloc_ = 0; @@ -66,6 +71,8 @@ size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module& module) { module.cfi_initial_rules_); map_sizes_[map_index++] = cfi_delta_rules_serializer_.SizeOf( module.cfi_delta_rules_); + map_sizes_[map_index++] = + inline_origin_serializer_.SizeOf(module.inline_origins_); // Header size. 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 = cfi_init_rules_serializer_.Write(module.cfi_initial_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. dest = SimpleSerializer::Write(0, dest); return dest; diff --git a/src/processor/module_serializer.h b/src/processor/module_serializer.h index 932ac3d7..94e25c01 100644 --- a/src/processor/module_serializer.h +++ b/src/processor/module_serializer.h @@ -99,6 +99,7 @@ class ModuleSerializer { typedef BasicSourceLineResolver::Line Line; typedef BasicSourceLineResolver::Function Function; typedef BasicSourceLineResolver::PublicSymbol PublicSymbol; + typedef BasicSourceLineResolver::InlineOrigin InlineOrigin; // Internal implementation for ConvertOneModule and ConvertAllModules methods. bool SerializeModuleAndLoadIntoFastResolver( @@ -120,6 +121,7 @@ class ModuleSerializer { linked_ptr > wfi_serializer_; RangeMapSerializer cfi_init_rules_serializer_; StdMapSerializer cfi_delta_rules_serializer_; + StdMapSerializer> inline_origin_serializer_; }; } // namespace google_breakpad diff --git a/src/processor/simple_serializer-inl.h b/src/processor/simple_serializer-inl.h index cb1a0408..4b4200e4 100644 --- a/src/processor/simple_serializer-inl.h +++ b/src/processor/simple_serializer-inl.h @@ -113,6 +113,25 @@ class SimpleSerializer { } }; +// Specializations of SimpleSerializer: InlineOrigin +template <> +class SimpleSerializer { + typedef BasicSourceLineResolver::InlineOrigin InlineOrigin; + + public: + static size_t SizeOf(const InlineOrigin& origin) { + return SimpleSerializer::SizeOf(origin.has_file_id) + + SimpleSerializer::SizeOf(origin.source_file_id) + + SimpleSerializer::SizeOf(origin.name); + } + static char* Write(const InlineOrigin& origin, char* dest) { + dest = SimpleSerializer::Write(origin.has_file_id, dest); + dest = SimpleSerializer::Write(origin.source_file_id, dest); + dest = SimpleSerializer::Write(origin.name, dest); + return dest; + } +}; + // Specializations of SimpleSerializer: PublicSymbol template<> class SimpleSerializer { @@ -165,7 +184,7 @@ class SimpleSerializer { }; // Specializations of SimpleSerializer: Linked_ptr version of -// Line, Function, PublicSymbol, WindowsFrameInfo. +// Line, InlineOrigin, Inline, Function, PublicSymbol, WindowsFrameInfo. template<> class SimpleSerializer< linked_ptr > { typedef BasicSourceLineResolver::Line Line; @@ -181,11 +200,86 @@ class SimpleSerializer< linked_ptr > { } }; +template <> +class SimpleSerializer> { + typedef BasicSourceLineResolver::InlineOrigin InlineOrigin; + + public: + static size_t SizeOf(const linked_ptr& origin_ptr) { + if (origin_ptr.get() == NULL) + return 0; + return SimpleSerializer::SizeOf(*(origin_ptr.get())); + } + static char* Write(const linked_ptr& origin_ptr, char* dest) { + if (origin_ptr.get()) + dest = SimpleSerializer::Write(*(origin_ptr.get()), dest); + return dest; + } +}; + +// Specializations of SimpleSerializer: Inline +template <> +class SimpleSerializer>; +template <> +class SimpleSerializer { + 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> { + typedef BasicSourceLineResolver::Inline Inline; + + public: + static size_t SizeOf(const linked_ptr& inline_ptr) { + if (inline_ptr.get() == NULL) + return 0; + return SimpleSerializer::SizeOf(*(inline_ptr.get())); + } + static char* Write(const linked_ptr& inline_ptr, char* dest) { + if (inline_ptr.get()) + dest = SimpleSerializer::Write(*(inline_ptr.get()), dest); + return dest; + } +}; + +size_t SimpleSerializer::SizeOf( + const Inline& in) { + return SimpleSerializer::SizeOf(in.has_call_site_file_id) + + SimpleSerializer::SizeOf(in.inline_nest_level) + + SimpleSerializer::SizeOf(in.call_site_line) + + SimpleSerializer::SizeOf(in.call_site_file_id) + + SimpleSerializer::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::Write(const Inline& in, + char* dest) { + dest = SimpleSerializer::Write(in.has_call_site_file_id, dest); + dest = SimpleSerializer::Write(in.inline_nest_level, dest); + dest = SimpleSerializer::Write(in.call_site_line, dest); + dest = SimpleSerializer::Write(in.call_site_file_id, dest); + dest = SimpleSerializer::Write(in.origin_id, dest); + // Write the size of inline_ranges. + dest = SimpleSerializer::Write(in.inline_ranges.size(), dest); + for (const std::pair& range : in.inline_ranges) { + dest = SimpleSerializer::Write(range.first, dest); + dest = SimpleSerializer::Write(range.second, dest); + } + return dest; +} + template<> class SimpleSerializer { // Convenient type names. typedef BasicSourceLineResolver::Function Function; typedef BasicSourceLineResolver::Line Line; + typedef BasicSourceLineResolver::Inline Inline; + public: static size_t SizeOf(const Function& func) { unsigned int size = 0; @@ -193,6 +287,11 @@ class SimpleSerializer { size += SimpleSerializer::SizeOf(func.address); size += SimpleSerializer::SizeOf(func.size); size += SimpleSerializer::SizeOf(func.parameter_size); + size += SimpleSerializer::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); return size; } @@ -202,12 +301,22 @@ class SimpleSerializer { dest = SimpleSerializer::Write(func.address, dest); dest = SimpleSerializer::Write(func.size, dest); dest = SimpleSerializer::Write(func.parameter_size, dest); + dest = SimpleSerializer::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::Write(dest - old_dest - sizeof(int32_t), + old_dest); dest = range_map_serializer_.Write(func.lines, dest); return dest; } private: // This static member is defined in module_serializer.cc. - static RangeMapSerializer< MemAddr, linked_ptr > range_map_serializer_; + static RangeMapSerializer> range_map_serializer_; + static ContainedRangeMapSerializer> + inline_range_map_serializer_; }; template<> diff --git a/src/processor/source_line_resolver_base_types.h b/src/processor/source_line_resolver_base_types.h index 4d3ce066..82889550 100644 --- a/src/processor/source_line_resolver_base_types.h +++ b/src/processor/source_line_resolver_base_types.h @@ -71,6 +71,7 @@ class SourceLineResolverBase::AutoFileCloser { }; struct SourceLineResolverBase::InlineOrigin { + InlineOrigin() {} InlineOrigin(bool has_file_id, int32_t source_file_id, const string& name) : has_file_id(has_file_id), source_file_id(source_file_id), @@ -84,6 +85,7 @@ struct SourceLineResolverBase::InlineOrigin { struct SourceLineResolverBase::Inline { // A vector of (address, size) pair for a INLINE record. using InlineRanges = std::vector>; + Inline() {} Inline(bool has_call_site_file_id, int32_t inline_nest_level, int32_t call_site_line,