1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 20:07:36 +00:00

LibDebug: Port the rest of DWARF parsing to Core::Stream

This commit is contained in:
Tim Schumacher 2023-01-22 00:37:38 +01:00 committed by Andreas Kling
parent e62269650a
commit 91505d8cf3
8 changed files with 144 additions and 163 deletions

View file

@ -7,7 +7,6 @@
#include "DebugInfo.h" #include "DebugInfo.h"
#include <AK/Debug.h> #include <AK/Debug.h>
#include <AK/LexicalPath.h> #include <AK/LexicalPath.h>
#include <AK/MemoryStream.h>
#include <AK/QuickSort.h> #include <AK/QuickSort.h>
#include <LibDebug/Dwarf/CompilationUnit.h> #include <LibDebug/Dwarf/CompilationUnit.h>
#include <LibDebug/Dwarf/DwarfInfo.h> #include <LibDebug/Dwarf/DwarfInfo.h>

View file

@ -9,7 +9,6 @@
#include "CompilationUnit.h" #include "CompilationUnit.h"
#include <AK/Forward.h> #include <AK/Forward.h>
#include <AK/Function.h> #include <AK/Function.h>
#include <AK/MemoryStream.h>
#include <AK/Noncopyable.h> #include <AK/Noncopyable.h>
#include <LibCore/Stream.h> #include <LibCore/Stream.h>

View file

