mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:42:44 +00:00 
			
		
		
		
	LibDebug: Implement symbolication for x86_64
This commit is contained in:
		
							parent
							
								
									567fa4b2f0
								
							
						
					
					
						commit
						2c41e89d08
					
				
					 9 changed files with 33 additions and 43 deletions
				
			
		|  | @ -35,10 +35,6 @@ ELFObjectInfo const* Backtrace::object_info_for_region(ELF::Core::MemoryRegionIn | ||||||
|         return nullptr; |         return nullptr; | ||||||
| 
 | 
 | ||||||
|     auto image = make<ELF::Image>(file_or_error.value()->bytes()); |     auto image = make<ELF::Image>(file_or_error.value()->bytes()); | ||||||
| #if !ARCH(I386) |  | ||||||
|     // FIXME: Fix LibDebug
 |  | ||||||
|     return nullptr; |  | ||||||
| #endif |  | ||||||
|     auto info = make<ELFObjectInfo>(file_or_error.release_value(), make<Debug::DebugInfo>(move(image))); |     auto info = make<ELFObjectInfo>(file_or_error.release_value(), make<Debug::DebugInfo>(move(image))); | ||||||
|     auto* info_ptr = info.ptr(); |     auto* info_ptr = info.ptr(); | ||||||
|     m_debug_info_cache.set(path, move(info)); |     m_debug_info_cache.set(path, move(info)); | ||||||
|  | @ -81,11 +77,11 @@ Backtrace::~Backtrace() | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Backtrace::add_entry(const Reader& coredump, FlatPtr eip) | void Backtrace::add_entry(const Reader& coredump, FlatPtr ip) | ||||||
| { | { | ||||||
|     auto* region = coredump.region_containing((FlatPtr)eip); |     auto* region = coredump.region_containing((FlatPtr)ip); | ||||||
|     if (!region) { |     if (!region) { | ||||||
|         m_entries.append({ eip, {}, {}, {} }); |         m_entries.append({ ip, {}, {}, {} }); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     auto object_name = region->object_name(); |     auto object_name = region->object_name(); | ||||||
|  | @ -95,15 +91,9 @@ void Backtrace::add_entry(const Reader& coredump, FlatPtr eip) | ||||||
|     if (!object_info) |     if (!object_info) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
| #if ARCH(I386) |     auto function_name = object_info->debug_info->elf().symbolicate(ip - region->region_start); | ||||||
|     auto function_name = object_info->debug_info->elf().symbolicate(eip - region->region_start); |     auto source_position = object_info->debug_info->get_source_position_with_inlines(ip - region->region_start); | ||||||
|     auto source_position = object_info->debug_info->get_source_position_with_inlines(eip - region->region_start); |     m_entries.append({ ip, object_name, function_name, source_position }); | ||||||
| #else |  | ||||||
|     // FIXME: Fix symbolication.
 |  | ||||||
|     auto function_name = ""; |  | ||||||
|     Debug::DebugInfo::SourcePositionWithInlines source_position; |  | ||||||
| #endif |  | ||||||
|     m_entries.append({ eip, object_name, function_name, source_position }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| String Backtrace::Entry::to_string(bool color) const | String Backtrace::Entry::to_string(bool color) const | ||||||
|  |  | ||||||
|  | @ -42,7 +42,7 @@ public: | ||||||
|     const Vector<Entry> entries() const { return m_entries; } |     const Vector<Entry> entries() const { return m_entries; } | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void add_entry(const Reader&, FlatPtr eip); |     void add_entry(const Reader&, FlatPtr ip); | ||||||
|     ELFObjectInfo const* object_info_for_region(ELF::Core::MemoryRegionInfo const&); |     ELFObjectInfo const* object_info_for_region(ELF::Core::MemoryRegionInfo const&); | ||||||
| 
 | 
 | ||||||
|     ELF::Core::ThreadInfo m_thread_info; |     ELF::Core::ThreadInfo m_thread_info; | ||||||
|  |  | ||||||
|  | @ -60,9 +60,9 @@ void DebugInfo::parse_scopes_impl(Dwarf::DIE const& die) | ||||||
|             dbgln_if(SPAM_DEBUG, "DWARF: Couldn't find attribute LowPc for scope"); |             dbgln_if(SPAM_DEBUG, "DWARF: Couldn't find attribute LowPc for scope"); | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         scope.address_low = child.get_attribute(Dwarf::Attribute::LowPc).value().data.as_u32; |         scope.address_low = child.get_attribute(Dwarf::Attribute::LowPc).value().data.as_addr; | ||||||
|         // The attribute name HighPc is confusing. In this context, it seems to actually be a positive offset from LowPc
 |         // The attribute name HighPc is confusing. In this context, it seems to actually be a positive offset from LowPc
 | ||||||
|         scope.address_high = scope.address_low + child.get_attribute(Dwarf::Attribute::HighPc).value().data.as_u32; |         scope.address_high = scope.address_low + child.get_attribute(Dwarf::Attribute::HighPc).value().data.as_addr; | ||||||
| 
 | 
 | ||||||
|         child.for_each_child([&](Dwarf::DIE const& variable_entry) { |         child.for_each_child([&](Dwarf::DIE const& variable_entry) { | ||||||
|             if (!(variable_entry.tag() == Dwarf::EntryTag::Variable |             if (!(variable_entry.tag() == Dwarf::EntryTag::Variable | ||||||
|  | @ -78,7 +78,6 @@ void DebugInfo::parse_scopes_impl(Dwarf::DIE const& die) | ||||||
| 
 | 
 | ||||||
| void DebugInfo::prepare_lines() | void DebugInfo::prepare_lines() | ||||||
| { | { | ||||||
| 
 |  | ||||||
|     Vector<Dwarf::LineProgram::LineInfo> all_lines; |     Vector<Dwarf::LineProgram::LineInfo> all_lines; | ||||||
|     m_dwarf_info.for_each_compilation_unit([&all_lines](Dwarf::CompilationUnit const& unit) { |     m_dwarf_info.for_each_compilation_unit([&all_lines](Dwarf::CompilationUnit const& unit) { | ||||||
|         all_lines.extend(unit.line_program().lines()); |         all_lines.extend(unit.line_program().lines()); | ||||||
|  | @ -115,7 +114,7 @@ void DebugInfo::prepare_lines() | ||||||
|     }); |     }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Optional<DebugInfo::SourcePosition> DebugInfo::get_source_position(u32 target_address) const | Optional<DebugInfo::SourcePosition> DebugInfo::get_source_position(FlatPtr target_address) const | ||||||
| { | { | ||||||
|     if (m_sorted_lines.is_empty()) |     if (m_sorted_lines.is_empty()) | ||||||
|         return {}; |         return {}; | ||||||
|  | @ -219,7 +218,7 @@ static void parse_variable_location(Dwarf::DIE const& variable_die, DebugInfo::V | ||||||
|     switch (location_info.value().type) { |     switch (location_info.value().type) { | ||||||
|     case Dwarf::AttributeValue::Type::UnsignedNumber: |     case Dwarf::AttributeValue::Type::UnsignedNumber: | ||||||
|         variable_info.location_type = DebugInfo::VariableInfo::LocationType::Address; |         variable_info.location_type = DebugInfo::VariableInfo::LocationType::Address; | ||||||
|         variable_info.location_data.address = location_info.value().data.as_u32; |         variable_info.location_data.address = location_info.value().data.as_addr; | ||||||
|         break; |         break; | ||||||
|     case Dwarf::AttributeValue::Type::DwarfExpression: { |     case Dwarf::AttributeValue::Type::DwarfExpression: { | ||||||
|         auto expression_bytes = ReadonlyBytes { location_info.value().data.as_raw_bytes.bytes, location_info.value().data.as_raw_bytes.length }; |         auto expression_bytes = ReadonlyBytes { location_info.value().data.as_raw_bytes.bytes, location_info.value().data.as_raw_bytes.length }; | ||||||
|  | @ -228,7 +227,7 @@ static void parse_variable_location(Dwarf::DIE const& variable_die, DebugInfo::V | ||||||
|         if (value.type != Dwarf::Expression::Type::None) { |         if (value.type != Dwarf::Expression::Type::None) { | ||||||
|             VERIFY(value.type == Dwarf::Expression::Type::UnsignedInteger); |             VERIFY(value.type == Dwarf::Expression::Type::UnsignedInteger); | ||||||
|             variable_info.location_type = DebugInfo::VariableInfo::LocationType::Address; |             variable_info.location_type = DebugInfo::VariableInfo::LocationType::Address; | ||||||
|             variable_info.location_data.address = value.data.as_u32; |             variable_info.location_data.address = value.data.as_addr; | ||||||
|         } |         } | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|  | @ -349,7 +348,7 @@ bool DebugInfo::is_variable_tag_supported(Dwarf::EntryTag const& tag) | ||||||
|         || tag == Dwarf::EntryTag::ArrayType; |         || tag == Dwarf::EntryTag::ArrayType; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| String DebugInfo::name_of_containing_function(u32 address) const | String DebugInfo::name_of_containing_function(FlatPtr address) const | ||||||
| { | { | ||||||
|     auto function = get_containing_function(address); |     auto function = get_containing_function(address); | ||||||
|     if (!function.has_value()) |     if (!function.has_value()) | ||||||
|  | @ -357,7 +356,7 @@ String DebugInfo::name_of_containing_function(u32 address) const | ||||||
|     return function.value().name; |     return function.value().name; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Optional<DebugInfo::VariablesScope> DebugInfo::get_containing_function(u32 address) const | Optional<DebugInfo::VariablesScope> DebugInfo::get_containing_function(FlatPtr address) const | ||||||
| { | { | ||||||
|     for (const auto& scope : m_scopes) { |     for (const auto& scope : m_scopes) { | ||||||
|         if (!scope.is_function || address < scope.address_low || address >= scope.address_high) |         if (!scope.is_function || address < scope.address_low || address >= scope.address_high) | ||||||
|  | @ -386,7 +385,7 @@ DebugInfo::SourcePosition DebugInfo::SourcePosition::from_line_info(Dwarf::LineP | ||||||
|     return { line.file, line.line, line.address }; |     return { line.file, line.line, line.address }; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| DebugInfo::SourcePositionWithInlines DebugInfo::get_source_position_with_inlines(u32 address) const | DebugInfo::SourcePositionWithInlines DebugInfo::get_source_position_with_inlines(FlatPtr address) const | ||||||
| { | { | ||||||
|     // If the address is in an "inline chain", this is the inner-most inlined position.
 |     // If the address is in an "inline chain", this is the inner-most inlined position.
 | ||||||
|     auto inner_source_position = get_source_position(address); |     auto inner_source_position = get_source_position(address); | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ public: | ||||||
|     struct SourcePosition { |     struct SourcePosition { | ||||||
|         FlyString file_path; |         FlyString file_path; | ||||||
|         size_t line_number { 0 }; |         size_t line_number { 0 }; | ||||||
|         Optional<u32> address_of_first_statement; |         Optional<FlatPtr> address_of_first_statement; | ||||||
| 
 | 
 | ||||||
|         SourcePosition() |         SourcePosition() | ||||||
|             : SourcePosition(String::empty(), 0) |             : SourcePosition(String::empty(), 0) | ||||||
|  | @ -42,7 +42,7 @@ public: | ||||||
|             , line_number(line_number) |             , line_number(line_number) | ||||||
|         { |         { | ||||||
|         } |         } | ||||||
|         SourcePosition(String file_path, size_t line_number, u32 address_of_first_statement) |         SourcePosition(String file_path, size_t line_number, FlatPtr address_of_first_statement) | ||||||
|             : file_path(file_path) |             : file_path(file_path) | ||||||
|             , line_number(line_number) |             , line_number(line_number) | ||||||
|             , address_of_first_statement(address_of_first_statement) |             , address_of_first_statement(address_of_first_statement) | ||||||
|  | @ -65,7 +65,7 @@ public: | ||||||
|         String type_name; |         String type_name; | ||||||
|         LocationType location_type { LocationType::None }; |         LocationType location_type { LocationType::None }; | ||||||
|         union { |         union { | ||||||
|             u32 address; |             FlatPtr address; | ||||||
|         } location_data { 0 }; |         } location_data { 0 }; | ||||||
| 
 | 
 | ||||||
|         union { |         union { | ||||||
|  | @ -86,20 +86,20 @@ public: | ||||||
|     struct VariablesScope { |     struct VariablesScope { | ||||||
|         bool is_function { false }; |         bool is_function { false }; | ||||||
|         String name; |         String name; | ||||||
|         u32 address_low { 0 }; |         FlatPtr address_low { 0 }; | ||||||
|         u32 address_high { 0 }; // Non-inclusive - the lowest address after address_low that's not in this scope
 |         FlatPtr address_high { 0 }; // Non-inclusive - the lowest address after address_low that's not in this scope
 | ||||||
|         Vector<Dwarf::DIE> dies_of_variables; |         Vector<Dwarf::DIE> dies_of_variables; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     NonnullOwnPtrVector<VariableInfo> get_variables_in_current_scope(PtraceRegisters const&) const; |     NonnullOwnPtrVector<VariableInfo> get_variables_in_current_scope(PtraceRegisters const&) const; | ||||||
| 
 | 
 | ||||||
|     Optional<SourcePosition> get_source_position(u32 address) const; |     Optional<SourcePosition> get_source_position(FlatPtr address) const; | ||||||
| 
 | 
 | ||||||
|     struct SourcePositionWithInlines { |     struct SourcePositionWithInlines { | ||||||
|         Optional<SourcePosition> source_position; |         Optional<SourcePosition> source_position; | ||||||
|         Vector<SourcePosition> inline_chain; |         Vector<SourcePosition> inline_chain; | ||||||
|     }; |     }; | ||||||
|     SourcePositionWithInlines get_source_position_with_inlines(u32 address) const; |     SourcePositionWithInlines get_source_position_with_inlines(FlatPtr address) const; | ||||||
| 
 | 
 | ||||||
|     struct SourcePositionAndAddress { |     struct SourcePositionAndAddress { | ||||||
|         String file; |         String file; | ||||||
|  | @ -109,9 +109,9 @@ public: | ||||||
| 
 | 
 | ||||||
|     Optional<SourcePositionAndAddress> get_address_from_source_position(const String& file, size_t line) const; |     Optional<SourcePositionAndAddress> get_address_from_source_position(const String& file, size_t line) const; | ||||||
| 
 | 
 | ||||||
|     String name_of_containing_function(u32 address) const; |     String name_of_containing_function(FlatPtr address) const; | ||||||
|     Vector<SourcePosition> source_lines_in_scope(const VariablesScope&) const; |     Vector<SourcePosition> source_lines_in_scope(const VariablesScope&) const; | ||||||
|     Optional<VariablesScope> get_containing_function(u32 address) const; |     Optional<VariablesScope> get_containing_function(FlatPtr address) const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void prepare_variable_scopes(); |     void prepare_variable_scopes(); | ||||||
|  |  | ||||||
|  | @ -25,6 +25,7 @@ struct AttributeValue { | ||||||
|     } type; |     } type; | ||||||
| 
 | 
 | ||||||
|     union { |     union { | ||||||
|  |         FlatPtr as_addr; | ||||||
|         u32 as_u32; |         u32 as_u32; | ||||||
|         i32 as_i32; |         i32 as_i32; | ||||||
|         u64 as_u64; |         u64 as_u64; | ||||||
|  |  | ||||||
|  | @ -47,7 +47,7 @@ void DwarfInfo::populate_compilation_units() | ||||||
| 
 | 
 | ||||||
|         debug_info_stream >> compilation_unit_header; |         debug_info_stream >> compilation_unit_header; | ||||||
|         VERIFY(compilation_unit_header.common.version <= 5); |         VERIFY(compilation_unit_header.common.version <= 5); | ||||||
|         VERIFY(compilation_unit_header.address_size() == sizeof(u32)); |         VERIFY(compilation_unit_header.address_size() == sizeof(FlatPtr)); | ||||||
| 
 | 
 | ||||||
|         u32 length_after_header = compilation_unit_header.length() - (compilation_unit_header.header_size() - offsetof(CompilationUnitHeader, common.version)); |         u32 length_after_header = compilation_unit_header.length() - (compilation_unit_header.header_size() - offsetof(CompilationUnitHeader, common.version)); | ||||||
| 
 | 
 | ||||||
|  | @ -102,11 +102,11 @@ AttributeValue DwarfInfo::get_attribute_value(AttributeDataForm form, ssize_t im | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case AttributeDataForm::Addr: { |     case AttributeDataForm::Addr: { | ||||||
|         u32 address; |         FlatPtr address; | ||||||
|         debug_info_stream >> address; |         debug_info_stream >> address; | ||||||
|         VERIFY(!debug_info_stream.has_any_error()); |         VERIFY(!debug_info_stream.has_any_error()); | ||||||
|         value.type = AttributeValue::Type::UnsignedNumber; |         value.type = AttributeValue::Type::UnsignedNumber; | ||||||
|         value.data.as_u32 = address; |         value.data.as_addr = address; | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     case AttributeDataForm::SData: { |     case AttributeDataForm::SData: { | ||||||
|  | @ -250,7 +250,6 @@ void DwarfInfo::build_cached_dies() const | ||||||
|         if (!start.has_value() || !end.has_value()) |         if (!start.has_value() || !end.has_value()) | ||||||
|             return {}; |             return {}; | ||||||
| 
 | 
 | ||||||
|         VERIFY(sizeof(FlatPtr) == sizeof(u32)); |  | ||||||
|         VERIFY(start->type == Dwarf::AttributeValue::Type::UnsignedNumber); |         VERIFY(start->type == Dwarf::AttributeValue::Type::UnsignedNumber); | ||||||
| 
 | 
 | ||||||
|         // DW_AT_high_pc attribute can have different meanings depending on the attribute form.
 |         // DW_AT_high_pc attribute can have different meanings depending on the attribute form.
 | ||||||
|  | @ -258,7 +257,7 @@ void DwarfInfo::build_cached_dies() const | ||||||
| 
 | 
 | ||||||
|         uint32_t range_end = 0; |         uint32_t range_end = 0; | ||||||
|         if (end->form == Dwarf::AttributeDataForm::Addr) |         if (end->form == Dwarf::AttributeDataForm::Addr) | ||||||
|             range_end = end->data.as_u32; |             range_end = end->data.as_addr; | ||||||
|         else |         else | ||||||
|             range_end = start->data.as_u32 + end->data.as_u32; |             range_end = start->data.as_u32 + end->data.as_u32; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ enum class Type { | ||||||
| struct Value { | struct Value { | ||||||
|     Type type; |     Type type; | ||||||
|     union { |     union { | ||||||
|  |         FlatPtr as_addr; | ||||||
|         u32 as_u32; |         u32 as_u32; | ||||||
|     } data { 0 }; |     } data { 0 }; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -174,7 +174,7 @@ void LineProgram::handle_extended_opcode() | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|     default: |     default: | ||||||
|         dbgln_if(DWARF_DEBUG, "offset: {:p}", m_stream.offset()); |         dbgln("Encountered unknown sub opcode {} at stream offset {:p}", sub_opcode, m_stream.offset()); | ||||||
|         VERIFY_NOT_REACHED(); |         VERIFY_NOT_REACHED(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -109,7 +109,7 @@ public: | ||||||
|     explicit LineProgram(DwarfInfo& dwarf_info, InputMemoryStream& stream); |     explicit LineProgram(DwarfInfo& dwarf_info, InputMemoryStream& stream); | ||||||
| 
 | 
 | ||||||
|     struct LineInfo { |     struct LineInfo { | ||||||
|         u32 address { 0 }; |         FlatPtr address { 0 }; | ||||||
|         FlyString file; |         FlyString file; | ||||||
|         size_t line { 0 }; |         size_t line { 0 }; | ||||||
|     }; |     }; | ||||||
|  | @ -176,7 +176,7 @@ private: | ||||||
|     Vector<FileEntry> m_source_files; |     Vector<FileEntry> m_source_files; | ||||||
| 
 | 
 | ||||||
|     // The registers of the "line program" virtual machine
 |     // The registers of the "line program" virtual machine
 | ||||||
|     u32 m_address { 0 }; |     FlatPtr m_address { 0 }; | ||||||
|     size_t m_line { 0 }; |     size_t m_line { 0 }; | ||||||
|     size_t m_file_index { 0 }; |     size_t m_file_index { 0 }; | ||||||
|     bool m_is_statement { false }; |     bool m_is_statement { false }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Gunnar Beutner
						Gunnar Beutner