@ -8,7 +8,8 @@
#include "CompilationUnit.h" #include "CompilationUnit.h"
#include "DwarfInfo.h" #include "DwarfInfo.h"
#include <AK/ByteBuffer.h> #include <AK/ByteBuffer.h>
#include <AK/MemoryStream.h> #include <AK/LEB128.h>
#include <LibCore/MemoryStream.h>
namespace Debug::Dwarf { namespace Debug::Dwarf {
@ -22,10 +23,12 @@ ErrorOr<void> DIE::rehydrate_from(u32 offset, Optional<u32> parent_offset)
{ {
m_offset = offset; m_offset = offset;
InputMemoryStream stream(m_compilation_unit.dwarf_info().debug_info_data()); auto stream = TRY(Core::Stream::FixedMemoryStream::construct(m_compilation_unit.dwarf_info().debug_info_data()));
stream.discard_or_error(m_offset); // Note: We can't just slice away from the input data here, since get_attribute_value will try to recover the original offset using seek().
stream.read_LEB128_unsigned(m_abbreviation_code); TRY(stream->seek(m_offset));
m_data_offset = stream.offset(); Core::Stream::WrapInAKInputStream wrapped_stream { *stream };
LEB128::read_unsigned(wrapped_stream, m_abbreviation_code);
m_data_offset = TRY(stream->tell());
if (m_abbreviation_code == 0) { if (m_abbreviation_code == 0) {
// An abbreviation code of 0 ( = null DIE entry) means the end of a chain of siblings // An abbreviation code of 0 ( = null DIE entry) means the end of a chain of siblings
@ -39,24 +42,25 @@ ErrorOr<void> DIE::rehydrate_from(u32 offset, Optional<u32> parent_offset)
// We iterate the attributes data only to calculate this DIE's size // We iterate the attributes data only to calculate this DIE's size
for (auto& attribute_spec : abbreviation_info->attribute_specifications) { for (auto& attribute_spec : abbreviation_info->attribute_specifications) {
TRY(m_compilation_unit.dwarf_info().get_attribute_value(attribute_spec.form, attribute_spec.value, stream, &m_compilation_unit)); TRY(m_compilation_unit.dwarf_info().get_attribute_value(attribute_spec.form, attribute_spec.value, *stream, &m_compilation_unit));
} }
} }
m_size = stream.offset() - m_offset; m_size = TRY(stream->tell()) - m_offset;
m_parent_offset = parent_offset; m_parent_offset = parent_offset;
return {}; return {};
} }
ErrorOr<Optional<AttributeValue>> DIE::get_attribute(Attribute const& attribute) const ErrorOr<Optional<AttributeValue>> DIE::get_attribute(Attribute const& attribute) const
{ {
InputMemoryStream stream { m_compilation_unit.dwarf_info().debug_info_data() }; auto stream = TRY(Core::Stream::FixedMemoryStream::construct(m_compilation_unit.dwarf_info().debug_info_data()));
stream.discard_or_error(m_data_offset); // Note: We can't just slice away from the input data here, since get_attribute_value will try to recover the original offset using seek().
TRY(stream->seek(m_data_offset));
auto abbreviation_info = m_compilation_unit.abbreviations_map().get(m_abbreviation_code); auto abbreviation_info = m_compilation_unit.abbreviations_map().get(m_abbreviation_code);
VERIFY(abbreviation_info); VERIFY(abbreviation_info);
for (auto const& attribute_spec : abbreviation_info->attribute_specifications) { for (auto const& attribute_spec : abbreviation_info->attribute_specifications) {
auto value = TRY(m_compilation_unit.dwarf_info().get_attribute_value(attribute_spec.form, attribute_spec.value, stream, &m_compilation_unit)); auto value = TRY(m_compilation_unit.dwarf_info().get_attribute_value(attribute_spec.form, attribute_spec.value, *stream, &m_compilation_unit));
if (attribute_spec.attribute == attribute) { if (attribute_spec.attribute == attribute) {
return value; return value;
} }

View file

@ -10,7 +10,7 @@
#include "CompilationUnit.h" #include "CompilationUnit.h"
#include <AK/ByteReader.h> #include <AK/ByteReader.h>
#include <AK/MemoryStream.h> #include <AK/LEB128.h>
#include <LibCore/MemoryStream.h> #include <LibCore/MemoryStream.h>
#include <LibDebug/DebugInfo.h> #include <LibDebug/DebugInfo.h>
@ -47,59 +47,54 @@ ErrorOr<void> DwarfInfo::populate_compilation_units()
if (!m_debug_info_data.data()) if (!m_debug_info_data.data())
return {}; return {};
InputMemoryStream debug_info_stream { m_debug_info_data }; auto debug_info_stream = TRY(Core::Stream::FixedMemoryStream::construct(m_debug_info_data));
InputMemoryStream line_info_stream { m_debug_line_data }; auto line_info_stream = TRY(Core::Stream::FixedMemoryStream::construct(m_debug_line_data));
while (!debug_info_stream.eof()) { while (!debug_info_stream->is_eof()) {
auto unit_offset = debug_info_stream.offset(); auto unit_offset = TRY(debug_info_stream->tell());
CompilationUnitHeader compilation_unit_header {};
debug_info_stream >> compilation_unit_header; auto compilation_unit_header = TRY(CompilationUnitHeader::read_from_stream(*debug_info_stream));
VERIFY(compilation_unit_header.common.version <= 5); VERIFY(compilation_unit_header.common.version <= 5);
VERIFY(compilation_unit_header.address_size() == sizeof(FlatPtr)); 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));
auto line_program = make<LineProgram>(*this, line_info_stream); auto line_program = make<LineProgram>(*this, *line_info_stream);
// HACK: Clang generates line programs for embedded resource assembly files, but not compile units. // HACK: Clang generates line programs for embedded resource assembly files, but not compile units.
// Meaning that for graphical applications, some line info data would be unread, triggering the assertion below. // Meaning that for graphical applications, some line info data would be unread, triggering the assertion below.
// As a fix, we don't create compilation units for line programs that come from resource files. // As a fix, we don't create compilation units for line programs that come from resource files.
#if defined(AK_COMPILER_CLANG) #if defined(AK_COMPILER_CLANG)
if (line_program->looks_like_embedded_resource()) { if (line_program->looks_like_embedded_resource()) {
debug_info_stream.seek(unit_offset); TRY(debug_info_stream->seek(unit_offset));
} else } else
#endif #endif
{ {
m_compilation_units.append(make<CompilationUnit>(*this, unit_offset, compilation_unit_header, move(line_program))); m_compilation_units.append(make<CompilationUnit>(*this, unit_offset, compilation_unit_header, move(line_program)));
debug_info_stream.discard_or_error(length_after_header); TRY(debug_info_stream->discard(length_after_header));
} }
} }
VERIFY(line_info_stream.eof()); VERIFY(line_info_stream->is_eof());
return {}; return {};
} }
ErrorOr<AttributeValue> DwarfInfo::get_attribute_value(AttributeDataForm form, ssize_t implicit_const_value, ErrorOr<AttributeValue> DwarfInfo::get_attribute_value(AttributeDataForm form, ssize_t implicit_const_value,
InputMemoryStream& debug_info_stream, CompilationUnit const* unit) const Core::Stream::SeekableStream& debug_info_stream, CompilationUnit const* unit) const
{ {
AttributeValue value; AttributeValue value;
value.m_form = form; value.m_form = form;
value.m_compilation_unit = unit; value.m_compilation_unit = unit;
auto assign_raw_bytes_value = [&](size_t length) -> ErrorOr<void> { auto assign_raw_bytes_value = [&](size_t length) -> ErrorOr<void> {
value.m_data.as_raw_bytes = { debug_info_data().offset_pointer(debug_info_stream.offset()), length }; value.m_data.as_raw_bytes = { debug_info_data().offset_pointer(TRY(debug_info_stream.tell())), length };
TRY(debug_info_stream.discard(length));
debug_info_stream.discard_or_error(length);
VERIFY(!debug_info_stream.has_any_error());
return {}; return {};
}; };
switch (form) { switch (form) {
case AttributeDataForm::StringPointer: { case AttributeDataForm::StringPointer: {
u32 offset; auto offset = TRY(debug_info_stream.read_value<u32>());
debug_info_stream >> offset;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::String; value.m_type = AttributeValue::Type::String;
auto strings_data = debug_strings_data(); auto strings_data = debug_strings_data();
@ -107,65 +102,55 @@ ErrorOr<AttributeValue> DwarfInfo::get_attribute_value(AttributeDataForm form, s
break; break;
} }
case AttributeDataForm::Data1: { case AttributeDataForm::Data1: {
u8 data; auto data = TRY(debug_info_stream.read_value<u8>());
debug_info_stream >> data;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::UnsignedNumber; value.m_type = AttributeValue::Type::UnsignedNumber;
value.m_data.as_unsigned = data; value.m_data.as_unsigned = data;
break; break;
} }
case AttributeDataForm::Data2: { case AttributeDataForm::Data2: {
u16 data; auto data = TRY(debug_info_stream.read_value<u16>());
debug_info_stream >> data;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::UnsignedNumber; value.m_type = AttributeValue::Type::UnsignedNumber;
value.m_data.as_signed = data; value.m_data.as_signed = data;
break; break;
} }
case AttributeDataForm::Addr: { case AttributeDataForm::Addr: {
FlatPtr address; auto address = TRY(debug_info_stream.read_value<FlatPtr>());
debug_info_stream >> address;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::Address; value.m_type = AttributeValue::Type::Address;
value.m_data.as_addr = address; value.m_data.as_addr = address;
break; break;
} }
case AttributeDataForm::SData: { case AttributeDataForm::SData: {
i64 data; i64 data;
debug_info_stream.read_LEB128_signed(data); Core::Stream::WrapInAKInputStream wrapped_debug_info_stream { debug_info_stream };
VERIFY(!debug_info_stream.has_any_error()); LEB128::read_signed(wrapped_debug_info_stream, data);
VERIFY(!wrapped_debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::SignedNumber; value.m_type = AttributeValue::Type::SignedNumber;
value.m_data.as_signed = data; value.m_data.as_signed = data;
break; break;
} }
case AttributeDataForm::UData: { case AttributeDataForm::UData: {
u64 data; u64 data;
debug_info_stream.read_LEB128_unsigned(data); Core::Stream::WrapInAKInputStream wrapped_debug_info_stream { debug_info_stream };
VERIFY(!debug_info_stream.has_any_error()); LEB128::read_unsigned(wrapped_debug_info_stream, data);
VERIFY(!wrapped_debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::UnsignedNumber; value.m_type = AttributeValue::Type::UnsignedNumber;
value.m_data.as_unsigned = data; value.m_data.as_unsigned = data;
break; break;
} }
case AttributeDataForm::SecOffset: { case AttributeDataForm::SecOffset: {
u32 data; auto data = TRY(debug_info_stream.read_value<u32>());
debug_info_stream >> data;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::SecOffset; value.m_type = AttributeValue::Type::SecOffset;
value.m_data.as_unsigned = data; value.m_data.as_unsigned = data;
break; break;
} }
case AttributeDataForm::Data4: { case AttributeDataForm::Data4: {
u32 data; auto data = TRY(debug_info_stream.read_value<u32>());
debug_info_stream >> data;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::UnsignedNumber; value.m_type = AttributeValue::Type::UnsignedNumber;
value.m_data.as_unsigned = data; value.m_data.as_unsigned = data;
break; break;
} }
case AttributeDataForm::Data8: { case AttributeDataForm::Data8: {
u64 data; auto data = TRY(debug_info_stream.read_value<u64>());
debug_info_stream >> data;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::UnsignedNumber; value.m_type = AttributeValue::Type::UnsignedNumber;
value.m_data.as_unsigned = data; value.m_data.as_unsigned = data;
break; break;
@ -173,13 +158,10 @@ ErrorOr<AttributeValue> DwarfInfo::get_attribute_value(AttributeDataForm form, s
case AttributeDataForm::Data16: { case AttributeDataForm::Data16: {
value.m_type = AttributeValue::Type::RawBytes; value.m_type = AttributeValue::Type::RawBytes;
TRY(assign_raw_bytes_value(16)); TRY(assign_raw_bytes_value(16));
VERIFY(!debug_info_stream.has_any_error());
break; break;
} }
case AttributeDataForm::Ref4: { case AttributeDataForm::Ref4: {
u32 data; auto data = TRY(debug_info_stream.read_value<u32>());
debug_info_stream >> data;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::DieReference; value.m_type = AttributeValue::Type::DieReference;
VERIFY(unit); VERIFY(unit);
value.m_data.as_unsigned = data + unit->offset(); value.m_data.as_unsigned = data + unit->offset();
@ -192,57 +174,49 @@ ErrorOr<AttributeValue> DwarfInfo::get_attribute_value(AttributeDataForm form, s
} }
case AttributeDataForm::ExprLoc: { case AttributeDataForm::ExprLoc: {
size_t length; size_t length;
debug_info_stream.read_LEB128_unsigned(length); Core::Stream::WrapInAKInputStream wrapped_debug_info_stream { debug_info_stream };
VERIFY(!debug_info_stream.has_any_error()); LEB128::read_unsigned(wrapped_debug_info_stream, length);
VERIFY(!wrapped_debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::DwarfExpression; value.m_type = AttributeValue::Type::DwarfExpression;
TRY(assign_raw_bytes_value(length)); TRY(assign_raw_bytes_value(length));
break; break;
} }
case AttributeDataForm::String: { case AttributeDataForm::String: {
DeprecatedString str; u32 str_offset = TRY(debug_info_stream.tell());
u32 str_offset = debug_info_stream.offset();
debug_info_stream >> str;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::String; value.m_type = AttributeValue::Type::String;
value.m_data.as_string = bit_cast<char const*>(debug_info_data().offset_pointer(str_offset)); value.m_data.as_string = bit_cast<char const*>(debug_info_data().offset_pointer(str_offset));
TRY(debug_info_stream.discard(strlen(value.m_data.as_string) + 1));
break; break;
} }
case AttributeDataForm::Block1: { case AttributeDataForm::Block1: {
value.m_type = AttributeValue::Type::RawBytes; value.m_type = AttributeValue::Type::RawBytes;
u8 length; auto length = TRY(debug_info_stream.read_value<u8>());
debug_info_stream >> length;
VERIFY(!debug_info_stream.has_any_error());
TRY(assign_raw_bytes_value(length)); TRY(assign_raw_bytes_value(length));
break; break;
} }
case AttributeDataForm::Block2: { case AttributeDataForm::Block2: {
value.m_type = AttributeValue::Type::RawBytes; value.m_type = AttributeValue::Type::RawBytes;
u16 length; auto length = TRY(debug_info_stream.read_value<u16>());
debug_info_stream >> length;
VERIFY(!debug_info_stream.has_any_error());
TRY(assign_raw_bytes_value(length)); TRY(assign_raw_bytes_value(length));
break; break;
} }
case AttributeDataForm::Block4: { case AttributeDataForm::Block4: {
value.m_type = AttributeValue::Type::RawBytes; value.m_type = AttributeValue::Type::RawBytes;
u32 length; auto length = TRY(debug_info_stream.read_value<u32>());
debug_info_stream >> length;
VERIFY(!debug_info_stream.has_any_error());
TRY(assign_raw_bytes_value(length)); TRY(assign_raw_bytes_value(length));
break; break;
} }
case AttributeDataForm::Block: { case AttributeDataForm::Block: {
value.m_type = AttributeValue::Type::RawBytes; value.m_type = AttributeValue::Type::RawBytes;
size_t length; size_t length;
debug_info_stream.read_LEB128_unsigned(length); Core::Stream::WrapInAKInputStream wrapped_debug_info_stream { debug_info_stream };
VERIFY(!debug_info_stream.has_any_error()); LEB128::read_unsigned(wrapped_debug_info_stream, length);
VERIFY(!wrapped_debug_info_stream.has_any_error());
TRY(assign_raw_bytes_value(length)); TRY(assign_raw_bytes_value(length));
break; break;
} }
case AttributeDataForm::LineStrP: { case AttributeDataForm::LineStrP: {
u32 offset; auto offset = TRY(debug_info_stream.read_value<u32>());
debug_info_stream >> offset;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::String; value.m_type = AttributeValue::Type::String;
auto strings_data = debug_line_strings_data(); auto strings_data = debug_line_strings_data();
@ -256,73 +230,64 @@ ErrorOr<AttributeValue> DwarfInfo::get_attribute_value(AttributeDataForm form, s
break; break;
} }
case AttributeDataForm::StrX1: { case AttributeDataForm::StrX1: {
u8 index; auto index = TRY(debug_info_stream.read_value<u8>());
debug_info_stream >> index;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::String; value.m_type = AttributeValue::Type::String;
value.m_data.as_unsigned = index; value.m_data.as_unsigned = index;
break; break;
} }
case AttributeDataForm::StrX2: { case AttributeDataForm::StrX2: {
u16 index; auto index = TRY(debug_info_stream.read_value<u16>());
debug_info_stream >> index;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::String; value.m_type = AttributeValue::Type::String;
value.m_data.as_unsigned = index; value.m_data.as_unsigned = index;
break; break;
} }
case AttributeDataForm::StrX4: { case AttributeDataForm::StrX4: {
u32 index; auto index = TRY(debug_info_stream.read_value<u32>());
debug_info_stream >> index;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::String; value.m_type = AttributeValue::Type::String;
value.m_data.as_unsigned = index; value.m_data.as_unsigned = index;
break; break;
} }
case AttributeDataForm::StrX: { case AttributeDataForm::StrX: {
size_t index; size_t index;
debug_info_stream.read_LEB128_unsigned(index); Core::Stream::WrapInAKInputStream wrapped_debug_info_stream { debug_info_stream };
VERIFY(!debug_info_stream.has_any_error()); LEB128::read_unsigned(wrapped_debug_info_stream, index);
VERIFY(!wrapped_debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::String; value.m_type = AttributeValue::Type::String;
value.m_data.as_unsigned = index; value.m_data.as_unsigned = index;
break; break;
} }
case AttributeDataForm::AddrX1: { case AttributeDataForm::AddrX1: {
u8 index; auto index = TRY(debug_info_stream.read_value<u8>());
debug_info_stream >> index;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::Address; value.m_type = AttributeValue::Type::Address;
value.m_data.as_unsigned = index; value.m_data.as_unsigned = index;
break; break;
} }
case AttributeDataForm::AddrX2: { case AttributeDataForm::AddrX2: {
u16 index; auto index = TRY(debug_info_stream.read_value<u16>());
debug_info_stream >> index;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::Address; value.m_type = AttributeValue::Type::Address;
value.m_data.as_unsigned = index; value.m_data.as_unsigned = index;
break; break;
} }
case AttributeDataForm::AddrX4: { case AttributeDataForm::AddrX4: {
u32 index; auto index = TRY(debug_info_stream.read_value<u32>());
debug_info_stream >> index;
VERIFY(!debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::Address; value.m_type = AttributeValue::Type::Address;
value.m_data.as_unsigned = index; value.m_data.as_unsigned = index;
break; break;
} }
case AttributeDataForm::AddrX: { case AttributeDataForm::AddrX: {
size_t index; size_t index;
debug_info_stream.read_LEB128_unsigned(index); Core::Stream::WrapInAKInputStream wrapped_debug_info_stream { debug_info_stream };
VERIFY(!debug_info_stream.has_any_error()); LEB128::read_unsigned(wrapped_debug_info_stream, index);
VERIFY(!wrapped_debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::Address; value.m_type = AttributeValue::Type::Address;
value.m_data.as_unsigned = index; value.m_data.as_unsigned = index;
break; break;
} }
case AttributeDataForm::RngListX: { case AttributeDataForm::RngListX: {
size_t index; size_t index;
debug_info_stream.read_LEB128_unsigned(index); Core::Stream::WrapInAKInputStream wrapped_debug_info_stream { debug_info_stream };
VERIFY(!debug_info_stream.has_any_error()); LEB128::read_unsigned(wrapped_debug_info_stream, index);
VERIFY(!wrapped_debug_info_stream.has_any_error());
value.m_type = AttributeValue::Type::UnsignedNumber; value.m_type = AttributeValue::Type::UnsignedNumber;
value.m_data.as_unsigned = index; value.m_data.as_unsigned = index;
break; break;

View file

@ -14,6 +14,7 @@
#include <AK/NonnullRefPtr.h> #include <AK/NonnullRefPtr.h>
#include <AK/RedBlackTree.h> #include <AK/RedBlackTree.h>
#include <AK/RefCounted.h> #include <AK/RefCounted.h>
#include <LibCore/Stream.h>
#include <LibDebug/Dwarf/DIE.h> #include <LibDebug/Dwarf/DIE.h>
#include <LibELF/Image.h> #include <LibELF/Image.h>
@ -42,7 +43,7 @@ public:
ErrorOr<void> for_each_compilation_unit(Callback) const; ErrorOr<void> for_each_compilation_unit(Callback) const;
ErrorOr<AttributeValue> get_attribute_value(AttributeDataForm form, ssize_t implicit_const_value, ErrorOr<AttributeValue> get_attribute_value(AttributeDataForm form, ssize_t implicit_const_value,
InputMemoryStream& debug_info_stream, CompilationUnit const* unit = nullptr) const; Core::Stream::SeekableStream& debug_info_stream, CompilationUnit const* unit = nullptr) const;
ErrorOr<Optional<DIE>> get_die_at_address(FlatPtr) const; ErrorOr<Optional<DIE>> get_die_at_address(FlatPtr) const;

View file

@ -6,8 +6,8 @@
#pragma once #pragma once
#include <AK/Stream.h>
#include <AK/Types.h> #include <AK/Types.h>
#include <LibCore/Stream.h>
namespace Debug::Dwarf { namespace Debug::Dwarf {
@ -53,17 +53,18 @@ struct [[gnu::packed]] CompilationUnitHeader {
} }
u32 abbrev_offset() const { return (common.version <= 4) ? v4.abbrev_offset : v5.abbrev_offset; } u32 abbrev_offset() const { return (common.version <= 4) ? v4.abbrev_offset : v5.abbrev_offset; }
u8 address_size() const { return (common.version <= 4) ? v4.address_size : v5.address_size; } u8 address_size() const { return (common.version <= 4) ? v4.address_size : v5.address_size; }
};
inline InputStream& operator>>(InputStream& stream, CompilationUnitHeader& header) static ErrorOr<CompilationUnitHeader> read_from_stream(Core::Stream::Stream& stream)
{ {
stream.read_or_error(Bytes { &header.common, sizeof(header.common) }); CompilationUnitHeader header;
if (header.common.version <= 4) TRY(stream.read_entire_buffer(Bytes { &header.common, sizeof(header.common) }));
stream.read_or_error(Bytes { &header.v4, sizeof(header.v4) }); if (header.common.version <= 4)
else TRY(stream.read_entire_buffer(Bytes { &header.v4, sizeof(header.v4) }));
stream.read_or_error(Bytes { &header.v5, sizeof(header.v5) }); else
return stream; TRY(stream.read_entire_buffer(Bytes { &header.v5, sizeof(header.v5) }));
} return header;
}
};
enum class EntryTag : u16 { enum class EntryTag : u16 {
None = 0, None = 0,

View file

@ -8,16 +8,17 @@
#include <AK/Debug.h> #include <AK/Debug.h>
#include <AK/DeprecatedString.h> #include <AK/DeprecatedString.h>
#include <AK/Function.h> #include <AK/Function.h>
#include <AK/LEB128.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <LibDebug/Dwarf/DwarfInfo.h> #include <LibDebug/Dwarf/DwarfInfo.h>
namespace Debug::Dwarf { namespace Debug::Dwarf {
LineProgram::LineProgram(DwarfInfo& dwarf_info, InputMemoryStream& stream) LineProgram::LineProgram(DwarfInfo& dwarf_info, Core::Stream::SeekableStream& stream)
: m_dwarf_info(dwarf_info) : m_dwarf_info(dwarf_info)
, m_stream(stream) , m_stream(stream)
{ {
m_unit_offset = m_stream.offset(); m_unit_offset = m_stream.tell().release_value_but_fixme_should_propagate_errors();
parse_unit_header().release_value_but_fixme_should_propagate_errors(); parse_unit_header().release_value_but_fixme_should_propagate_errors();
parse_source_directories().release_value_but_fixme_should_propagate_errors(); parse_source_directories().release_value_but_fixme_should_propagate_errors();
parse_source_files().release_value_but_fixme_should_propagate_errors(); parse_source_files().release_value_but_fixme_should_propagate_errors();
@ -26,7 +27,7 @@ LineProgram::LineProgram(DwarfInfo& dwarf_info, InputMemoryStream& stream)
ErrorOr<void> LineProgram::parse_unit_header() ErrorOr<void> LineProgram::parse_unit_header()
{ {
m_stream >> m_unit_header; m_unit_header = TRY(LineProgramUnitHeader32::read_from_stream(m_stream));
VERIFY(m_unit_header.version() >= MIN_DWARF_VERSION && m_unit_header.version() <= MAX_DWARF_VERSION); VERIFY(m_unit_header.version() >= MIN_DWARF_VERSION && m_unit_header.version() <= MAX_DWARF_VERSION);
VERIFY(m_unit_header.opcode_base() <= sizeof(m_unit_header.std_opcode_lengths) / sizeof(m_unit_header.std_opcode_lengths[0]) + 1); VERIFY(m_unit_header.opcode_base() <= sizeof(m_unit_header.std_opcode_lengths) / sizeof(m_unit_header.std_opcode_lengths[0]) + 1);
@ -37,24 +38,25 @@ ErrorOr<void> LineProgram::parse_unit_header()
ErrorOr<void> LineProgram::parse_path_entries(Function<void(PathEntry& entry)> callback, PathListType list_type) ErrorOr<void> LineProgram::parse_path_entries(Function<void(PathEntry& entry)> callback, PathListType list_type)
{ {
Core::Stream::WrapInAKInputStream wrapped_stream { m_stream };
if (m_unit_header.version() >= 5) { if (m_unit_header.version() >= 5) {
u8 path_entry_format_count = 0; auto path_entry_format_count = TRY(m_stream.read_value<u8>());
m_stream >> path_entry_format_count;
Vector<PathEntryFormat> format_descriptions; Vector<PathEntryFormat> format_descriptions;
for (u8 i = 0; i < path_entry_format_count; i++) { for (u8 i = 0; i < path_entry_format_count; i++) {
UnderlyingType<ContentType> content_type; UnderlyingType<ContentType> content_type;
m_stream.read_LEB128_unsigned(content_type); LEB128::read_unsigned(wrapped_stream, content_type);
UnderlyingType<AttributeDataForm> data_form; UnderlyingType<AttributeDataForm> data_form;
m_stream.read_LEB128_unsigned(data_form); LEB128::read_unsigned(wrapped_stream, data_form);
format_descriptions.empend(static_cast<ContentType>(content_type), static_cast<AttributeDataForm>(data_form)); format_descriptions.empend(static_cast<ContentType>(content_type), static_cast<AttributeDataForm>(data_form));
} }
size_t paths_count = 0; size_t paths_count = 0;
m_stream.read_LEB128_unsigned(paths_count); LEB128::read_unsigned(wrapped_stream, paths_count);
for (size_t i = 0; i < paths_count; i++) { for (size_t i = 0; i < paths_count; i++) {
PathEntry entry; PathEntry entry;
@ -74,29 +76,30 @@ ErrorOr<void> LineProgram::parse_path_entries(Function<void(PathEntry& entry)> c
callback(entry); callback(entry);
} }
} else { } else {
while (m_stream.peek_or_error()) { while (true) {
DeprecatedString path; StringBuilder builder;
m_stream >> path; while (auto c = TRY(m_stream.read_value<char>()))
TRY(builder.try_append(c));
auto path = builder.to_deprecated_string();
if (path.length() == 0)
break;
dbgln_if(DWARF_DEBUG, "path: {}", path); dbgln_if(DWARF_DEBUG, "path: {}", path);
PathEntry entry; PathEntry entry;
entry.path = path; entry.path = path;
if (list_type == PathListType::Filenames) { if (list_type == PathListType::Filenames) {
size_t directory_index = 0; size_t directory_index = 0;
m_stream.read_LEB128_unsigned(directory_index); LEB128::read_unsigned(wrapped_stream, directory_index);
size_t _unused = 0; size_t _unused = 0;
m_stream.read_LEB128_unsigned(_unused); // skip modification time LEB128::read_unsigned(wrapped_stream, _unused); // skip modification time
m_stream.read_LEB128_unsigned(_unused); // skip file size LEB128::read_unsigned(wrapped_stream, _unused); // skip file size
entry.directory_index = directory_index; entry.directory_index = directory_index;
dbgln_if(DWARF_DEBUG, "file: {}, directory index: {}", path, directory_index); dbgln_if(DWARF_DEBUG, "file: {}, directory index: {}", path, directory_index);
} }
callback(entry); callback(entry);
} }
m_stream.handle_recoverable_error();
m_stream.discard_or_error(1);
} }
VERIFY(!m_stream.has_any_error()); VERIFY(!wrapped_stream.has_any_error());
return {}; return {};
} }
@ -157,11 +160,13 @@ void LineProgram::reset_registers()
ErrorOr<void> LineProgram::handle_extended_opcode() ErrorOr<void> LineProgram::handle_extended_opcode()
{ {
size_t length = 0; Core::Stream::WrapInAKInputStream wrapped_stream { m_stream };
m_stream.read_LEB128_unsigned(length);
u8 sub_opcode = 0; size_t length = 0;
m_stream >> sub_opcode; LEB128::read_unsigned(wrapped_stream, length);
TRY(wrapped_stream.try_handle_any_error());
auto sub_opcode = TRY(m_stream.read_value<u8>());
switch (sub_opcode) { switch (sub_opcode) {
case ExtendedOpcodes::EndSequence: { case ExtendedOpcodes::EndSequence: {
@ -171,18 +176,19 @@ ErrorOr<void> LineProgram::handle_extended_opcode()
} }
case ExtendedOpcodes::SetAddress: { case ExtendedOpcodes::SetAddress: {
VERIFY(length == sizeof(size_t) + 1); VERIFY(length == sizeof(size_t) + 1);
m_stream >> m_address; m_address = TRY(m_stream.read_value<FlatPtr>());
dbgln_if(DWARF_DEBUG, "SetAddress: {:p}", m_address); dbgln_if(DWARF_DEBUG, "SetAddress: {:p}", m_address);
break; break;
} }
case ExtendedOpcodes::SetDiscriminator: { case ExtendedOpcodes::SetDiscriminator: {
dbgln_if(DWARF_DEBUG, "SetDiscriminator"); dbgln_if(DWARF_DEBUG, "SetDiscriminator");
size_t discriminator; size_t discriminator;
m_stream.read_LEB128_unsigned(discriminator); LEB128::read_unsigned(wrapped_stream, discriminator);
TRY(wrapped_stream.try_handle_any_error());
break; break;
} }
default: default:
dbgln("Encountered unknown sub opcode {} at stream offset {:p}", sub_opcode, m_stream.offset()); dbgln("Encountered unknown sub opcode {} at stream offset {:p}", sub_opcode, TRY(m_stream.tell()));
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
} }
@ -190,6 +196,8 @@ ErrorOr<void> LineProgram::handle_extended_opcode()
} }
ErrorOr<void> LineProgram::handle_standard_opcode(u8 opcode) ErrorOr<void> LineProgram::handle_standard_opcode(u8 opcode)
{ {
Core::Stream::WrapInAKInputStream wrapped_stream { m_stream };
switch (opcode) { switch (opcode) {
case StandardOpcodes::Copy: { case StandardOpcodes::Copy: {
append_to_line_info(); append_to_line_info();
@ -197,7 +205,8 @@ ErrorOr<void> LineProgram::handle_standard_opcode(u8 opcode)
} }
case StandardOpcodes::AdvancePc: { case StandardOpcodes::AdvancePc: {
size_t operand = 0; size_t operand = 0;
m_stream.read_LEB128_unsigned(operand); LEB128::read_unsigned(wrapped_stream, operand);
TRY(wrapped_stream.try_handle_any_error());
size_t delta = operand * m_unit_header.min_instruction_length(); size_t delta = operand * m_unit_header.min_instruction_length();
dbgln_if(DWARF_DEBUG, "AdvancePC by: {} to: {:p}", delta, m_address + delta); dbgln_if(DWARF_DEBUG, "AdvancePC by: {} to: {:p}", delta, m_address + delta);
m_address += delta; m_address += delta;
@ -205,7 +214,8 @@ ErrorOr<void> LineProgram::handle_standard_opcode(u8 opcode)
} }
case StandardOpcodes::SetFile: { case StandardOpcodes::SetFile: {
size_t new_file_index = 0; size_t new_file_index = 0;
m_stream.read_LEB128_unsigned(new_file_index); LEB128::read_unsigned(wrapped_stream, new_file_index);
TRY(wrapped_stream.try_handle_any_error());
dbgln_if(DWARF_DEBUG, "SetFile: new file index: {}", new_file_index); dbgln_if(DWARF_DEBUG, "SetFile: new file index: {}", new_file_index);
m_file_index = new_file_index; m_file_index = new_file_index;
break; break;
@ -214,13 +224,15 @@ ErrorOr<void> LineProgram::handle_standard_opcode(u8 opcode)
// not implemented // not implemented
dbgln_if(DWARF_DEBUG, "SetColumn"); dbgln_if(DWARF_DEBUG, "SetColumn");
size_t new_column; size_t new_column;
m_stream.read_LEB128_unsigned(new_column); LEB128::read_unsigned(wrapped_stream, new_column);
TRY(wrapped_stream.try_handle_any_error());
break; break;
} }
case StandardOpcodes::AdvanceLine: { case StandardOpcodes::AdvanceLine: {
ssize_t line_delta; ssize_t line_delta;
m_stream.read_LEB128_signed(line_delta); LEB128::read_signed(wrapped_stream, line_delta);
TRY(wrapped_stream.try_handle_any_error());
VERIFY(line_delta >= 0 || m_line >= (size_t)(-line_delta)); VERIFY(line_delta >= 0 || m_line >= (size_t)(-line_delta));
m_line += line_delta; m_line += line_delta;
dbgln_if(DWARF_DEBUG, "AdvanceLine: {}", m_line); dbgln_if(DWARF_DEBUG, "AdvanceLine: {}", m_line);
@ -241,13 +253,13 @@ ErrorOr<void> LineProgram::handle_standard_opcode(u8 opcode)
} }
case StandardOpcodes::SetIsa: { case StandardOpcodes::SetIsa: {
size_t isa; size_t isa;
m_stream.read_LEB128_unsigned(isa); LEB128::read_unsigned(wrapped_stream, isa);
TRY(wrapped_stream.try_handle_any_error());
dbgln_if(DWARF_DEBUG, "SetIsa: {}", isa); dbgln_if(DWARF_DEBUG, "SetIsa: {}", isa);
break; break;
} }
case StandardOpcodes::FixAdvancePc: { case StandardOpcodes::FixAdvancePc: {
u16 delta = 0; auto delta = TRY(m_stream.read_value<u16>());
m_stream >> delta;
dbgln_if(DWARF_DEBUG, "FixAdvancePC by: {} to: {:p}", delta, m_address + delta); dbgln_if(DWARF_DEBUG, "FixAdvancePC by: {} to: {:p}", delta, m_address + delta);
m_address += delta; m_address += delta;
break; break;
@ -291,11 +303,10 @@ ErrorOr<void> LineProgram::run_program()
{ {
reset_registers(); reset_registers();
while (m_stream.offset() < m_unit_offset + sizeof(u32) + m_unit_header.length()) { while (TRY(m_stream.tell()) < m_unit_offset + sizeof(u32) + m_unit_header.length()) {
u8 opcode = 0; auto opcode = TRY(m_stream.read_value<u8>());
m_stream >> opcode;
dbgln_if(DWARF_DEBUG, "{:p}: opcode: {}", m_stream.offset() - 1, opcode); dbgln_if(DWARF_DEBUG, "{:p}: opcode: {}", TRY(m_stream.tell()) - 1, opcode);
if (opcode == 0) { if (opcode == 0) {
TRY(handle_extended_opcode()); TRY(handle_extended_opcode());

View file

@ -7,8 +7,8 @@
#pragma once #pragma once
#include <AK/DeprecatedFlyString.h> #include <AK/DeprecatedFlyString.h>
#include <AK/MemoryStream.h>
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibCore/Stream.h>
#include <LibDebug/Dwarf/DwarfTypes.h> #include <LibDebug/Dwarf/DwarfTypes.h>
namespace Debug::Dwarf { namespace Debug::Dwarf {
@ -65,6 +65,18 @@ struct [[gnu::packed]] LineProgramUnitHeader32 {
i8 line_base() const { return (common.version <= 4) ? v4.line_base : v5.line_base; } i8 line_base() const { return (common.version <= 4) ? v4.line_base : v5.line_base; }
u8 line_range() const { return (common.version <= 4) ? v4.line_range : v5.line_range; } u8 line_range() const { return (common.version <= 4) ? v4.line_range : v5.line_range; }
u8 opcode_base() const { return (common.version <= 4) ? v4.opcode_base : v5.opcode_base; } u8 opcode_base() const { return (common.version <= 4) ? v4.opcode_base : v5.opcode_base; }
static ErrorOr<LineProgramUnitHeader32> read_from_stream(Core::Stream::Stream& stream)
{
LineProgramUnitHeader32 header;
TRY(stream.read_entire_buffer(Bytes { &header.common, sizeof(header.common) }));
if (header.common.version <= 4)
TRY(stream.read_entire_buffer(Bytes { &header.v4, sizeof(header.v4) }));
else
TRY(stream.read_entire_buffer(Bytes { &header.v5, sizeof(header.v5) }));
TRY(stream.read_entire_buffer(Bytes { &header.std_opcode_lengths, min(sizeof(header.std_opcode_lengths), (header.opcode_base() - 1) * sizeof(header.std_opcode_lengths[0])) }));
return header;
}
}; };
enum class ContentType { enum class ContentType {
@ -92,23 +104,12 @@ enum class PathListType {
Filenames, Filenames,
}; };
inline InputStream& operator>>(InputStream& stream, LineProgramUnitHeader32& header)
{
stream.read_or_error(Bytes { &header.common, sizeof(header.common) });
if (header.common.version <= 4)
stream.read_or_error(Bytes { &header.v4, sizeof(header.v4) });
else
stream.read_or_error(Bytes { &header.v5, sizeof(header.v5) });
stream.read_or_error(Bytes { &header.std_opcode_lengths, min(sizeof(header.std_opcode_lengths), (header.opcode_base() - 1) * sizeof(header.std_opcode_lengths[0])) });
return stream;
}
class LineProgram { class LineProgram {
AK_MAKE_NONCOPYABLE(LineProgram); AK_MAKE_NONCOPYABLE(LineProgram);
AK_MAKE_NONMOVABLE(LineProgram); AK_MAKE_NONMOVABLE(LineProgram);
public: public:
explicit LineProgram(DwarfInfo& dwarf_info, InputMemoryStream& stream); explicit LineProgram(DwarfInfo& dwarf_info, Core::Stream::SeekableStream& stream);
struct LineInfo { struct LineInfo {
FlatPtr address { 0 }; FlatPtr address { 0 };
@ -173,7 +174,7 @@ private:
static constexpr u16 MAX_DWARF_VERSION = 5; static constexpr u16 MAX_DWARF_VERSION = 5;
DwarfInfo& m_dwarf_info; DwarfInfo& m_dwarf_info;
InputMemoryStream& m_stream; Core::Stream::SeekableStream& m_stream;
size_t m_unit_offset { 0 }; size_t m_unit_offset { 0 };
LineProgramUnitHeader32 m_unit_header {}; LineProgramUnitHeader32 m_unit_header {};