From 421aa7c475ea50bddd2a0f27e8b7cb7d70c7167a Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 2 Jun 2024 16:58:24 +0200 Subject: [PATCH] Everywhere: Remove more unused components --- .../Lagom/Tools/CodeGenerators/CMakeLists.txt | 1 - .../CodeGenerators/LibEDID/CMakeLists.txt | 1 - .../CodeGenerators/LibEDID/GeneratePnpIDs.cpp | 193 ------- Tests/CMakeLists.txt | 2 - Userland/Libraries/CMakeLists.txt | 3 - Userland/Libraries/LibDebug/CMakeLists.txt | 15 - Userland/Libraries/LibDebug/DebugInfo.cpp | 466 --------------- Userland/Libraries/LibDebug/DebugInfo.h | 134 ----- Userland/Libraries/LibDebug/DebugSession.cpp | 532 ------------------ Userland/Libraries/LibDebug/DebugSession.h | 351 ------------ .../LibDebug/Dwarf/AbbreviationsMap.cpp | 75 --- .../LibDebug/Dwarf/AbbreviationsMap.h | 38 -- .../LibDebug/Dwarf/AddressRanges.cpp | 109 ---- .../Libraries/LibDebug/Dwarf/AddressRanges.h | 50 -- .../LibDebug/Dwarf/AttributeValue.cpp | 49 -- .../Libraries/LibDebug/Dwarf/AttributeValue.h | 59 -- .../LibDebug/Dwarf/CompilationUnit.cpp | 149 ----- .../LibDebug/Dwarf/CompilationUnit.h | 70 --- Userland/Libraries/LibDebug/Dwarf/DIE.cpp | 103 ---- Userland/Libraries/LibDebug/Dwarf/DIE.h | 50 -- .../Libraries/LibDebug/Dwarf/DwarfInfo.cpp | 392 ------------- Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h | 99 ---- .../Libraries/LibDebug/Dwarf/DwarfTypes.h | 337 ----------- .../Libraries/LibDebug/Dwarf/LineProgram.cpp | 320 ----------- .../Libraries/LibDebug/Dwarf/LineProgram.h | 197 ------- Userland/Libraries/LibDebug/LoadedLibrary.h | 32 -- .../Libraries/LibDebug/ProcessInspector.cpp | 62 -- .../Libraries/LibDebug/ProcessInspector.h | 38 -- 28 files changed, 3927 deletions(-) delete mode 100644 Meta/Lagom/Tools/CodeGenerators/LibEDID/CMakeLists.txt delete mode 100644 Meta/Lagom/Tools/CodeGenerators/LibEDID/GeneratePnpIDs.cpp delete mode 100644 Userland/Libraries/LibDebug/CMakeLists.txt delete mode 100644 Userland/Libraries/LibDebug/DebugInfo.cpp delete mode 100644 Userland/Libraries/LibDebug/DebugInfo.h delete mode 100644 Userland/Libraries/LibDebug/DebugSession.cpp delete mode 100644 Userland/Libraries/LibDebug/DebugSession.h delete mode 100644 Userland/Libraries/LibDebug/Dwarf/AbbreviationsMap.cpp delete mode 100644 Userland/Libraries/LibDebug/Dwarf/AbbreviationsMap.h delete mode 100644 Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp delete mode 100644 Userland/Libraries/LibDebug/Dwarf/AddressRanges.h delete mode 100644 Userland/Libraries/LibDebug/Dwarf/AttributeValue.cpp delete mode 100644 Userland/Libraries/LibDebug/Dwarf/AttributeValue.h delete mode 100644 Userland/Libraries/LibDebug/Dwarf/CompilationUnit.cpp delete mode 100644 Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h delete mode 100644 Userland/Libraries/LibDebug/Dwarf/DIE.cpp delete mode 100644 Userland/Libraries/LibDebug/Dwarf/DIE.h delete mode 100644 Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp delete mode 100644 Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h delete mode 100644 Userland/Libraries/LibDebug/Dwarf/DwarfTypes.h delete mode 100644 Userland/Libraries/LibDebug/Dwarf/LineProgram.cpp delete mode 100644 Userland/Libraries/LibDebug/Dwarf/LineProgram.h delete mode 100644 Userland/Libraries/LibDebug/LoadedLibrary.h delete mode 100644 Userland/Libraries/LibDebug/ProcessInspector.cpp delete mode 100644 Userland/Libraries/LibDebug/ProcessInspector.h diff --git a/Meta/Lagom/Tools/CodeGenerators/CMakeLists.txt b/Meta/Lagom/Tools/CodeGenerators/CMakeLists.txt index 43e7a61a87d..c659ae74acb 100644 --- a/Meta/Lagom/Tools/CodeGenerators/CMakeLists.txt +++ b/Meta/Lagom/Tools/CodeGenerators/CMakeLists.txt @@ -3,7 +3,6 @@ add_subdirectory(IPCCompiler) if (BUILD_LAGOM) add_subdirectory(JSSpecCompiler) endif() -add_subdirectory(LibEDID) add_subdirectory(LibGL) add_subdirectory(LibLocale) add_subdirectory(LibTextCodec) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibEDID/CMakeLists.txt b/Meta/Lagom/Tools/CodeGenerators/LibEDID/CMakeLists.txt deleted file mode 100644 index 8d49533d397..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/LibEDID/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -lagom_tool(GeneratePnpIDsData SOURCES GeneratePnpIDs.cpp LIBS LibMain) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibEDID/GeneratePnpIDs.cpp b/Meta/Lagom/Tools/CodeGenerators/LibEDID/GeneratePnpIDs.cpp deleted file mode 100644 index 3b6a0d7aba9..00000000000 --- a/Meta/Lagom/Tools/CodeGenerators/LibEDID/GeneratePnpIDs.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -struct ApprovalDate { - unsigned year; - unsigned month; - unsigned day; -}; - -struct PnpIdData { - String manufacturer_name; - ApprovalDate approval_date; -}; - -static ErrorOr parse_approval_date(StringView date) -{ - auto parts = date.trim_whitespace().split_view('/', SplitBehavior::KeepEmpty); - if (parts.size() != 3) - return Error::from_string_literal("Failed to parse approval date parts (mm/dd/yyyy)"); - - auto month = parts[0].to_number(); - if (!month.has_value()) - return Error::from_string_literal("Failed to parse month from approval date"); - if (month.value() == 0 || month.value() > 12) - return Error::from_string_literal("Invalid month in approval date"); - - auto day = parts[1].to_number(); - if (!day.has_value()) - return Error::from_string_literal("Failed to parse day from approval date"); - if (day.value() == 0 || day.value() > 31) - return Error::from_string_literal("Invalid day in approval date"); - - auto year = parts[2].to_number(); - if (!year.has_value()) - return Error::from_string_literal("Failed to parse year from approval date"); - if (year.value() < 1900 || year.value() > 2999) - return Error::from_string_literal("Invalid year approval date"); - - return ApprovalDate { .year = year.value(), .month = month.value(), .day = day.value() }; -} - -static ErrorOr> parse_pnp_ids_database(Core::InputBufferedFile& pnp_ids_file) -{ - HashMap pnp_id_data; - Array buffer; - - // The first line is just a header. - (void)TRY(pnp_ids_file.read_line(buffer)); - - while (TRY(pnp_ids_file.can_read_line())) { - auto line = TRY(pnp_ids_file.read_line(buffer)); - - auto segments = line.split_view(','); - VERIFY(segments.size() >= 3); - - auto approval_date = TRY(parse_approval_date(segments.take_last())); - auto manufacturer_id = MUST(String::from_utf8(segments.take_last())); - auto manufacturer_name = MUST(MUST(String::join(',', segments)).trim("\""sv)); - - pnp_id_data.set(move(manufacturer_id), { .manufacturer_name = move(manufacturer_name), .approval_date = approval_date }); - } - - if (pnp_id_data.size() <= 1) - return Error::from_string_literal("Expected more than one row"); - - return pnp_id_data; -} - -static ErrorOr generate_header(Core::InputBufferedFile& file) -{ - StringBuilder builder; - SourceGenerator generator { builder }; - - generator.append(R"~~~( -#pragma once - -#include -#include -#include - -namespace PnpIDs { - struct PnpIDData { - StringView manufacturer_id; - StringView manufacturer_name; - struct { - u16 year { 0 }; - u8 month { 0 }; - u8 day { 0 }; - } approval_date; - }; - - Optional find_by_manufacturer_id(StringView); - IterationDecision for_each(Function); -} -)~~~"); - - TRY(file.write_until_depleted(generator.as_string_view().bytes())); - return {}; -} - -static ErrorOr generate_source(Core::InputBufferedFile& file, HashMap const& pnp_ids) -{ - StringBuilder builder; - SourceGenerator generator { builder }; - - generator.append(R"~~~( -#include - -namespace PnpIDs { - -static constexpr PnpIDData s_pnp_ids[] = {)~~~"); - - for (auto& pnp_id_data : pnp_ids) { - generator.set("manufacturer_id", pnp_id_data.key); - generator.set("manufacturer_name", pnp_id_data.value.manufacturer_name); - generator.set("approval_year", MUST(String::number(pnp_id_data.value.approval_date.year))); - generator.set("approval_month", MUST(String::number(pnp_id_data.value.approval_date.month))); - generator.set("approval_day", MUST(String::number(pnp_id_data.value.approval_date.day))); - - generator.append(R"~~~( - { "@manufacturer_id@"sv, "@manufacturer_name@"sv, { @approval_year@, @approval_month@, @approval_day@ } },)~~~"); - } - - generator.append(R"~~~( -}; - -Optional find_by_manufacturer_id(StringView manufacturer_id) -{ - for (auto& pnp_data : s_pnp_ids) { - if (pnp_data.manufacturer_id == manufacturer_id) - return pnp_data; - } - return {}; -} - -IterationDecision for_each(Function callback) -{ - for (auto& pnp_data : s_pnp_ids) { - auto decision = callback(pnp_data); - if (decision != IterationDecision::Continue) - return decision; - } - return IterationDecision::Continue; -} - -} -)~~~"); - - TRY(file.write_until_depleted(generator.as_string_view().bytes())); - return {}; -} - -ErrorOr serenity_main(Main::Arguments arguments) -{ - StringView generated_header_path; - StringView generated_implementation_path; - StringView pnp_ids_file_path; - - Core::ArgsParser args_parser; - args_parser.add_option(generated_header_path, "Path to the header file to generate", "generated-header-path", 'h', "generated-header-path"); - args_parser.add_option(generated_implementation_path, "Path to the implementation file to generate", "generated-implementation-path", 'c', "generated-implementation-path"); - args_parser.add_option(pnp_ids_file_path, "Path to the input PNP ID database file", "pnp-ids-file", 'p', "pnp-ids-file"); - args_parser.parse(arguments); - - auto open_file = [&](StringView path, Core::File::OpenMode mode = Core::File::OpenMode::Read) -> ErrorOr> { - if (path.is_empty()) { - args_parser.print_usage(stderr, arguments.strings[0]); - return Error::from_string_literal("Must provide all command line options"); - } - - auto file = TRY(Core::File::open(path, mode)); - return Core::InputBufferedFile::create(move(file)); - }; - - auto generated_header_file = TRY(open_file(generated_header_path, Core::File::OpenMode::ReadWrite)); - auto generated_implementation_file = TRY(open_file(generated_implementation_path, Core::File::OpenMode::ReadWrite)); - auto pnp_ids_file = TRY(open_file(pnp_ids_file_path)); - - auto pnp_id_map = TRY(parse_pnp_ids_database(*pnp_ids_file)); - - TRY(generate_header(*generated_header_file)); - TRY(generate_source(*generated_implementation_file, pnp_id_map)); - - return 0; -} diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 74c86c32a11..705039bd967 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -5,9 +5,7 @@ add_subdirectory(LibC) add_subdirectory(LibCompress) add_subdirectory(LibCore) add_subdirectory(LibCpp) -add_subdirectory(LibDeviceTree) add_subdirectory(LibDiff) -add_subdirectory(LibEDID) add_subdirectory(LibELF) add_subdirectory(LibGfx) add_subdirectory(LibGL) diff --git a/Userland/Libraries/CMakeLists.txt b/Userland/Libraries/CMakeLists.txt index 65462af2b7e..d847f98e81b 100644 --- a/Userland/Libraries/CMakeLists.txt +++ b/Userland/Libraries/CMakeLists.txt @@ -13,13 +13,10 @@ add_subdirectory(LibCoredump) add_subdirectory(LibCpp) add_subdirectory(LibCrypt) add_subdirectory(LibCrypto) -add_subdirectory(LibDebug) add_subdirectory(LibDesktop) -add_subdirectory(LibDeviceTree) add_subdirectory(LibDiff) add_subdirectory(LibDNS) add_subdirectory(LibDSP) -add_subdirectory(LibEDID) add_subdirectory(LibELF) add_subdirectory(LibFileSystem) add_subdirectory(LibFileSystemAccessClient) diff --git a/Userland/Libraries/LibDebug/CMakeLists.txt b/Userland/Libraries/LibDebug/CMakeLists.txt deleted file mode 100644 index e022c1a13ca..00000000000 --- a/Userland/Libraries/LibDebug/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -set(SOURCES - DebugInfo.cpp - DebugSession.cpp - Dwarf/AbbreviationsMap.cpp - Dwarf/AddressRanges.cpp - Dwarf/AttributeValue.cpp - Dwarf/CompilationUnit.cpp - Dwarf/DIE.cpp - Dwarf/DwarfInfo.cpp - Dwarf/LineProgram.cpp - ProcessInspector.cpp -) - -serenity_lib(LibDebug debug) -target_link_libraries(LibDebug PRIVATE LibCore LibELF LibFileSystem LibRegex) diff --git a/Userland/Libraries/LibDebug/DebugInfo.cpp b/Userland/Libraries/LibDebug/DebugInfo.cpp deleted file mode 100644 index ae885347aee..00000000000 --- a/Userland/Libraries/LibDebug/DebugInfo.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright (c) 2020-2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "DebugInfo.h" -#include -#include -#include -#include -#include - -namespace Debug { - -DebugInfo::DebugInfo(ELF::Image const& elf, ByteString source_root, FlatPtr base_address) - : m_elf(elf) - , m_source_root(move(source_root)) - , m_base_address(base_address) - , m_dwarf_info(m_elf) -{ - prepare_variable_scopes().release_value_but_fixme_should_propagate_errors(); - prepare_lines().release_value_but_fixme_should_propagate_errors(); -} - -ErrorOr DebugInfo::prepare_variable_scopes() -{ - TRY(m_dwarf_info.for_each_compilation_unit([&](Dwarf::CompilationUnit const& unit) -> ErrorOr { - auto root = unit.root_die(); - TRY(parse_scopes_impl(root)); - return {}; - })); - return {}; -} - -ErrorOr DebugInfo::parse_scopes_impl(Dwarf::DIE const& die) -{ - TRY(die.for_each_child([&](Dwarf::DIE const& child) -> ErrorOr { - if (child.is_null()) - return {}; - if (!(child.tag() == Dwarf::EntryTag::SubProgram || child.tag() == Dwarf::EntryTag::LexicalBlock)) - return {}; - - if (TRY(child.get_attribute(Dwarf::Attribute::Inline)).has_value()) { - dbgln_if(SPAM_DEBUG, "DWARF inlined functions are not supported"); - return {}; - } - if (TRY(child.get_attribute(Dwarf::Attribute::Ranges)).has_value()) { - dbgln_if(SPAM_DEBUG, "DWARF ranges are not supported"); - return {}; - } - auto name = TRY(child.get_attribute(Dwarf::Attribute::Name)); - - VariablesScope scope {}; - scope.is_function = (child.tag() == Dwarf::EntryTag::SubProgram); - if (name.has_value()) - scope.name = TRY(name.value().as_string()); - - if (!TRY(child.get_attribute(Dwarf::Attribute::LowPc)).has_value()) { - dbgln_if(SPAM_DEBUG, "DWARF: Couldn't find attribute LowPc for scope"); - return {}; - } - scope.address_low = TRY(TRY(child.get_attribute(Dwarf::Attribute::LowPc)).value().as_addr()); - auto high_pc = TRY(child.get_attribute(Dwarf::Attribute::HighPc)); - if (high_pc->type() == Dwarf::AttributeValue::Type::Address) - scope.address_high = TRY(high_pc->as_addr()); - else - scope.address_high = scope.address_low + high_pc->as_unsigned(); - - TRY(child.for_each_child([&](Dwarf::DIE const& variable_entry) -> ErrorOr { - if (!(variable_entry.tag() == Dwarf::EntryTag::Variable - || variable_entry.tag() == Dwarf::EntryTag::FormalParameter)) - return {}; - scope.dies_of_variables.append(variable_entry); - return {}; - })); - m_scopes.append(scope); - - TRY(parse_scopes_impl(child)); - - return {}; - })); - return {}; -} - -ErrorOr DebugInfo::prepare_lines() -{ - Vector all_lines; - TRY(m_dwarf_info.for_each_compilation_unit([&all_lines](Dwarf::CompilationUnit const& unit) -> ErrorOr { - all_lines.extend(unit.line_program().lines()); - return {}; - })); - - HashMap> memoized_full_paths; - auto compute_full_path = [&](DeprecatedFlyString const& file_path) -> Optional { - if (file_path.view().contains("Toolchain/"sv) || file_path.view().contains("libgcc"sv)) - return {}; - if (file_path.view().starts_with("./"sv) && !m_source_root.is_empty()) - return LexicalPath::join(m_source_root, file_path).string(); - if (auto index_of_serenity_slash = file_path.view().find("serenity/"sv); index_of_serenity_slash.has_value()) { - auto start_index = index_of_serenity_slash.value() + "serenity/"sv.length(); - return file_path.view().substring_view(start_index, file_path.length() - start_index); - } - return file_path; - }; - - m_sorted_lines.ensure_capacity(all_lines.size()); - - for (auto const& line_info : all_lines) { - auto maybe_full_path = memoized_full_paths.ensure(line_info.file, [&] { return compute_full_path(line_info.file); }); - if (!maybe_full_path.has_value()) - continue; - m_sorted_lines.unchecked_append({ line_info.address, maybe_full_path.release_value(), line_info.line }); - } - - quick_sort(m_sorted_lines, [](auto& a, auto& b) { - return a.address < b.address; - }); - return {}; -} - -Optional DebugInfo::get_source_position(FlatPtr target_address) const -{ - if (m_sorted_lines.is_empty()) - return {}; - if (target_address < m_sorted_lines[0].address) - return {}; - - // TODO: We can do a binary search here - for (size_t i = 0; i < m_sorted_lines.size() - 1; ++i) { - if (m_sorted_lines[i + 1].address > target_address) { - return SourcePosition::from_line_info(m_sorted_lines[i]); - } - } - return {}; -} - -Optional DebugInfo::get_address_from_source_position(ByteString const& file, size_t line) const -{ - ByteString file_path = file; - if (!file_path.starts_with('/')) - file_path = ByteString::formatted("/{}", file_path); - - Optional result; - for (auto const& line_entry : m_sorted_lines) { - if (!line_entry.file.ends_with(file_path)) - continue; - - if (line_entry.line > line) - continue; - - // We look for the source position that is closest to the desired position, and is not after it. - // For example, get_address_of_source_position("main.cpp", 73) could return the address for an instruction whose location is ("main.cpp", 72) - // as there might not be an instruction mapped for "main.cpp", 73. - if (!result.has_value() || (line_entry.line > result.value().line)) { - result = SourcePositionAndAddress { line_entry.file, line_entry.line, line_entry.address }; - } - } - return result; -} - -ErrorOr>> DebugInfo::get_variables_in_current_scope(PtraceRegisters const& regs) const -{ - Vector> variables; - - // TODO: We can store the scopes in a better data structure - for (auto const& scope : m_scopes) { - FlatPtr ip; -#if ARCH(X86_64) - ip = regs.rip; -#elif ARCH(AARCH64) - TODO_AARCH64(); -#elif ARCH(RISCV64) - TODO_RISCV64(); -#else -# error Unknown architecture -#endif - if (ip - m_base_address < scope.address_low || ip - m_base_address >= scope.address_high) - continue; - - for (auto const& die_entry : scope.dies_of_variables) { - auto variable_info = TRY(create_variable_info(die_entry, regs)); - if (!variable_info) - continue; - variables.append(variable_info.release_nonnull()); - } - } - return variables; -} - -static ErrorOr> parse_variable_type_die(Dwarf::DIE const& variable_die, DebugInfo::VariableInfo& variable_info) -{ - auto type_die_offset = TRY(variable_die.get_attribute(Dwarf::Attribute::Type)); - if (!type_die_offset.has_value()) - return Optional {}; - - VERIFY(type_die_offset.value().type() == Dwarf::AttributeValue::Type::DieReference); - - auto type_die = variable_die.compilation_unit().get_die_at_offset(type_die_offset.value().as_unsigned()); - auto type_name = TRY(type_die.get_attribute(Dwarf::Attribute::Name)); - if (type_name.has_value()) { - variable_info.type_name = TRY(type_name.value().as_string()); - } else { - dbgln("Unnamed DWARF type at offset: {}", type_die.offset()); - variable_info.type_name = "[Unnamed Type]"; - } - - return type_die; -} - -static ErrorOr parse_variable_location(Dwarf::DIE const& variable_die, DebugInfo::VariableInfo& variable_info, PtraceRegisters const&) -{ - auto location_info = TRY(variable_die.get_attribute(Dwarf::Attribute::Location)); - if (!location_info.has_value()) { - location_info = TRY(variable_die.get_attribute(Dwarf::Attribute::MemberLocation)); - } - - if (!location_info.has_value()) - return {}; - - switch (location_info.value().type()) { - case Dwarf::AttributeValue::Type::UnsignedNumber: - if (location_info->form() != Dwarf::AttributeDataForm::LocListX) { - variable_info.location_type = DebugInfo::VariableInfo::LocationType::Address; - variable_info.location_data.address = location_info.value().as_unsigned(); - } else { - dbgln("Warning: unsupported Dwarf 5 loclist"); - } - break; - default: - dbgln("Warning: unhandled Dwarf location type: {}", to_underlying(location_info.value().type())); - } - - return {}; -} - -ErrorOr> DebugInfo::create_variable_info(Dwarf::DIE const& variable_die, PtraceRegisters const& regs, u32 address_offset) const -{ - VERIFY(is_variable_tag_supported(variable_die.tag())); - - if (variable_die.tag() == Dwarf::EntryTag::FormalParameter - && !TRY(variable_die.get_attribute(Dwarf::Attribute::Name)).has_value()) { - // We don't want to display info for unused parameters - return OwnPtr {}; - } - - NonnullOwnPtr variable_info = make(); - auto name_attribute = TRY(variable_die.get_attribute(Dwarf::Attribute::Name)); - if (name_attribute.has_value()) - variable_info->name = TRY(name_attribute.value().as_string()); - - auto type_die = TRY(parse_variable_type_die(variable_die, *variable_info)); - - if (variable_die.tag() == Dwarf::EntryTag::Enumerator) { - auto constant = TRY(variable_die.get_attribute(Dwarf::Attribute::ConstValue)); - VERIFY(constant.has_value()); - switch (constant.value().type()) { - case Dwarf::AttributeValue::Type::UnsignedNumber: - variable_info->constant_data.as_u32 = constant.value().as_unsigned(); - break; - case Dwarf::AttributeValue::Type::SignedNumber: - variable_info->constant_data.as_i32 = constant.value().as_signed(); - break; - case Dwarf::AttributeValue::Type::String: - variable_info->constant_data.as_string = TRY(constant.value().as_string()); - break; - default: - VERIFY_NOT_REACHED(); - } - } else { - TRY(parse_variable_location(variable_die, *variable_info, regs)); - variable_info->location_data.address += address_offset; - } - - if (type_die.has_value()) - TRY(add_type_info_to_variable(type_die.value(), regs, variable_info)); - - return variable_info; -} - -ErrorOr DebugInfo::add_type_info_to_variable(Dwarf::DIE const& type_die, PtraceRegisters const& regs, DebugInfo::VariableInfo* parent_variable) const -{ - OwnPtr type_info; - auto is_array_type = type_die.tag() == Dwarf::EntryTag::ArrayType; - - if (type_die.tag() == Dwarf::EntryTag::EnumerationType - || type_die.tag() == Dwarf::EntryTag::StructureType - || is_array_type) { - type_info = TRY(create_variable_info(type_die, regs)); - } - - TRY(type_die.for_each_child([&](Dwarf::DIE const& member) -> ErrorOr { - if (member.is_null()) - return {}; - - if (is_array_type && member.tag() == Dwarf::EntryTag::SubRangeType) { - auto upper_bound = TRY(member.get_attribute(Dwarf::Attribute::UpperBound)); - VERIFY(upper_bound.has_value()); - auto size = upper_bound.value().as_unsigned() + 1; - type_info->dimension_sizes.append(size); - return {}; - } - - if (!is_variable_tag_supported(member.tag())) - return {}; - - auto member_variable = TRY(create_variable_info(member, regs, parent_variable->location_data.address)); - VERIFY(member_variable); - - if (type_die.tag() == Dwarf::EntryTag::EnumerationType) { - member_variable->parent = type_info.ptr(); - type_info->members.append(member_variable.release_nonnull()); - } else { - if (parent_variable->location_type != DebugInfo::VariableInfo::LocationType::Address) - return {}; - - member_variable->parent = parent_variable; - parent_variable->members.append(member_variable.release_nonnull()); - } - - return {}; - })); - - if (type_info) { - if (is_array_type) { - StringBuilder array_type_name; - array_type_name.append(type_info->type_name); - for (auto array_size : type_info->dimension_sizes) { - array_type_name.append('['); - array_type_name.append(ByteString::formatted("{:d}", array_size)); - array_type_name.append(']'); - } - parent_variable->type_name = array_type_name.to_byte_string(); - } - parent_variable->type = move(type_info); - parent_variable->type->type_tag = type_die.tag(); - } - - return {}; -} - -bool DebugInfo::is_variable_tag_supported(Dwarf::EntryTag const& tag) -{ - return tag == Dwarf::EntryTag::Variable - || tag == Dwarf::EntryTag::Member - || tag == Dwarf::EntryTag::FormalParameter - || tag == Dwarf::EntryTag::EnumerationType - || tag == Dwarf::EntryTag::Enumerator - || tag == Dwarf::EntryTag::StructureType - || tag == Dwarf::EntryTag::ArrayType; -} - -ByteString DebugInfo::name_of_containing_function(FlatPtr address) const -{ - auto function = get_containing_function(address); - if (!function.has_value()) - return {}; - return function.value().name; -} - -Optional DebugInfo::get_containing_function(FlatPtr address) const -{ - for (auto const& scope : m_scopes) { - if (!scope.is_function || address < scope.address_low || address >= scope.address_high) - continue; - return scope; - } - return {}; -} - -Vector DebugInfo::source_lines_in_scope(VariablesScope const& scope) const -{ - Vector source_lines; - for (auto const& line : m_sorted_lines) { - if (line.address < scope.address_low) - continue; - - if (line.address >= scope.address_high) - break; - source_lines.append(SourcePosition::from_line_info(line)); - } - return source_lines; -} - -DebugInfo::SourcePosition DebugInfo::SourcePosition::from_line_info(Dwarf::LineProgram::LineInfo const& line) -{ - return { line.file, line.line, line.address }; -} - -ErrorOr DebugInfo::get_source_position_with_inlines(FlatPtr address) const -{ - // If the address is in an "inline chain", this is the inner-most inlined position. - auto inner_source_position = get_source_position(address); - - auto die = TRY(m_dwarf_info.get_die_at_address(address)); - if (!die.has_value() || die->tag() == Dwarf::EntryTag::SubroutineType) { - // Inline chain is empty - return SourcePositionWithInlines { inner_source_position, {} }; - } - - Vector inline_chain; - - auto insert_to_chain = [&](Dwarf::DIE const& die) -> ErrorOr { - auto caller_source_path = TRY(get_source_path_of_inline(die)); - auto caller_line = TRY(get_line_of_inline(die)); - - if (!caller_source_path.has_value() || !caller_line.has_value()) { - return {}; - } - - inline_chain.append({ ByteString::formatted("{}/{}", caller_source_path->directory, caller_source_path->filename), caller_line.value() }); - return {}; - }; - - while (die->tag() == Dwarf::EntryTag::InlinedSubroutine) { - TRY(insert_to_chain(*die)); - - if (!die->parent_offset().has_value()) { - break; - } - - auto parent = TRY(die->compilation_unit().dwarf_info().get_cached_die_at_offset(die->parent_offset().value())); - if (!parent.has_value()) { - break; - } - die = *parent; - } - - return SourcePositionWithInlines { inner_source_position, inline_chain }; -} - -ErrorOr> DebugInfo::get_source_path_of_inline(Dwarf::DIE const& die) const -{ - auto caller_file = TRY(die.get_attribute(Dwarf::Attribute::CallFile)); - if (caller_file.has_value()) { - size_t file_index = 0; - - if (caller_file->type() == Dwarf::AttributeValue::Type::UnsignedNumber) { - file_index = caller_file->as_unsigned(); - } else if (caller_file->type() == Dwarf::AttributeValue::Type::SignedNumber) { - // For some reason, the file_index is sometimes stored as a signed number. - auto signed_file_index = caller_file->as_signed(); - VERIFY(signed_file_index >= 0); - VERIFY(static_cast(signed_file_index) <= NumericLimits::max()); - file_index = static_cast(caller_file->as_signed()); - } else { - return Optional {}; - } - - return die.compilation_unit().line_program().get_directory_and_file(file_index); - } - return Optional {}; -} - -ErrorOr> DebugInfo::get_line_of_inline(Dwarf::DIE const& die) const -{ - auto caller_line = TRY(die.get_attribute(Dwarf::Attribute::CallLine)); - if (!caller_line.has_value()) - return Optional {}; - - if (caller_line->type() != Dwarf::AttributeValue::Type::UnsignedNumber) - return Optional {}; - return Optional { caller_line.value().as_unsigned() }; -} - -} diff --git a/Userland/Libraries/LibDebug/DebugInfo.h b/Userland/Libraries/LibDebug/DebugInfo.h deleted file mode 100644 index 1fc11492d7f..00000000000 --- a/Userland/Libraries/LibDebug/DebugInfo.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2020-2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Debug { - -class DebugInfo { - AK_MAKE_NONCOPYABLE(DebugInfo); - AK_MAKE_NONMOVABLE(DebugInfo); - -public: - explicit DebugInfo(ELF::Image const&, ByteString source_root = {}, FlatPtr base_address = 0); - - ELF::Image const& elf() const { return m_elf; } - - struct SourcePosition { - DeprecatedFlyString file_path; - size_t line_number { 0 }; - Optional address_of_first_statement; - - SourcePosition() - : SourcePosition(ByteString::empty(), 0) - { - } - SourcePosition(ByteString file_path, size_t line_number) - : file_path(file_path) - , line_number(line_number) - { - } - SourcePosition(ByteString file_path, size_t line_number, FlatPtr address_of_first_statement) - : file_path(file_path) - , line_number(line_number) - , address_of_first_statement(address_of_first_statement) - { - } - - bool operator==(SourcePosition const& other) const { return file_path == other.file_path && line_number == other.line_number; } - - static SourcePosition from_line_info(Dwarf::LineProgram::LineInfo const&); - }; - - struct VariableInfo { - enum class LocationType { - None, - Address, - Register, - }; - ByteString name; - ByteString type_name; - LocationType location_type { LocationType::None }; - union { - FlatPtr address; - } location_data { 0 }; - - union { - u32 as_u32; - u32 as_i32; - char const* as_string; - } constant_data { 0 }; - - Dwarf::EntryTag type_tag; - OwnPtr type; - Vector> members; - VariableInfo* parent { nullptr }; - Vector dimension_sizes; - - bool is_enum_type() const { return type && type->type_tag == Dwarf::EntryTag::EnumerationType; } - }; - - struct VariablesScope { - bool is_function { false }; - ByteString name; - FlatPtr address_low { 0 }; - FlatPtr address_high { 0 }; // Non-inclusive - the lowest address after address_low that's not in this scope - Vector dies_of_variables; - }; - - ErrorOr>> get_variables_in_current_scope(PtraceRegisters const&) const; - - Optional get_source_position(FlatPtr address) const; - - struct SourcePositionWithInlines { - Optional source_position; - Vector inline_chain; - }; - ErrorOr get_source_position_with_inlines(FlatPtr address) const; - - struct SourcePositionAndAddress { - ByteString file; - size_t line; - FlatPtr address; - }; - - Optional get_address_from_source_position(ByteString const& file, size_t line) const; - - ByteString name_of_containing_function(FlatPtr address) const; - Vector source_lines_in_scope(VariablesScope const&) const; - Optional get_containing_function(FlatPtr address) const; - -private: - ErrorOr prepare_variable_scopes(); - ErrorOr prepare_lines(); - ErrorOr parse_scopes_impl(Dwarf::DIE const& die); - ErrorOr> create_variable_info(Dwarf::DIE const& variable_die, PtraceRegisters const&, u32 address_offset = 0) const; - static bool is_variable_tag_supported(Dwarf::EntryTag const& tag); - ErrorOr add_type_info_to_variable(Dwarf::DIE const& type_die, PtraceRegisters const& regs, DebugInfo::VariableInfo* parent_variable) const; - - ErrorOr> get_source_path_of_inline(Dwarf::DIE const&) const; - ErrorOr> get_line_of_inline(Dwarf::DIE const&) const; - - ELF::Image const& m_elf; - ByteString m_source_root; - FlatPtr m_base_address { 0 }; - Dwarf::DwarfInfo m_dwarf_info; - - Vector m_scopes; - Vector m_sorted_lines; -}; - -} diff --git a/Userland/Libraries/LibDebug/DebugSession.cpp b/Userland/Libraries/LibDebug/DebugSession.cpp deleted file mode 100644 index d6b0761a451..00000000000 --- a/Userland/Libraries/LibDebug/DebugSession.cpp +++ /dev/null @@ -1,532 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "DebugSession.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Debug { - -DebugSession::DebugSession(pid_t pid, ByteString source_root, Function on_initialization_progress) - : m_debuggee_pid(pid) - , m_source_root(source_root) - , m_on_initialization_progress(move(on_initialization_progress)) -{ -} - -DebugSession::~DebugSession() -{ - if (m_is_debuggee_dead) - return; - - for (auto const& bp : m_breakpoints) { - disable_breakpoint(bp.key); - } - m_breakpoints.clear(); - - for (auto const& wp : m_watchpoints) { - disable_watchpoint(wp.key); - } - m_watchpoints.clear(); - - if (ptrace(PT_DETACH, m_debuggee_pid, 0, 0) < 0) { - perror("PT_DETACH"); - } -} - -void DebugSession::for_each_loaded_library(Function func) const -{ - for (auto const& lib_name : m_loaded_libraries.keys()) { - auto const& lib = *m_loaded_libraries.get(lib_name).value(); - if (func(lib) == IterationDecision::Break) - break; - } -} - -OwnPtr DebugSession::exec_and_attach(ByteString const& command, - ByteString source_root, - Function()> setup_child, - Function on_initialization_progress) -{ - auto pid = fork(); - - if (pid < 0) { - perror("fork"); - exit(1); - } - - if (!pid) { - - if (setup_child) { - if (setup_child().is_error()) { - perror("DebugSession::setup_child"); - exit(1); - } - } - - if (ptrace(PT_TRACE_ME, 0, 0, 0) < 0) { - perror("PT_TRACE_ME"); - exit(1); - } - - auto parts = command.split(' '); - VERIFY(!parts.is_empty()); - char const** args = bit_cast(calloc(parts.size() + 1, sizeof(char const*))); - for (size_t i = 0; i < parts.size(); i++) { - args[i] = parts[i].characters(); - } - char const** envp = bit_cast(calloc(2, sizeof(char const*))); - // This causes loader to stop on a breakpoint before jumping to the entry point of the program. - envp[0] = "_LOADER_BREAKPOINT=1"; - int rc = execvpe(args[0], const_cast(args), const_cast(envp)); - if (rc < 0) { - perror("execvp"); - exit(1); - } - } - - if (waitpid(pid, nullptr, WSTOPPED) != pid) { - perror("waitpid"); - return {}; - } - - if (ptrace(PT_ATTACH, pid, 0, 0) < 0) { - perror("PT_ATTACH"); - return {}; - } - - // We want to continue until the exit from the 'execve' syscall. - // This ensures that when we start debugging the process - // it executes the target image, and not the forked image of the tracing process. - // NOTE: we only need to do this when we are debugging a new process (i.e not attaching to a process that's already running!) - - if (waitpid(pid, nullptr, WSTOPPED) != pid) { - perror("wait_pid"); - return {}; - } - - auto debug_session = adopt_own(*new DebugSession(pid, source_root, move(on_initialization_progress))); - - // Continue until breakpoint before entry point of main program - int wstatus = debug_session->continue_debuggee_and_wait(); - if (WSTOPSIG(wstatus) != SIGTRAP) { - dbgln("expected SIGTRAP"); - return {}; - } - - // At this point, libraries should have been loaded - auto update_or_error = debug_session->update_loaded_libs(); - if (update_or_error.is_error()) { - dbgln("update failed: {}", update_or_error.error()); - return {}; - } - - return debug_session; -} - -OwnPtr DebugSession::attach(pid_t pid, ByteString source_root, Function on_initialization_progress) -{ - if (ptrace(PT_ATTACH, pid, 0, 0) < 0) { - perror("PT_ATTACH"); - return {}; - } - - int status = 0; - if (waitpid(pid, &status, WSTOPPED | WEXITED) != pid || !WIFSTOPPED(status)) { - perror("waitpid"); - return {}; - } - - auto debug_session = adopt_own(*new DebugSession(pid, source_root, move(on_initialization_progress))); - // At this point, libraries should have been loaded - auto update_or_error = debug_session->update_loaded_libs(); - if (update_or_error.is_error()) { - dbgln("update failed: {}", update_or_error.error()); - return {}; - } - - return debug_session; -} - -bool DebugSession::poke(FlatPtr address, FlatPtr data) -{ - if (ptrace(PT_POKE, m_debuggee_pid, bit_cast(address), bit_cast(data)) < 0) { - perror("PT_POKE"); - return false; - } - return true; -} - -Optional DebugSession::peek(FlatPtr address) const -{ - Optional result; - auto rc = ptrace(PT_PEEK, m_debuggee_pid, bit_cast(address), nullptr); - if (errno == 0) - result = static_cast(rc); - return result; -} - -bool DebugSession::poke_debug(u32 register_index, FlatPtr data) const -{ - if (ptrace(PT_POKEDEBUG, m_debuggee_pid, bit_cast(static_cast(register_index)), bit_cast(data)) < 0) { - perror("PT_POKEDEBUG"); - return false; - } - return true; -} - -Optional DebugSession::peek_debug(u32 register_index) const -{ - auto rc = ptrace(PT_PEEKDEBUG, m_debuggee_pid, bit_cast(static_cast(register_index)), nullptr); - if (errno == 0) - return static_cast(rc); - - return {}; -} - -bool DebugSession::insert_breakpoint(FlatPtr address) -{ - // We insert a software breakpoint by - // patching the first byte of the instruction at 'address' - // with the breakpoint instruction (int3) - - if (m_breakpoints.contains(address)) - return false; - - auto original_bytes = peek(address); - - if (!original_bytes.has_value()) - return false; - - VERIFY((original_bytes.value() & 0xff) != BREAKPOINT_INSTRUCTION); - - BreakPoint breakpoint { address, original_bytes.value(), BreakPointState::Disabled }; - - m_breakpoints.set(address, breakpoint); - - enable_breakpoint(breakpoint.address); - - return true; -} - -bool DebugSession::disable_breakpoint(FlatPtr address) -{ - auto breakpoint = m_breakpoints.get(address); - VERIFY(breakpoint.has_value()); - if (!poke(breakpoint.value().address, breakpoint.value().original_first_word)) - return false; - - auto bp = m_breakpoints.get(breakpoint.value().address).value(); - bp.state = BreakPointState::Disabled; - m_breakpoints.set(bp.address, bp); - return true; -} - -bool DebugSession::enable_breakpoint(FlatPtr address) -{ - auto breakpoint = m_breakpoints.get(address); - VERIFY(breakpoint.has_value()); - - VERIFY(breakpoint.value().state == BreakPointState::Disabled); - - if (!poke(breakpoint.value().address, (breakpoint.value().original_first_word & ~static_cast(0xff)) | BREAKPOINT_INSTRUCTION)) - return false; - - auto bp = m_breakpoints.get(breakpoint.value().address).value(); - bp.state = BreakPointState::Enabled; - m_breakpoints.set(bp.address, bp); - return true; -} - -bool DebugSession::remove_breakpoint(FlatPtr address) -{ - if (!disable_breakpoint(address)) - return false; - - m_breakpoints.remove(address); - return true; -} - -bool DebugSession::breakpoint_exists(FlatPtr address) const -{ - return m_breakpoints.contains(address); -} - -bool DebugSession::insert_watchpoint(FlatPtr address, u32 ebp) -{ - auto current_register_status = peek_debug(DEBUG_CONTROL_REGISTER); - if (!current_register_status.has_value()) - return false; - // FIXME: 64 bit support - u32 dr7_value = static_cast(current_register_status.value()); - u32 next_available_index; - for (next_available_index = 0; next_available_index < 4; next_available_index++) { - auto bitmask = 1 << (next_available_index * 2); - if ((dr7_value & bitmask) == 0) - break; - } - if (next_available_index > 3) - return false; - WatchPoint watchpoint { address, next_available_index, ebp }; - - if (!poke_debug(next_available_index, bit_cast(address))) - return false; - - dr7_value |= (1u << (next_available_index * 2)); // Enable local breakpoint for our index - auto condition_shift = 16 + (next_available_index * 4); - dr7_value &= ~(0b11u << condition_shift); - dr7_value |= 1u << condition_shift; // Trigger on writes - auto length_shift = 18 + (next_available_index * 4); - dr7_value &= ~(0b11u << length_shift); - // FIXME: take variable size into account? - dr7_value |= 0b11u << length_shift; // 4 bytes wide - if (!poke_debug(DEBUG_CONTROL_REGISTER, dr7_value)) - return false; - - m_watchpoints.set(address, watchpoint); - return true; -} - -bool DebugSession::remove_watchpoint(FlatPtr address) -{ - if (!disable_watchpoint(address)) - return false; - return m_watchpoints.remove(address); -} - -bool DebugSession::disable_watchpoint(FlatPtr address) -{ - VERIFY(watchpoint_exists(address)); - auto watchpoint = m_watchpoints.get(address).value(); - if (!poke_debug(watchpoint.debug_register_index, 0)) - return false; - auto current_register_status = peek_debug(DEBUG_CONTROL_REGISTER); - if (!current_register_status.has_value()) - return false; - u32 dr7_value = current_register_status.value(); - dr7_value &= ~(1u << watchpoint.debug_register_index * 2); - if (!poke_debug(watchpoint.debug_register_index, dr7_value)) - return false; - return true; -} - -bool DebugSession::watchpoint_exists(FlatPtr address) const -{ - return m_watchpoints.contains(address); -} - -PtraceRegisters DebugSession::get_registers() const -{ - PtraceRegisters regs; - if (ptrace(PT_GETREGS, m_debuggee_pid, ®s, 0) < 0) { - perror("PT_GETREGS"); - VERIFY_NOT_REACHED(); - } - return regs; -} - -void DebugSession::set_registers(PtraceRegisters const& regs) -{ - if (ptrace(PT_SETREGS, m_debuggee_pid, bit_cast(®s), 0) < 0) { - perror("PT_SETREGS"); - VERIFY_NOT_REACHED(); - } -} - -void DebugSession::continue_debuggee(ContinueType type) -{ - int command = (type == ContinueType::FreeRun) ? PT_CONTINUE : PT_SYSCALL; - if (ptrace(command, m_debuggee_pid, 0, 0) < 0) { - perror("continue"); - VERIFY_NOT_REACHED(); - } -} - -int DebugSession::continue_debuggee_and_wait(ContinueType type) -{ - continue_debuggee(type); - int wstatus = 0; - if (waitpid(m_debuggee_pid, &wstatus, WSTOPPED | WEXITED) != m_debuggee_pid) { - perror("waitpid"); - VERIFY_NOT_REACHED(); - } - return wstatus; -} - -FlatPtr DebugSession::single_step() -{ - // Single stepping works by setting the x86 TRAP flag bit in the eflags register. - // This flag causes the cpu to enter single-stepping mode, which causes - // Interrupt 1 (debug interrupt) to be emitted after every instruction. - // To single step the program, we set the TRAP flag and continue the debuggee. - // After the debuggee has stopped, we clear the TRAP flag. - - auto regs = get_registers(); -#if ARCH(X86_64) - constexpr u32 TRAP_FLAG = 0x100; - regs.rflags |= TRAP_FLAG; -#elif ARCH(AARCH64) - TODO_AARCH64(); -#elif ARCH(RISCV64) - TODO_RISCV64(); -#else -# error Unknown architecture -#endif - set_registers(regs); - - continue_debuggee(); - - if (waitpid(m_debuggee_pid, 0, WSTOPPED) != m_debuggee_pid) { - perror("waitpid"); - VERIFY_NOT_REACHED(); - } - - regs = get_registers(); -#if ARCH(X86_64) - regs.rflags &= ~(TRAP_FLAG); -#elif ARCH(AARCH64) - TODO_AARCH64(); -#elif ARCH(RISCV64) - TODO_RISCV64(); -#else -# error Unknown architecture -#endif - set_registers(regs); - return regs.ip(); -} - -void DebugSession::detach() -{ - for (auto& breakpoint : m_breakpoints.keys()) { - remove_breakpoint(breakpoint); - } - for (auto& watchpoint : m_watchpoints.keys()) - remove_watchpoint(watchpoint); - continue_debuggee(); -} - -Optional DebugSession::insert_breakpoint(ByteString const& symbol_name) -{ - Optional result; - for_each_loaded_library([this, symbol_name, &result](auto& lib) { - // The loader contains its own definitions for LibC symbols, so we don't want to include it in the search. - if (lib.name == "Loader.so") - return IterationDecision::Continue; - - auto symbol = lib.debug_info->elf().find_demangled_function(symbol_name); - if (!symbol.has_value()) - return IterationDecision::Continue; - - FlatPtr breakpoint_address = symbol->value() + lib.base_address; - bool rc = this->insert_breakpoint(breakpoint_address); - if (!rc) - return IterationDecision::Break; - - result = InsertBreakpointAtSymbolResult { lib.name, breakpoint_address }; - return IterationDecision::Break; - }); - return result; -} - -Optional DebugSession::insert_breakpoint(ByteString const& filename, size_t line_number) -{ - auto address_and_source_position = get_address_from_source_position(filename, line_number); - if (!address_and_source_position.has_value()) - return {}; - - auto address = address_and_source_position.value().address; - bool rc = this->insert_breakpoint(address); - if (!rc) - return {}; - - auto lib = library_at(address); - VERIFY(lib); - - return InsertBreakpointAtSourcePositionResult { lib->name, address_and_source_position.value().file, address_and_source_position.value().line, address }; -} - -ErrorOr DebugSession::update_loaded_libs() -{ - auto file_name = TRY(String::formatted("/proc/{}/vm", m_debuggee_pid)); - auto file = TRY(Core::File::open(file_name, Core::File::OpenMode::Read)); - - auto file_contents = TRY(file->read_until_eof()); - auto json = TRY(JsonValue::from_string(file_contents)); - - auto const& vm_entries = json.as_array(); - Regex segment_name_re("(.+): "); - - auto get_path_to_object = [&segment_name_re](ByteString const& vm_name) -> Optional { - if (vm_name == "/usr/lib/Loader.so") - return vm_name; - RegexResult result; - auto rc = segment_name_re.search(vm_name, result); - if (!rc) - return {}; - auto lib_name = result.capture_group_matches.at(0).at(0).view.string_view().to_byte_string(); - if (lib_name.starts_with('/')) - return lib_name; - return ByteString::formatted("/usr/lib/{}", lib_name); - }; - - ScopeGuard progress_guard([this]() { - if (m_on_initialization_progress) - m_on_initialization_progress(0); - }); - - size_t vm_entry_index = 0; - - vm_entries.for_each([&](auto& entry) { - ++vm_entry_index; - if (m_on_initialization_progress) - m_on_initialization_progress(vm_entry_index / static_cast(vm_entries.size())); - - // TODO: check that region is executable - auto vm_name = entry.as_object().get_byte_string("name"sv).value(); - - auto object_path = get_path_to_object(vm_name); - if (!object_path.has_value()) - return IterationDecision::Continue; - - ByteString lib_name = object_path.value(); - if (FileSystem::looks_like_shared_library(lib_name)) - lib_name = LexicalPath::basename(object_path.value()); - - FlatPtr base_address = entry.as_object().get_addr("address"sv).value_or(0); - if (auto it = m_loaded_libraries.find(lib_name); it != m_loaded_libraries.end()) { - // We expect the VM regions to be sorted by address. - VERIFY(base_address >= it->value->base_address); - return IterationDecision::Continue; - } - - auto file_or_error = Core::MappedFile::map(object_path.value()); - if (file_or_error.is_error()) - return IterationDecision::Continue; - - auto image = make(file_or_error.value()->bytes()); - auto debug_info = make(*image, m_source_root, base_address); - auto lib = make(lib_name, file_or_error.release_value(), move(image), move(debug_info), base_address); - m_loaded_libraries.set(lib_name, move(lib)); - - return IterationDecision::Continue; - }); - - return {}; -} - -void DebugSession::stop_debuggee() -{ - kill(pid(), SIGSTOP); -} - -} diff --git a/Userland/Libraries/LibDebug/DebugSession.h b/Userland/Libraries/LibDebug/DebugSession.h deleted file mode 100644 index cf69c34d744..00000000000 --- a/Userland/Libraries/LibDebug/DebugSession.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Debug { - -class DebugSession : public ProcessInspector { -public: - static OwnPtr exec_and_attach(ByteString const& command, ByteString source_root = {}, Function()> setup_child = {}, Function on_initialization_progress = {}); - static OwnPtr attach(pid_t pid, ByteString source_root = {}, Function on_initialization_progress = {}); - - virtual ~DebugSession() override; - - // ^Debug::ProcessInspector - virtual bool poke(FlatPtr address, FlatPtr data) override; - virtual Optional peek(FlatPtr address) const override; - virtual PtraceRegisters get_registers() const override; - virtual void set_registers(PtraceRegisters const&) override; - virtual void for_each_loaded_library(Function) const override; - - int pid() const { return m_debuggee_pid; } - - bool poke_debug(u32 register_index, FlatPtr data) const; - Optional peek_debug(u32 register_index) const; - - enum class BreakPointState { - Enabled, - Disabled, - }; - - struct BreakPoint { - FlatPtr address { 0 }; - FlatPtr original_first_word { 0 }; - BreakPointState state { BreakPointState::Disabled }; - }; - - struct InsertBreakpointAtSymbolResult { - ByteString library_name; - FlatPtr address { 0 }; - }; - - Optional insert_breakpoint(ByteString const& symbol_name); - - struct InsertBreakpointAtSourcePositionResult { - ByteString library_name; - ByteString filename; - size_t line_number { 0 }; - FlatPtr address { 0 }; - }; - - Optional insert_breakpoint(ByteString const& filename, size_t line_number); - - bool insert_breakpoint(FlatPtr address); - bool disable_breakpoint(FlatPtr address); - bool enable_breakpoint(FlatPtr address); - bool remove_breakpoint(FlatPtr address); - bool breakpoint_exists(FlatPtr address) const; - - struct WatchPoint { - FlatPtr address { 0 }; - u32 debug_register_index { 0 }; - u32 ebp { 0 }; - }; - - bool insert_watchpoint(FlatPtr address, u32 ebp); - bool remove_watchpoint(FlatPtr address); - bool disable_watchpoint(FlatPtr address); - bool watchpoint_exists(FlatPtr address) const; - - void dump_breakpoints() - { - for (auto addr : m_breakpoints.keys()) { - dbgln("{}", addr); - } - } - - enum class ContinueType { - FreeRun, - Syscall, - }; - void continue_debuggee(ContinueType type = ContinueType::FreeRun); - void stop_debuggee(); - - // Returns the wstatus result of waitpid() - int continue_debuggee_and_wait(ContinueType type = ContinueType::FreeRun); - - // Returns the new eip - FlatPtr single_step(); - - void detach(); - - enum DesiredInitialDebugeeState { - Running, - Stopped - }; - template - void run(DesiredInitialDebugeeState, Callback); - - enum DebugDecision { - Continue, - SingleStep, - ContinueBreakAtSyscall, - Detach, - Kill, - }; - - enum DebugBreakReason { - Breakpoint, - Syscall, - Exited, - }; - -private: - explicit DebugSession(pid_t, ByteString source_root, Function on_initialization_progress = {}); - - // x86 breakpoint instruction "int3" - static constexpr u8 BREAKPOINT_INSTRUCTION = 0xcc; - - ErrorOr update_loaded_libs(); - - int m_debuggee_pid { -1 }; - ByteString m_source_root; - bool m_is_debuggee_dead { false }; - - HashMap m_breakpoints; - HashMap m_watchpoints; - - // Maps from library name to LoadedLibrary object - HashMap> m_loaded_libraries; - - Function m_on_initialization_progress; -}; - -template -void DebugSession::run(DesiredInitialDebugeeState initial_debugee_state, Callback callback) -{ - enum class State { - FirstIteration, - FreeRun, - Syscall, - ConsecutiveBreakpoint, - SingleStep, - }; - - State state { State::FirstIteration }; - - auto do_continue_and_wait = [&]() { - int wstatus = continue_debuggee_and_wait((state == State::Syscall) ? ContinueType::Syscall : ContinueType::FreeRun); - - // FIXME: This check actually only checks whether the debuggee - // stopped because it hit a breakpoint/syscall/is in single stepping mode or not - if (WSTOPSIG(wstatus) != SIGTRAP && WSTOPSIG(wstatus) != SIGSTOP) { - callback(DebugBreakReason::Exited, Optional()); - m_is_debuggee_dead = true; - return true; - } - return false; - }; - - for (;;) { - if ((state == State::FirstIteration && initial_debugee_state == DesiredInitialDebugeeState::Running) || state == State::FreeRun || state == State::Syscall) { - if (do_continue_and_wait()) - break; - } - if (state == State::FirstIteration) - state = State::FreeRun; - - auto regs = get_registers(); - -#if ARCH(X86_64) - FlatPtr current_instruction = regs.rip; -#elif ARCH(AARCH64) - FlatPtr current_instruction; - TODO_AARCH64(); -#elif ARCH(RISCV64) - FlatPtr current_instruction; - TODO_RISCV64(); -#else -# error Unknown architecture -#endif - - auto debug_status = peek_debug(DEBUG_STATUS_REGISTER); - if (debug_status.has_value() && (debug_status.value() & 0b1111) > 0) { - // Tripped a watchpoint - auto watchpoint_index = debug_status.value() & 0b1111; - Optional watchpoint {}; - for (auto wp : m_watchpoints) { - if ((watchpoint_index & (1 << wp.value.debug_register_index)) == 0) - continue; - watchpoint = wp.value; - break; - } - if (watchpoint.has_value()) { - auto required_ebp = watchpoint.value().ebp; - auto found_ebp = false; - -#if ARCH(X86_64) - FlatPtr current_ebp = regs.rbp; -#elif ARCH(AARCH64) - FlatPtr current_ebp; - TODO_AARCH64(); -#elif ARCH(RISCV64) - FlatPtr current_ebp; - TODO_RISCV64(); -#else -# error Unknown architecture -#endif - - // FIXME: Use AK::unwind_stack_from_frame_pointer - do { - if (current_ebp == required_ebp) { - found_ebp = true; - break; - } - auto return_address = peek(current_ebp + sizeof(FlatPtr)); - auto next_ebp = peek(current_ebp); - VERIFY(return_address.has_value()); - VERIFY(next_ebp.has_value()); - current_instruction = return_address.value(); - current_ebp = next_ebp.value(); - } while (current_ebp && current_instruction); - - if (!found_ebp) { - dbgln("Removing watchpoint at {:p} because it went out of scope!", watchpoint.value().address); - remove_watchpoint(watchpoint.value().address); - continue; - } - } - } - - Optional current_breakpoint; - - if (state == State::FreeRun || state == State::Syscall) { - current_breakpoint = m_breakpoints.get(current_instruction - 1); - if (current_breakpoint.has_value()) - state = State::FreeRun; - } else { - current_breakpoint = m_breakpoints.get(current_instruction); - } - - if (current_breakpoint.has_value()) { - // We want to make the breakpoint transparent to the user of the debugger. - // To achieve this, we perform two rollbacks: - // 1. Set regs.eip to point at the actual address of the instruction we broke on. - // regs.eip currently points to one byte after the address of the original instruction, - // because the cpu has just executed the INT3 we patched into the instruction. - // 2. We restore the original first byte of the instruction, - // because it was patched with INT3. - auto breakpoint_addr = bit_cast(current_breakpoint.value().address); -#if ARCH(X86_64) - regs.rip = breakpoint_addr; -#elif ARCH(AARCH64) - (void)breakpoint_addr; - TODO_AARCH64(); -#elif ARCH(RISCV64) - (void)breakpoint_addr; - TODO_RISCV64(); -#else -# error Unknown architecture -#endif - set_registers(regs); - disable_breakpoint(current_breakpoint.value().address); - } - - DebugBreakReason reason = (state == State::Syscall && !current_breakpoint.has_value()) ? DebugBreakReason::Syscall : DebugBreakReason::Breakpoint; - - DebugDecision decision = callback(reason, regs); - - if (reason == DebugBreakReason::Syscall) { - // skip the exit from the syscall - if (do_continue_and_wait()) - break; - } - - if (decision == DebugDecision::Continue) { - state = State::FreeRun; - } else if (decision == DebugDecision::ContinueBreakAtSyscall) { - state = State::Syscall; - } - - bool did_single_step = false; - - // Re-enable the breakpoint if it wasn't removed by the user - if (current_breakpoint.has_value()) { - auto current_breakpoint_address = bit_cast(current_breakpoint.value().address); - if (m_breakpoints.contains(current_breakpoint_address)) { - // The current breakpoint was removed to make it transparent to the user. - // We now want to re-enable it - the code execution flow could hit it again. - // To re-enable the breakpoint, we first perform a single step and execute the - // instruction of the breakpoint, and then redo the INT3 patch in its first byte. - - // If the user manually inserted a breakpoint at the current instruction, - // we need to disable that breakpoint because we want to singlestep over that - // instruction (we re-enable it again later anyways). - if (m_breakpoints.contains(current_breakpoint_address) && m_breakpoints.get(current_breakpoint_address).value().state == BreakPointState::Enabled) { - disable_breakpoint(current_breakpoint.value().address); - } - auto stopped_address = single_step(); - enable_breakpoint(current_breakpoint.value().address); - did_single_step = true; - // If there is another breakpoint after the current one, - // Then we are already on it (because of single_step) - auto breakpoint_at_next_instruction = m_breakpoints.get(stopped_address); - if (breakpoint_at_next_instruction.has_value() - && breakpoint_at_next_instruction.value().state == BreakPointState::Enabled) { - state = State::ConsecutiveBreakpoint; - } - } - } - - if (decision == DebugDecision::SingleStep) { - state = State::SingleStep; - } - - if (decision == DebugDecision::Detach) { - detach(); - break; - } - if (decision == DebugDecision::Kill) { - kill(m_debuggee_pid, SIGTERM); - break; - } - - if (state == State::SingleStep && !did_single_step) { - single_step(); - } - } -} - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/AbbreviationsMap.cpp b/Userland/Libraries/LibDebug/Dwarf/AbbreviationsMap.cpp deleted file mode 100644 index 67f926a43e5..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/AbbreviationsMap.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "AbbreviationsMap.h" -#include "DwarfInfo.h" - -#include -#include - -namespace Debug::Dwarf { - -AbbreviationsMap::AbbreviationsMap(DwarfInfo const& dwarf_info, u32 offset) - : m_dwarf_info(dwarf_info) - , m_offset(offset) -{ - populate_map().release_value_but_fixme_should_propagate_errors(); -} - -ErrorOr AbbreviationsMap::populate_map() -{ - FixedMemoryStream abbreviation_stream { m_dwarf_info.abbreviation_data() }; - TRY(abbreviation_stream.discard(m_offset)); - - while (!abbreviation_stream.is_eof()) { - size_t abbreviation_code = TRY(abbreviation_stream.read_value>()); - // An abbreviation code of 0 marks the end of the - // abbreviations for a given compilation unit - if (abbreviation_code == 0) - break; - - size_t tag = TRY(abbreviation_stream.read_value>()); - - auto has_children = TRY(abbreviation_stream.read_value()); - - AbbreviationEntry abbreviation_entry {}; - abbreviation_entry.tag = static_cast(tag); - abbreviation_entry.has_children = (has_children == 1); - - AttributeSpecification current_attribute_specification {}; - do { - size_t attribute_value = TRY(abbreviation_stream.read_value>()); - size_t form_value = TRY(abbreviation_stream.read_value>()); - - current_attribute_specification.attribute = static_cast(attribute_value); - current_attribute_specification.form = static_cast(form_value); - - if (current_attribute_specification.form == AttributeDataForm::ImplicitConst) { - ssize_t data_value = TRY(abbreviation_stream.read_value>()); - current_attribute_specification.value = data_value; - } - - if (current_attribute_specification.attribute != Attribute::None) { - abbreviation_entry.attribute_specifications.append(current_attribute_specification); - } - } while (current_attribute_specification.attribute != Attribute::None || current_attribute_specification.form != AttributeDataForm::None); - - m_entries.set(static_cast(abbreviation_code), move(abbreviation_entry)); - } - - return {}; -} - -AbbreviationsMap::AbbreviationEntry const* AbbreviationsMap::get(u32 code) const -{ - auto it = m_entries.find(code); - if (it == m_entries.end()) { - return nullptr; - } - return &it->value; -} - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/AbbreviationsMap.h b/Userland/Libraries/LibDebug/Dwarf/AbbreviationsMap.h deleted file mode 100644 index 64306f57287..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/AbbreviationsMap.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "DwarfTypes.h" -#include -#include -#include - -namespace Debug::Dwarf { - -class DwarfInfo; - -class AbbreviationsMap { -public: - AbbreviationsMap(DwarfInfo const& dwarf_info, u32 offset); - - struct AbbreviationEntry { - EntryTag tag; - bool has_children; - - Vector attribute_specifications; - }; - AbbreviationEntry const* get(u32 code) const; - -private: - ErrorOr populate_map(); - - DwarfInfo const& m_dwarf_info; - u32 m_offset { 0 }; - HashMap m_entries; -}; - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp b/Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp deleted file mode 100644 index 53dc83cb21c..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/AddressRanges.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2020-2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "AddressRanges.h" -#include "DwarfTypes.h" -#include - -namespace Debug::Dwarf { - -AddressRangesV5::AddressRangesV5(NonnullOwnPtr range_lists_stream, CompilationUnit const& compilation_unit) - : m_range_lists_stream(move(range_lists_stream)) - , m_compilation_unit(compilation_unit) -{ -} - -ErrorOr AddressRangesV5::for_each_range(Function callback) -{ - // Dwarf version 5, section 2.17.3 "Non-Contiguous Address Ranges" - - Optional current_base_address; - while (!m_range_lists_stream->is_eof()) { - auto entry_type = TRY(m_range_lists_stream->read_value()); - switch (static_cast(entry_type)) { - case RangeListEntryType::BaseAddress: { - current_base_address = TRY(m_range_lists_stream->read_value()); - break; - } - case RangeListEntryType::BaseAddressX: { - FlatPtr index = TRY(m_range_lists_stream->read_value>()); - current_base_address = TRY(m_compilation_unit.get_address(index)); - break; - } - case RangeListEntryType::OffsetPair: { - Optional base_address = current_base_address; - if (!base_address.has_value()) { - base_address = TRY(m_compilation_unit.base_address()); - } - - if (!base_address.has_value()) - return Error::from_string_literal("Expected base_address for rangelist"); - - size_t start_offset = TRY(m_range_lists_stream->read_value>()); - size_t end_offset = TRY(m_range_lists_stream->read_value>()); - callback(Range { start_offset + *base_address, end_offset + *base_address }); - break; - } - case RangeListEntryType::StartLength: { - auto start = TRY(m_range_lists_stream->read_value()); - size_t length = TRY(m_range_lists_stream->read_value>()); - callback(Range { start, start + length }); - break; - } - case RangeListEntryType::StartXEndX: { - size_t start = TRY(m_range_lists_stream->read_value>()); - size_t end = TRY(m_range_lists_stream->read_value>()); - callback(Range { TRY(m_compilation_unit.get_address(start)), TRY(m_compilation_unit.get_address(end)) }); - break; - } - case RangeListEntryType::StartXLength: { - size_t start = TRY(m_range_lists_stream->read_value>()); - size_t length = TRY(m_range_lists_stream->read_value>()); - auto start_addr = TRY(m_compilation_unit.get_address(start)); - callback(Range { start_addr, start_addr + length }); - break; - } - case RangeListEntryType::EndOfList: - return {}; - default: - dbgln("unsupported range list entry type: {:#x}", entry_type); - return Error::from_string_literal("Unsupported range list entry type"); - } - } - - return {}; -} - -AddressRangesV4::AddressRangesV4(NonnullOwnPtr ranges_stream, CompilationUnit const& compilation_unit) - : m_ranges_stream(move(ranges_stream)) - , m_compilation_unit(compilation_unit) -{ -} - -ErrorOr AddressRangesV4::for_each_range(Function callback) -{ - // Dwarf version 4, section 2.17.3 "Non-Contiguous Address Ranges" - - Optional current_base_address; - while (!m_ranges_stream->is_eof()) { - auto begin = TRY(m_ranges_stream->read_value()); - auto end = TRY(m_ranges_stream->read_value()); - - if (begin == 0 && end == 0) { - // end of list entry - return {}; - } else if (begin == explode_byte(0xff)) { - current_base_address = end; - } else { - FlatPtr base = current_base_address.value_or(TRY(m_compilation_unit.base_address()).value_or(0)); - callback({ base + begin, base + end }); - } - } - - return {}; -} - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/AddressRanges.h b/Userland/Libraries/LibDebug/Dwarf/AddressRanges.h deleted file mode 100644 index 8b8ec7b15b4..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/AddressRanges.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2020-2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "CompilationUnit.h" -#include -#include -#include - -namespace Debug::Dwarf { - -struct Range { - FlatPtr start { 0 }; - FlatPtr end { 0 }; -}; - -class AddressRangesV5 { - AK_MAKE_NONCOPYABLE(AddressRangesV5); - AK_MAKE_NONMOVABLE(AddressRangesV5); - -public: - // FIXME: This should be fine with using a non-owned stream. - AddressRangesV5(NonnullOwnPtr range_lists_stream, CompilationUnit const& compilation_unit); - - ErrorOr for_each_range(Function); - -private: - NonnullOwnPtr m_range_lists_stream; - CompilationUnit const& m_compilation_unit; -}; - -class AddressRangesV4 { - AK_MAKE_NONCOPYABLE(AddressRangesV4); - AK_MAKE_NONMOVABLE(AddressRangesV4); - -public: - AddressRangesV4(NonnullOwnPtr ranges_stream, CompilationUnit const&); - - ErrorOr for_each_range(Function); - -private: - NonnullOwnPtr m_ranges_stream; - CompilationUnit const& m_compilation_unit; -}; - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/AttributeValue.cpp b/Userland/Libraries/LibDebug/Dwarf/AttributeValue.cpp deleted file mode 100644 index 966820b8c6f..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/AttributeValue.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2021, Daniel Bertalan - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "AttributeValue.h" -#include "CompilationUnit.h" - -namespace Debug::Dwarf { - -ErrorOr AttributeValue::as_addr() const -{ - switch (m_form) { - case AttributeDataForm::Addr: - return m_data.as_addr; - case AttributeDataForm::AddrX: - case AttributeDataForm::AddrX1: - case AttributeDataForm::AddrX2: - case AttributeDataForm::AddrX3: - case AttributeDataForm::AddrX4: { - auto index = m_data.as_unsigned; - return m_compilation_unit->get_address(index); - } - default: - VERIFY_NOT_REACHED(); - } -} - -ErrorOr AttributeValue::as_string() const -{ - switch (m_form) { - case AttributeDataForm::String: - case AttributeDataForm::StringPointer: - case AttributeDataForm::LineStrP: - return m_data.as_string; - case AttributeDataForm::StrX: - case AttributeDataForm::StrX1: - case AttributeDataForm::StrX2: - case AttributeDataForm::StrX3: - case AttributeDataForm::StrX4: { - auto index = m_data.as_unsigned; - return m_compilation_unit->get_string(index); - } - default: - VERIFY_NOT_REACHED(); - } -} -} diff --git a/Userland/Libraries/LibDebug/Dwarf/AttributeValue.h b/Userland/Libraries/LibDebug/Dwarf/AttributeValue.h deleted file mode 100644 index 6e2e6fcfb1a..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/AttributeValue.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace Debug::Dwarf { - -class CompilationUnit; - -class AttributeValue { - friend class DwarfInfo; - -public: - enum class Type : u8 { - UnsignedNumber, - SignedNumber, - String, - DieReference, // Reference to another DIE in the same compilation unit - Boolean, - DwarfExpression, - SecOffset, - RawBytes, - Address - }; - - Type type() const { return m_type; } - AttributeDataForm form() const { return m_form; } - - ErrorOr as_addr() const; - u64 as_unsigned() const { return m_data.as_unsigned; } - i64 as_signed() const { return m_data.as_signed; } - ErrorOr as_string() const; - bool as_bool() const { return m_data.as_bool; } - ReadonlyBytes as_raw_bytes() const { return m_data.as_raw_bytes; } - -private: - Type m_type; - union { - FlatPtr as_addr; - u64 as_unsigned; - i64 as_signed; - char const* as_string; // points to bytes in the memory mapped elf image - bool as_bool; - ReadonlyBytes as_raw_bytes; - } m_data {}; - - AttributeDataForm m_form {}; - - CompilationUnit const* m_compilation_unit { nullptr }; -}; - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.cpp b/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.cpp deleted file mode 100644 index 1539c2ed33a..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "CompilationUnit.h" -#include -#include -#include -#include -#include - -namespace Debug::Dwarf { - -CompilationUnit::CompilationUnit(DwarfInfo const& dwarf_info, u32 offset, CompilationUnitHeader const& header) - : m_dwarf_info(dwarf_info) - , m_offset(offset) - , m_header(header) - , m_abbreviations(dwarf_info, header.abbrev_offset()) -{ - VERIFY(header.version() < 5 || header.unit_type() == CompilationUnitType::Full); -} - -ErrorOr> CompilationUnit::create(DwarfInfo const& dwarf_info, u32 offset, CompilationUnitHeader const& header, ReadonlyBytes debug_line_data) -{ - auto compilation_unit = TRY(adopt_nonnull_own_or_enomem(new (nothrow) CompilationUnit(dwarf_info, offset, header))); - TRY(compilation_unit->populate_line_program(debug_line_data)); - return compilation_unit; -} - -ErrorOr CompilationUnit::populate_line_program(ReadonlyBytes debug_line_data) -{ - auto die = root_die(); - - auto res = TRY(die.get_attribute(Attribute::StmtList)); - if (!res.has_value()) - return EINVAL; - VERIFY(res->form() == AttributeDataForm::SecOffset); - - FixedMemoryStream debug_line_stream { debug_line_data }; - TRY(debug_line_stream.seek(res->as_unsigned())); - - m_line_program = TRY(LineProgram::create(m_dwarf_info, debug_line_stream)); - - return {}; -} - -CompilationUnit::~CompilationUnit() = default; - -DIE CompilationUnit::root_die() const -{ - return DIE(*this, m_offset + m_header.header_size()); -} - -DIE CompilationUnit::get_die_at_offset(u32 die_offset) const -{ - VERIFY(die_offset >= offset() && die_offset < offset() + size()); - return DIE(*this, die_offset); -} - -LineProgram const& CompilationUnit::line_program() const -{ - return *m_line_program; -} - -ErrorOr> CompilationUnit::base_address() const -{ - if (m_has_cached_base_address) - return m_cached_base_address; - - auto die = root_die(); - auto res = TRY(die.get_attribute(Attribute::LowPc)); - if (res.has_value()) { - m_cached_base_address = TRY(res->as_addr()); - } - m_has_cached_base_address = true; - return m_cached_base_address; -} - -ErrorOr CompilationUnit::address_table_base() const -{ - if (m_has_cached_address_table_base) - return m_cached_address_table_base; - - auto die = root_die(); - auto res = TRY(die.get_attribute(Attribute::AddrBase)); - if (res.has_value()) { - VERIFY(res->form() == AttributeDataForm::SecOffset); - m_cached_address_table_base = res->as_unsigned(); - } - m_has_cached_address_table_base = true; - return m_cached_address_table_base; -} - -ErrorOr CompilationUnit::string_offsets_base() const -{ - if (m_has_cached_string_offsets_base) - return m_cached_string_offsets_base; - - auto die = root_die(); - auto res = TRY(die.get_attribute(Attribute::StrOffsetsBase)); - if (res.has_value()) { - VERIFY(res->form() == AttributeDataForm::SecOffset); - m_cached_string_offsets_base = res->as_unsigned(); - } - m_has_cached_string_offsets_base = true; - return m_cached_string_offsets_base; -} - -ErrorOr CompilationUnit::range_lists_base() const -{ - if (m_has_cached_range_lists_base) - return m_cached_range_lists_base; - - auto die = root_die(); - auto res = TRY(die.get_attribute(Attribute::RngListsBase)); - if (res.has_value()) { - VERIFY(res->form() == AttributeDataForm::SecOffset); - m_cached_range_lists_base = res->as_unsigned(); - } - m_has_cached_range_lists_base = true; - return m_cached_range_lists_base; -} - -ErrorOr CompilationUnit::get_address(size_t index) const -{ - auto base = TRY(address_table_base()); - auto debug_addr_data = dwarf_info().debug_addr_data(); - VERIFY(base < debug_addr_data.size()); - auto addresses = debug_addr_data.slice(base); - VERIFY(index * sizeof(FlatPtr) < addresses.size()); - FlatPtr value { 0 }; - ByteReader::load(addresses.offset_pointer(index * sizeof(FlatPtr)), value); - return value; -} - -ErrorOr CompilationUnit::get_string(size_t index) const -{ - auto base = TRY(string_offsets_base()); - auto debug_str_offsets_data = dwarf_info().debug_str_offsets_data(); - VERIFY(base < debug_str_offsets_data.size()); - // FIXME: This assumes DWARF32 - auto offsets = debug_str_offsets_data.slice(base); - VERIFY(index * sizeof(u32) < offsets.size()); - auto offset = ByteReader::load32(offsets.offset_pointer(index * sizeof(u32))); - return bit_cast(dwarf_info().debug_strings_data().offset(offset)); -} -} diff --git a/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h b/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h deleted file mode 100644 index f8d8c850b54..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/CompilationUnit.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "AbbreviationsMap.h" -#include -#include -#include - -namespace Debug::Dwarf { - -class DwarfInfo; -class DIE; -class LineProgram; - -class CompilationUnit { - AK_MAKE_NONCOPYABLE(CompilationUnit); - AK_MAKE_NONMOVABLE(CompilationUnit); - -public: - static ErrorOr> create(DwarfInfo const& dwarf_info, u32 offset, CompilationUnitHeader const&, ReadonlyBytes debug_line_data); - ~CompilationUnit(); - - u32 offset() const { return m_offset; } - u32 size() const { return m_header.length() + sizeof(u32); } - - DIE root_die() const; - DIE get_die_at_offset(u32 offset) const; - - ErrorOr get_address(size_t index) const; - ErrorOr get_string(size_t index) const; - - u8 dwarf_version() const { return m_header.version(); } - - DwarfInfo const& dwarf_info() const { return m_dwarf_info; } - AbbreviationsMap const& abbreviations_map() const { return m_abbreviations; } - LineProgram const& line_program() const; - ErrorOr> base_address() const; - - // DW_AT_addr_base - ErrorOr address_table_base() const; - // DW_AT_str_offsets_base - ErrorOr string_offsets_base() const; - // DW_AT_rnglists_base - ErrorOr range_lists_base() const; - -private: - CompilationUnit(DwarfInfo const& dwarf_info, u32 offset, CompilationUnitHeader const&); - ErrorOr populate_line_program(ReadonlyBytes debug_line_data); - - DwarfInfo const& m_dwarf_info; - u32 m_offset { 0 }; - CompilationUnitHeader m_header; - AbbreviationsMap m_abbreviations; - OwnPtr m_line_program; - mutable bool m_has_cached_base_address : 1 { false }; - mutable bool m_has_cached_address_table_base : 1 { false }; - mutable bool m_has_cached_string_offsets_base : 1 { false }; - mutable bool m_has_cached_range_lists_base : 1 { false }; - mutable Optional m_cached_base_address; - mutable u64 m_cached_address_table_base { 0 }; - mutable u64 m_cached_string_offsets_base { 0 }; - mutable u64 m_cached_range_lists_base { 0 }; -}; - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/DIE.cpp b/Userland/Libraries/LibDebug/Dwarf/DIE.cpp deleted file mode 100644 index 2d2c5154c1e..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/DIE.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2020-2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "DIE.h" -#include "CompilationUnit.h" -#include "DwarfInfo.h" -#include -#include -#include - -namespace Debug::Dwarf { - -DIE::DIE(CompilationUnit const& unit, u32 offset, Optional parent_offset) - : m_compilation_unit(unit) -{ - rehydrate_from(offset, parent_offset).release_value_but_fixme_should_propagate_errors(); -} - -ErrorOr DIE::rehydrate_from(u32 offset, Optional parent_offset) -{ - m_offset = offset; - - FixedMemoryStream stream { m_compilation_unit.dwarf_info().debug_info_data() }; - // 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_offset)); - m_abbreviation_code = TRY(stream.read_value>()); - m_data_offset = TRY(stream.tell()); - - if (m_abbreviation_code == 0) { - // An abbreviation code of 0 ( = null DIE entry) means the end of a chain of siblings - m_tag = EntryTag::None; - } else { - auto abbreviation_info = m_compilation_unit.abbreviations_map().get(m_abbreviation_code); - VERIFY(abbreviation_info); - - m_tag = abbreviation_info->tag; - m_has_children = abbreviation_info->has_children; - - // We iterate the attributes data only to calculate this DIE's size - 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)); - } - } - m_size = TRY(stream.tell()) - m_offset; - m_parent_offset = parent_offset; - return {}; -} - -ErrorOr> DIE::get_attribute(Attribute const& attribute) const -{ - FixedMemoryStream stream { m_compilation_unit.dwarf_info().debug_info_data() }; - // 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); - VERIFY(abbreviation_info); - - 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)); - if (attribute_spec.attribute == attribute) { - return value; - } - } - return Optional {}; -} - -ErrorOr DIE::for_each_child(Function(DIE const& child)> callback) const -{ - if (!m_has_children) - return {}; - - auto current_child = DIE(m_compilation_unit, m_offset + m_size, m_offset); - while (true) { - TRY(callback(current_child)); - if (current_child.is_null()) - break; - if (!current_child.has_children()) { - TRY(current_child.rehydrate_from(current_child.offset() + current_child.size(), m_offset)); - continue; - } - - auto sibling = TRY(current_child.get_attribute(Attribute::Sibling)); - u32 sibling_offset = 0; - if (sibling.has_value()) { - sibling_offset = sibling.value().as_unsigned(); - } else { - // NOTE: According to the spec, the compiler doesn't have to supply the sibling information. - // When it doesn't, we have to recursively iterate the current child's children to find where they end - TRY(current_child.for_each_child([&](DIE const& sub_child) -> ErrorOr { - sibling_offset = sub_child.offset() + sub_child.size(); - return {}; - })); - } - TRY(current_child.rehydrate_from(sibling_offset, m_offset)); - } - - return {}; -} - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/DIE.h b/Userland/Libraries/LibDebug/Dwarf/DIE.h deleted file mode 100644 index 56d38195918..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/DIE.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2020-2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "AttributeValue.h" -#include "DwarfTypes.h" -#include -#include -#include -#include - -namespace Debug::Dwarf { - -class CompilationUnit; - -// DIE = Debugging Information Entry -class DIE { -public: - DIE(CompilationUnit const&, u32 offset, Optional parent_offset = {}); - - u32 offset() const { return m_offset; } - u32 size() const { return m_size; } - bool has_children() const { return m_has_children; } - EntryTag tag() const { return m_tag; } - - ErrorOr> get_attribute(Attribute const&) const; - - ErrorOr for_each_child(Function(DIE const& child)> callback) const; - - bool is_null() const { return m_tag == EntryTag::None; } - CompilationUnit const& compilation_unit() const { return m_compilation_unit; } - Optional parent_offset() const { return m_parent_offset; } - -private: - ErrorOr rehydrate_from(u32 offset, Optional parent_offset); - CompilationUnit const& m_compilation_unit; - u32 m_offset { 0 }; - u32 m_data_offset { 0 }; - size_t m_abbreviation_code { 0 }; - EntryTag m_tag { EntryTag::None }; - bool m_has_children { false }; - u32 m_size { 0 }; - Optional m_parent_offset; -}; - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp deleted file mode 100644 index 8405725627a..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright (c) 2020-2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "DwarfInfo.h" -#include "AddressRanges.h" -#include "AttributeValue.h" -#include "CompilationUnit.h" - -#include -#include -#include -#include - -namespace Debug::Dwarf { - -DwarfInfo::DwarfInfo(ELF::Image const& elf) - : m_elf(elf) -{ - m_debug_info_data = section_data(".debug_info"sv); - m_abbreviation_data = section_data(".debug_abbrev"sv); - m_debug_strings_data = section_data(".debug_str"sv); - m_debug_line_data = section_data(".debug_line"sv); - m_debug_line_strings_data = section_data(".debug_line_str"sv); - m_debug_range_lists_data = section_data(".debug_rnglists"sv); - m_debug_str_offsets_data = section_data(".debug_str_offsets"sv); - m_debug_addr_data = section_data(".debug_addr"sv); - m_debug_ranges_data = section_data(".debug_ranges"sv); - - populate_compilation_units().release_value_but_fixme_should_propagate_errors(); -} - -DwarfInfo::~DwarfInfo() = default; - -ReadonlyBytes DwarfInfo::section_data(StringView section_name) const -{ - auto section = m_elf.lookup_section(section_name); - if (!section.has_value()) - return {}; - return section->bytes(); -} - -ErrorOr DwarfInfo::populate_compilation_units() -{ - if (!m_debug_info_data.data()) - return {}; - - FixedMemoryStream debug_info_stream { m_debug_info_data }; - - while (!debug_info_stream.is_eof()) { - auto unit_offset = TRY(debug_info_stream.tell()); - - auto compilation_unit_header = TRY(debug_info_stream.read_value()); - VERIFY(compilation_unit_header.common.version <= 5); - 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)); - - m_compilation_units.append(TRY(CompilationUnit::create(*this, unit_offset, compilation_unit_header, m_debug_line_data))); - TRY(debug_info_stream.discard(length_after_header)); - } - - return {}; -} - -ErrorOr DwarfInfo::get_attribute_value(AttributeDataForm form, ssize_t implicit_const_value, - SeekableStream& debug_info_stream, CompilationUnit const* unit) const -{ - AttributeValue value; - value.m_form = form; - value.m_compilation_unit = unit; - - auto assign_raw_bytes_value = [&](size_t length) -> ErrorOr { - value.m_data.as_raw_bytes = { debug_info_data().offset_pointer(TRY(debug_info_stream.tell())), length }; - TRY(debug_info_stream.discard(length)); - return {}; - }; - - switch (form) { - case AttributeDataForm::StringPointer: { - auto offset = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::String; - - auto strings_data = debug_strings_data(); - value.m_data.as_string = bit_cast(strings_data.offset_pointer(offset)); - break; - } - case AttributeDataForm::Data1: { - auto data = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::UnsignedNumber; - value.m_data.as_unsigned = data; - break; - } - case AttributeDataForm::Data2: { - auto data = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::UnsignedNumber; - value.m_data.as_signed = data; - break; - } - case AttributeDataForm::Addr: { - auto address = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::Address; - value.m_data.as_addr = address; - break; - } - case AttributeDataForm::SData: { - i64 data = TRY(debug_info_stream.read_value>()); - value.m_type = AttributeValue::Type::SignedNumber; - value.m_data.as_signed = data; - break; - } - case AttributeDataForm::UData: { - u64 data = TRY(debug_info_stream.read_value>()); - value.m_type = AttributeValue::Type::UnsignedNumber; - value.m_data.as_unsigned = data; - break; - } - case AttributeDataForm::SecOffset: { - auto data = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::SecOffset; - value.m_data.as_unsigned = data; - break; - } - case AttributeDataForm::Data4: { - auto data = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::UnsignedNumber; - value.m_data.as_unsigned = data; - break; - } - case AttributeDataForm::Data8: { - auto data = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::UnsignedNumber; - value.m_data.as_unsigned = data; - break; - } - case AttributeDataForm::Data16: { - value.m_type = AttributeValue::Type::RawBytes; - TRY(assign_raw_bytes_value(16)); - break; - } - case AttributeDataForm::Ref4: { - auto data = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::DieReference; - VERIFY(unit); - value.m_data.as_unsigned = data + unit->offset(); - break; - } - case AttributeDataForm::RefUData: { - auto data = TRY(debug_info_stream.read_value>()); - value.m_type = AttributeValue::Type::DieReference; - VERIFY(unit); - value.m_data.as_unsigned = data + unit->offset(); - break; - } - case AttributeDataForm::FlagPresent: { - value.m_type = AttributeValue::Type::Boolean; - value.m_data.as_bool = true; - break; - } - case AttributeDataForm::ExprLoc: { - size_t length = TRY(debug_info_stream.read_value>()); - value.m_type = AttributeValue::Type::DwarfExpression; - TRY(assign_raw_bytes_value(length)); - break; - } - case AttributeDataForm::String: { - u32 str_offset = TRY(debug_info_stream.tell()); - value.m_type = AttributeValue::Type::String; - value.m_data.as_string = bit_cast(debug_info_data().offset_pointer(str_offset)); - TRY(debug_info_stream.discard(strlen(value.m_data.as_string) + 1)); - break; - } - case AttributeDataForm::Block1: { - value.m_type = AttributeValue::Type::RawBytes; - auto length = TRY(debug_info_stream.read_value()); - TRY(assign_raw_bytes_value(length)); - break; - } - case AttributeDataForm::Block2: { - value.m_type = AttributeValue::Type::RawBytes; - auto length = TRY(debug_info_stream.read_value()); - TRY(assign_raw_bytes_value(length)); - break; - } - case AttributeDataForm::Block4: { - value.m_type = AttributeValue::Type::RawBytes; - auto length = TRY(debug_info_stream.read_value()); - TRY(assign_raw_bytes_value(length)); - break; - } - case AttributeDataForm::Block: { - value.m_type = AttributeValue::Type::RawBytes; - size_t length = TRY(debug_info_stream.read_value>()); - TRY(assign_raw_bytes_value(length)); - break; - } - case AttributeDataForm::LineStrP: { - auto offset = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::String; - - auto strings_data = debug_line_strings_data(); - value.m_data.as_string = bit_cast(strings_data.offset_pointer(offset)); - break; - } - case AttributeDataForm::ImplicitConst: { - /* Value is part of the abbreviation record. */ - value.m_type = AttributeValue::Type::SignedNumber; - value.m_data.as_signed = implicit_const_value; - break; - } - case AttributeDataForm::StrX1: { - auto index = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::String; - value.m_data.as_unsigned = index; - break; - } - case AttributeDataForm::StrX2: { - auto index = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::String; - value.m_data.as_unsigned = index; - break; - } - case AttributeDataForm::StrX4: { - auto index = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::String; - value.m_data.as_unsigned = index; - break; - } - case AttributeDataForm::StrX: { - size_t index = TRY(debug_info_stream.read_value>()); - value.m_type = AttributeValue::Type::String; - value.m_data.as_unsigned = index; - break; - } - case AttributeDataForm::AddrX1: { - auto index = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::Address; - value.m_data.as_unsigned = index; - break; - } - case AttributeDataForm::AddrX2: { - auto index = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::Address; - value.m_data.as_unsigned = index; - break; - } - case AttributeDataForm::AddrX4: { - auto index = TRY(debug_info_stream.read_value()); - value.m_type = AttributeValue::Type::Address; - value.m_data.as_unsigned = index; - break; - } - case AttributeDataForm::AddrX: { - size_t index = TRY(debug_info_stream.read_value>()); - value.m_type = AttributeValue::Type::Address; - value.m_data.as_unsigned = index; - break; - } - case AttributeDataForm::LocListX: - case AttributeDataForm::RngListX: { - size_t index = TRY(debug_info_stream.read_value>()); - value.m_type = AttributeValue::Type::UnsignedNumber; - value.m_data.as_unsigned = index; - break; - } - default: - dbgln("Unimplemented AttributeDataForm: {}", to_underlying(form)); - VERIFY_NOT_REACHED(); - } - return value; -} - -ErrorOr DwarfInfo::build_cached_dies() const -{ - auto insert_to_cache = [this](DIE const& die, DIERange const& range) { - m_cached_dies_by_range.insert(range.start_address, DIEAndRange { die, range }); - m_cached_dies_by_offset.insert(die.offset(), die); - }; - auto get_ranges_of_die = [this](DIE const& die) -> ErrorOr> { - auto ranges = TRY(die.get_attribute(Attribute::Ranges)); - if (ranges.has_value()) { - size_t offset; - if (ranges->form() == AttributeDataForm::SecOffset) { - offset = ranges->as_unsigned(); - } else { - auto index = ranges->as_unsigned(); - auto base = TRY(die.compilation_unit().range_lists_base()); - // FIXME: This assumes that the format is DWARf32 - auto offsets = debug_range_lists_data().slice(base); - offset = ByteReader::load32(offsets.offset_pointer(index * sizeof(u32))) + base; - } - - Vector entries; - if (die.compilation_unit().dwarf_version() == 5) { - auto range_lists_stream = TRY(try_make(debug_range_lists_data())); - TRY(range_lists_stream->seek(offset)); - AddressRangesV5 address_ranges(move(range_lists_stream), die.compilation_unit()); - TRY(address_ranges.for_each_range([&entries](auto range) { - entries.empend(range.start, range.end); - })); - } else { - auto ranges_stream = TRY(try_make(debug_ranges_data())); - TRY(ranges_stream->seek(offset)); - AddressRangesV4 address_ranges(move(ranges_stream), die.compilation_unit()); - TRY(address_ranges.for_each_range([&entries](auto range) { - entries.empend(range.start, range.end); - })); - } - return entries; - } - - auto start = TRY(die.get_attribute(Attribute::LowPc)); - auto end = TRY(die.get_attribute(Attribute::HighPc)); - - if (!start.has_value() || !end.has_value()) - return Vector {}; - - VERIFY(start->type() == Dwarf::AttributeValue::Type::Address); - - // DW_AT_high_pc attribute can have different meanings depending on the attribute form. - // (Dwarf version 5, section 2.17.2). - - uint32_t range_end = 0; - if (end->form() == Dwarf::AttributeDataForm::Addr) - range_end = TRY(end->as_addr()); - else - range_end = TRY(start->as_addr()) + end->as_unsigned(); - - return Vector { DIERange { TRY(start.value().as_addr()), range_end } }; - }; - - // If we simply use a lambda, type deduction fails because it's used recursively. - Function(DIE const& die)> insert_to_cache_recursively; - insert_to_cache_recursively = [&](DIE const& die) -> ErrorOr { - if (die.offset() == 0 || die.parent_offset().has_value()) { - auto ranges = TRY(get_ranges_of_die(die)); - for (auto& range : ranges) { - insert_to_cache(die, range); - } - } - TRY(die.for_each_child([&](DIE const& child) -> ErrorOr { - if (!child.is_null()) { - TRY(insert_to_cache_recursively(child)); - } - return {}; - })); - return {}; - }; - - TRY(for_each_compilation_unit([&](CompilationUnit const& compilation_unit) -> ErrorOr { - TRY(insert_to_cache_recursively(compilation_unit.root_die())); - return {}; - })); - - m_built_cached_dies = true; - return {}; -} - -ErrorOr> DwarfInfo::get_die_at_address(FlatPtr address) const -{ - if (!m_built_cached_dies) - TRY(build_cached_dies()); - - auto iter = m_cached_dies_by_range.find_largest_not_above_iterator(address); - while (!iter.is_end() && !iter.is_begin() && iter->range.end_address < address) { - --iter; - } - - if (iter.is_end()) - return Optional {}; - - if (iter->range.start_address > address || iter->range.end_address < address) { - return Optional {}; - } - - return iter->die; -} - -ErrorOr> DwarfInfo::get_cached_die_at_offset(FlatPtr offset) const -{ - if (!m_built_cached_dies) - TRY(build_cached_dies()); - - auto* die = m_cached_dies_by_offset.find(offset); - if (!die) - return Optional {}; - return *die; -} - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h b/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h deleted file mode 100644 index 63db8b69642..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/DwarfInfo.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2020-2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "AttributeValue.h" -#include "DwarfTypes.h" -#include -#include -#include -#include -#include -#include - -namespace Debug::Dwarf { - -class CompilationUnit; - -class DwarfInfo { - AK_MAKE_NONCOPYABLE(DwarfInfo); - AK_MAKE_NONMOVABLE(DwarfInfo); - -public: - explicit DwarfInfo(ELF::Image const&); - ~DwarfInfo(); - - ReadonlyBytes debug_info_data() const { return m_debug_info_data; } - ReadonlyBytes abbreviation_data() const { return m_abbreviation_data; } - ReadonlyBytes debug_strings_data() const { return m_debug_strings_data; } - ReadonlyBytes debug_line_strings_data() const { return m_debug_line_strings_data; } - ReadonlyBytes debug_range_lists_data() const { return m_debug_range_lists_data; } - ReadonlyBytes debug_str_offsets_data() const { return m_debug_str_offsets_data; } - ReadonlyBytes debug_addr_data() const { return m_debug_addr_data; } - ReadonlyBytes debug_ranges_data() const { return m_debug_ranges_data; } - - template - ErrorOr for_each_compilation_unit(Callback) const; - - ErrorOr get_attribute_value(AttributeDataForm form, ssize_t implicit_const_value, - SeekableStream& debug_info_stream, CompilationUnit const* unit = nullptr) const; - - ErrorOr> get_die_at_address(FlatPtr) const; - - // Note that even if there is a DIE at the given offset, - // but it does not exist in the DIE cache (because for example - // it does not contain an address range), then this function will not return it. - // To get any DIE object at a given offset in a compilation unit, - // use CompilationUnit::get_die_at_offset. - ErrorOr> get_cached_die_at_offset(FlatPtr) const; - -private: - ErrorOr populate_compilation_units(); - ErrorOr build_cached_dies() const; - - ReadonlyBytes section_data(StringView section_name) const; - - ELF::Image const& m_elf; - ReadonlyBytes m_debug_info_data; - ReadonlyBytes m_abbreviation_data; - ReadonlyBytes m_debug_strings_data; - ReadonlyBytes m_debug_line_data; - ReadonlyBytes m_debug_line_strings_data; - ReadonlyBytes m_debug_range_lists_data; - ReadonlyBytes m_debug_str_offsets_data; - ReadonlyBytes m_debug_addr_data; - ReadonlyBytes m_debug_ranges_data; - - Vector> m_compilation_units; - - struct DIERange { - FlatPtr start_address { 0 }; - FlatPtr end_address { 0 }; - }; - - struct DIEAndRange { - DIE die; - DIERange range; - }; - - using DIEStartAddress = FlatPtr; - - mutable RedBlackTree m_cached_dies_by_range; - mutable RedBlackTree m_cached_dies_by_offset; - mutable bool m_built_cached_dies { false }; -}; - -template -ErrorOr DwarfInfo::for_each_compilation_unit(Callback callback) const -{ - for (auto const& unit : m_compilation_units) { - TRY(callback(*unit)); - } - return {}; -} - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/DwarfTypes.h b/Userland/Libraries/LibDebug/Dwarf/DwarfTypes.h deleted file mode 100644 index bfdefaa39f0..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/DwarfTypes.h +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace Debug::Dwarf { - -enum class CompilationUnitType { - Full = 1, - Partial = 3 -}; - -struct [[gnu::packed]] CompilationUnitHeaderCommon { - u32 length; - u16 version; -}; - -struct [[gnu::packed]] CompilationUnitHeaderV4Ext { - u32 abbrev_offset; - u8 address_size; -}; - -struct [[gnu::packed]] CompilationUnitHeaderV5Ext { - u8 unit_type; - u8 address_size; - u32 abbrev_offset; -}; - -struct [[gnu::packed]] CompilationUnitHeader { - CompilationUnitHeaderCommon common; - - union { - CompilationUnitHeaderV4Ext v4; - CompilationUnitHeaderV5Ext v5; - }; - - size_t header_size() const - { - return sizeof(common) + ((common.version <= 4) ? sizeof(v4) : sizeof(v5)); - } - - u32 length() const { return common.length; } - u16 version() const { return common.version; } - CompilationUnitType unit_type() const - { - return (common.version <= 4) ? CompilationUnitType::Full : static_cast(v5.unit_type); - } - 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; } - - static ErrorOr read_from_stream(Stream& stream) - { - CompilationUnitHeader header; - TRY(stream.read_until_filled(Bytes { &header.common, sizeof(header.common) })); - if (header.common.version <= 4) - TRY(stream.read_until_filled(Bytes { &header.v4, sizeof(header.v4) })); - else - TRY(stream.read_until_filled(Bytes { &header.v5, sizeof(header.v5) })); - return header; - } -}; - -enum class EntryTag : u16 { - None = 0, - ArrayType = 0x1, - ClassType = 0x2, - EntryPoint = 0x3, - EnumerationType = 0x4, - FormalParameter = 0x5, - ImportedDeclaration = 0x8, - Label = 0xa, - LexicalBlock = 0xb, - Member = 0xd, - PointerType = 0xf, - ReferenceType = 0x10, - CompileUnit = 0x11, - StringType = 0x12, - StructureType = 0x13, - SubroutineType = 0x15, - TypeDef = 0x16, - UnionType = 0x17, - UnspecifiedParameters = 0x18, - Variant = 0x19, - CommonBlock = 0x1a, - CommonInclusion = 0x1b, - Inheritance = 0x1c, - InlinedSubroutine = 0x1d, - Module = 0x1e, - PtrToMemberType = 0x1f, - SetType = 0x20, - SubRangeType = 0x21, - WithStmt = 0x22, - AccessDeclaration = 0x23, - BaseType = 0x24, - CatchBlock = 0x25, - ConstType = 0x26, - Constant = 0x27, - Enumerator = 0x28, - FileType = 0x29, - Friend = 0x2a, - NameList = 0x2b, - NameListItem = 0x2c, - PackedType = 0x2d, - SubProgram = 0x2e, - TemplateTypeParam = 0x2f, - TemplateValueParam = 0x30, - ThrownType = 0x31, - TryBlock = 0x32, - VariantPart = 0x33, - Variable = 0x34, - VolatileType = 0x35, - DwarfProcedure = 0x36, - RestrictType = 0x37, - InterfaceType = 0x38, - Namespace = 0x39, - ImportedModule = 0x3a, - UnspecifiedType = 0x3b, - PartialUnit = 0x3c, - ImportedUnit = 0x3d, - MutableType = 0x3e, - Condition = 0x3f, - SharedTyped = 0x40, - TypeUnit = 0x41, - RValueReferenceType = 0x42, - TemplateAlias = 0x43, - CoArrayType = 0x44, - GenericSubRange = 0x45, - DynamicType = 0x46, - AtomicType = 0x47, - CallSite = 0x48, - CallSiteParameter = 0x49, - SkeletonUnit = 0x4a, - ImmutableType = 0x4b, - LoUser = 0x4080, - HiUser = 0xffff, -}; - -enum class Attribute : u16 { - None = 0, - Sibling = 0x1, - Location = 0x2, - Name = 0x3, - Ordering = 0x9, - ByteSize = 0xb, - BitOffset = 0xc, - BitSize = 0xd, - StmtList = 0x10, - LowPc = 0x11, - HighPc = 0x12, - Language = 0x13, - Discr = 0x15, - DiscrValue = 0x16, - Visibility = 0x17, - Import = 0x18, - StringLength = 0x19, - CommonReference = 0x1a, - CompDir = 0x1b, - ConstValue = 0x1c, - ContainingType = 0x1d, - DefaultValue = 0x1e, - Inline = 0x20, - IsOptional = 0x21, - LowerBound = 0x22, - Producer = 0x25, - Prototyped = 0x27, - ReturnAddr = 0x2a, - StartScope = 0x2c, - BitStride = 0x2e, - UpperBound = 0x2f, - AbstractOrigin = 0x31, - Accessibility = 0x32, - AddressClass = 0x33, - Artificial = 0x34, - BaseTypes = 0x35, - CallingConvention = 0x36, - Count = 0x37, - MemberLocation = 0x38, - DeclColumn = 0x39, - DeclFile = 0x3a, - DeclLine = 0x3b, - Declaration = 0x3c, - DiscrList = 0x3d, - Encoding = 0x3e, - External = 0x3f, - FrameBase = 0x40, - Friend = 0x41, - IdentifierCase = 0x43, - MacroInfo = 0x43, - NameListItem = 0x44, - Priority = 0x45, - Segment = 0x46, - Specification = 0x47, - StaticLink = 0x48, - Type = 0x49, - UseLocation = 0x4a, - VariableParameter = 0x4b, - Virtuality = 0x4c, - VtableElemLocation = 0x4d, - Allocated = 0x4e, - Associated = 0x4f, - DataLocation = 0x50, - ByteStride = 0x51, - EntryPC = 0x52, - UseUTF8 = 0x53, - Extension = 0x54, - Ranges = 0x55, - Trampoline = 0x56, - CallColumn = 0x57, - CallFile = 0x58, - CallLine = 0x59, - Description = 0x5a, - BinaryScale = 0x5b, - DecimalScale = 0x5c, - Small = 0x5d, - DecimalSign = 0x5e, - DigitCount = 0x5f, - PictureString = 0x60, - Mutable = 0x61, - ThreadsScaled = 0x62, - Explicit = 0x63, - ObjectPointer = 0x64, - Endianity = 0x65, - Elemental = 0x66, - Pure = 0x67, - Recursive = 0x68, - Signature = 0x69, - MainSubprogram = 0x6a, - DataBitOffset = 0x6b, - ConstExpr = 0x6c, - EnumClass = 0x6d, - LinkageName = 0x6e, - StringLengthBitSize = 0x6f, - StringLengthByteSize = 0x70, - Rank = 0x71, - StrOffsetsBase = 0x72, - AddrBase = 0x73, - RngListsBase = 0x74, - DWOName = 0x76, - Reference = 0x77, - RValueReference = 0x78, - Macros = 0x79, - CallAllCalls = 0x7a, - CallAllSourceCalls = 0x7b, - CallAllTailCalls = 0x7c, - CallReturnPC = 0x7d, - CallValue = 0x7e, - CallOrigin = 0x7f, - CallParameter = 0x80, - CallPC = 0x81, - CallTailCall = 0x82, - CallTarget = 0x83, - CallTargetClobbered = 0x84, - CallDataLocation = 0x85, - CallDataValue = 0x86, - NoReturn = 0x87, - Alignment = 0x88, - ExportSymbols = 0x89, - Deleted = 0x8a, - Defaulted = 0x8b, - LocListsBase = 0x8c, - LoUser = 0x2000, - HiUser = 0x3fff, -}; - -enum class AttributeDataForm : u8 { - None = 0, - Addr = 0x1, - Block2 = 0x3, - Block4 = 0x4, - Data2 = 0x5, - Data4 = 0x6, - Data8 = 0x7, - String = 0x8, - Block = 0x9, - Block1 = 0xa, - Data1 = 0xb, - Flag = 0xc, - SData = 0xd, - StringPointer = 0xe, - UData = 0xf, - RefAddr = 0x10, - Ref1 = 0x11, - Ref2 = 0x12, - Ref4 = 0x13, - Ref8 = 0x14, - RefUData = 0x15, - Indirect = 0x16, - SecOffset = 0x17, - ExprLoc = 0x18, - FlagPresent = 0x19, - StrX = 0x1a, - AddrX = 0x1b, - RefSup4 = 0x1c, - StrPSup = 0x1d, - Data16 = 0x1e, - LineStrP = 0x1f, - RefSig8 = 0x20, - ImplicitConst = 0x21, - LocListX = 0x22, - RngListX = 0x23, - RefSup8 = 0x24, - StrX1 = 0x25, - StrX2 = 0x26, - StrX3 = 0x27, - StrX4 = 0x28, - AddrX1 = 0x29, - AddrX2 = 0x2a, - AddrX3 = 0x2b, - AddrX4 = 0x2c -}; - -struct [[gnu::packed]] AttributeSpecification { - Attribute attribute; - AttributeDataForm form; - ssize_t value; -}; - -// Dwarf version 5, section 7.25 -enum class RangeListEntryType : u8 { - EndOfList = 0, - BaseAddressX = 0x1, - StartXEndX = 0x2, - StartXLength = 0x3, - OffsetPair = 0x4, - BaseAddress = 0x5, - StartEnd = 0x6, - StartLength = 0x7 -}; - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/LineProgram.cpp b/Userland/Libraries/LibDebug/Dwarf/LineProgram.cpp deleted file mode 100644 index 68b97f0b7db..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/LineProgram.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "LineProgram.h" -#include -#include -#include -#include -#include - -namespace Debug::Dwarf { - -LineProgram::LineProgram(DwarfInfo const& dwarf_info, size_t unit_offset) - : m_dwarf_info(dwarf_info) - , m_unit_offset(unit_offset) -{ -} - -ErrorOr> LineProgram::create(DwarfInfo const& dwarf_info, SeekableStream& stream) -{ - auto offset = TRY(stream.tell()); - auto program = TRY(adopt_nonnull_own_or_enomem(new (nothrow) LineProgram(dwarf_info, offset))); - TRY(program->parse_unit_header(stream)); - TRY(program->parse_source_directories(stream)); - TRY(program->parse_source_files(stream)); - TRY(program->run_program(stream)); - return program; -} - -ErrorOr LineProgram::parse_unit_header(SeekableStream& stream) -{ - m_unit_header = TRY(stream.read_value()); - - 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); - - dbgln_if(DWARF_DEBUG, "unit length: {}", m_unit_header.length()); - return {}; -} - -ErrorOr LineProgram::parse_path_entries(SeekableStream& stream, Function callback, PathListType list_type) -{ - if (m_unit_header.version() >= 5) { - auto path_entry_format_count = TRY(stream.read_value()); - - Vector format_descriptions; - - for (u8 i = 0; i < path_entry_format_count; i++) { - UnderlyingType content_type = TRY(stream.read_value>>()); - - UnderlyingType data_form = TRY(stream.read_value>>()); - - format_descriptions.empend(static_cast(content_type), static_cast(data_form)); - } - - size_t paths_count = TRY(stream.read_value>()); - - for (size_t i = 0; i < paths_count; i++) { - PathEntry entry; - for (auto& format_description : format_descriptions) { - auto value = TRY(m_dwarf_info.get_attribute_value(format_description.form, 0, stream)); - switch (format_description.type) { - case ContentType::Path: - entry.path = TRY(value.as_string()); - break; - case ContentType::DirectoryIndex: - entry.directory_index = value.as_unsigned(); - break; - default: - dbgln_if(DWARF_DEBUG, "Unhandled path list attribute: {}", to_underlying(format_description.type)); - } - } - callback(entry); - } - } else { - while (true) { - StringBuilder builder; - while (auto c = TRY(stream.read_value())) - TRY(builder.try_append(c)); - auto path = builder.to_byte_string(); - if (path.length() == 0) - break; - dbgln_if(DWARF_DEBUG, "path: {}", path); - PathEntry entry; - entry.path = path; - if (list_type == PathListType::Filenames) { - size_t directory_index = TRY(stream.read_value>()); - TRY(stream.read_value>()); // skip modification time - TRY(stream.read_value>()); // skip file size - entry.directory_index = directory_index; - dbgln_if(DWARF_DEBUG, "file: {}, directory index: {}", path, directory_index); - } - callback(entry); - } - } - - return {}; -} - -ErrorOr LineProgram::parse_source_directories(SeekableStream& stream) -{ - if (m_unit_header.version() < 5) { - m_source_directories.append("."); - } - - TRY(parse_path_entries(stream, [this](PathEntry& entry) { m_source_directories.append(entry.path); }, PathListType::Directories)); - - return {}; -} - -ErrorOr LineProgram::parse_source_files(SeekableStream& stream) -{ - if (m_unit_header.version() < 5) { - m_source_files.append({ ".", 0 }); - } - - TRY(parse_path_entries(stream, [this](PathEntry& entry) { m_source_files.append({ entry.path, entry.directory_index }); }, PathListType::Filenames)); - - return {}; -} - -void LineProgram::append_to_line_info() -{ - dbgln_if(DWARF_DEBUG, "appending line info: {:p}, {}:{}", m_address, m_source_files[m_file_index].name, m_line); - if (!m_is_statement) - return; - - if (m_file_index >= m_source_files.size()) - return; - - auto const& directory = m_source_directories[m_source_files[m_file_index].directory_index]; - - StringBuilder full_path(directory.length() + m_source_files[m_file_index].name.length() + 1); - full_path.append(directory); - full_path.append('/'); - full_path.append(m_source_files[m_file_index].name); - - m_lines.append({ m_address, DeprecatedFlyString { full_path.string_view() }, m_line }); -} - -void LineProgram::reset_registers() -{ - m_address = 0; - m_line = 1; - m_file_index = 1; - m_is_statement = m_unit_header.default_is_stmt() == 1; -} - -ErrorOr LineProgram::handle_extended_opcode(SeekableStream& stream) -{ - size_t length = TRY(stream.read_value>()); - - auto sub_opcode = TRY(stream.read_value()); - - switch (sub_opcode) { - case ExtendedOpcodes::EndSequence: { - append_to_line_info(); - reset_registers(); - break; - } - case ExtendedOpcodes::SetAddress: { - VERIFY(length == sizeof(size_t) + 1); - m_address = TRY(stream.read_value()); - dbgln_if(DWARF_DEBUG, "SetAddress: {:p}", m_address); - break; - } - case ExtendedOpcodes::SetDiscriminator: { - dbgln_if(DWARF_DEBUG, "SetDiscriminator"); - [[maybe_unused]] size_t discriminator = TRY(stream.read_value>()); - break; - } - default: - dbgln("Encountered unknown sub opcode {} at stream offset {:p}", sub_opcode, TRY(stream.tell())); - VERIFY_NOT_REACHED(); - } - - return {}; -} -ErrorOr LineProgram::handle_standard_opcode(SeekableStream& stream, u8 opcode) -{ - switch (opcode) { - case StandardOpcodes::Copy: { - append_to_line_info(); - break; - } - case StandardOpcodes::AdvancePc: { - size_t operand = TRY(stream.read_value>()); - size_t delta = operand * m_unit_header.min_instruction_length(); - dbgln_if(DWARF_DEBUG, "AdvancePC by: {} to: {:p}", delta, m_address + delta); - m_address += delta; - break; - } - case StandardOpcodes::SetFile: { - size_t new_file_index = TRY(stream.read_value>()); - dbgln_if(DWARF_DEBUG, "SetFile: new file index: {}", new_file_index); - m_file_index = new_file_index; - break; - } - case StandardOpcodes::SetColumn: { - // not implemented - dbgln_if(DWARF_DEBUG, "SetColumn"); - [[maybe_unused]] size_t new_column = TRY(stream.read_value>()); - - break; - } - case StandardOpcodes::AdvanceLine: { - ssize_t line_delta = TRY(stream.read_value>()); - VERIFY(line_delta >= 0 || m_line >= (size_t)(-line_delta)); - m_line += line_delta; - dbgln_if(DWARF_DEBUG, "AdvanceLine: {}", m_line); - break; - } - case StandardOpcodes::NegateStatement: { - dbgln_if(DWARF_DEBUG, "NegateStatement"); - m_is_statement = !m_is_statement; - break; - } - case StandardOpcodes::ConstAddPc: { - u8 adjusted_opcode = 255 - m_unit_header.opcode_base(); - ssize_t address_increment = (adjusted_opcode / m_unit_header.line_range()) * m_unit_header.min_instruction_length(); - address_increment *= m_unit_header.min_instruction_length(); - dbgln_if(DWARF_DEBUG, "ConstAddPc: advance pc by: {} to: {}", address_increment, (m_address + address_increment)); - m_address += address_increment; - break; - } - case StandardOpcodes::SetIsa: { - size_t isa = TRY(stream.read_value>()); - dbgln_if(DWARF_DEBUG, "SetIsa: {}", isa); - break; - } - case StandardOpcodes::FixAdvancePc: { - auto delta = TRY(stream.read_value()); - dbgln_if(DWARF_DEBUG, "FixAdvancePC by: {} to: {:p}", delta, m_address + delta); - m_address += delta; - break; - } - case StandardOpcodes::SetBasicBlock: { - m_basic_block = true; - break; - } - case StandardOpcodes::SetPrologueEnd: { - m_prologue_end = true; - break; - } - case StandardOpcodes::SetEpilogueBegin: { - m_epilogue_begin = true; - break; - } - default: - dbgln("Unhandled LineProgram opcode {}", opcode); - VERIFY_NOT_REACHED(); - } - - return {}; -} -void LineProgram::handle_special_opcode(u8 opcode) -{ - u8 adjusted_opcode = opcode - m_unit_header.opcode_base(); - ssize_t address_increment = (adjusted_opcode / m_unit_header.line_range()) * m_unit_header.min_instruction_length(); - ssize_t line_increment = m_unit_header.line_base() + (adjusted_opcode % m_unit_header.line_range()); - - m_address += address_increment; - m_line += line_increment; - - if constexpr (DWARF_DEBUG) { - dbgln("Special adjusted_opcode: {}, address_increment: {}, line_increment: {}", adjusted_opcode, address_increment, line_increment); - dbgln("Address is now: {:p}, and line is: {}:{}", m_address, m_source_files[m_file_index].name, m_line); - } - - append_to_line_info(); - - m_basic_block = false; - m_prologue_end = false; -} - -ErrorOr LineProgram::run_program(SeekableStream& stream) -{ - reset_registers(); - - while (TRY(stream.tell()) < m_unit_offset + sizeof(u32) + m_unit_header.length()) { - auto opcode = TRY(stream.read_value()); - - dbgln_if(DWARF_DEBUG, "{:p}: opcode: {}", TRY(stream.tell()) - 1, opcode); - - if (opcode == 0) { - TRY(handle_extended_opcode(stream)); - } else if (opcode >= 1 && opcode <= 12) { - TRY(handle_standard_opcode(stream, opcode)); - } else { - handle_special_opcode(opcode); - } - } - - return {}; -} - -LineProgram::DirectoryAndFile LineProgram::get_directory_and_file(size_t file_index) const -{ - VERIFY(file_index < m_source_files.size()); - auto file_entry = m_source_files[file_index]; - VERIFY(file_entry.directory_index < m_source_directories.size()); - auto directory_entry = m_source_directories[file_entry.directory_index]; - return { directory_entry, file_entry.name }; -} - -bool LineProgram::looks_like_embedded_resource() const -{ - if (source_files().size() == 1) - return source_files()[0].name.view().contains("serenity_icon_"sv); - - if (source_files().size() == 2 && source_files()[0].name.view() == "."sv) - return source_files()[1].name.view().contains("serenity_icon_"sv); - - return false; -} - -} diff --git a/Userland/Libraries/LibDebug/Dwarf/LineProgram.h b/Userland/Libraries/LibDebug/Dwarf/LineProgram.h deleted file mode 100644 index e30cbba3180..00000000000 --- a/Userland/Libraries/LibDebug/Dwarf/LineProgram.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace Debug::Dwarf { - -class DwarfInfo; - -struct [[gnu::packed]] LineProgramUnitHeader32Common { - u32 length; - u16 version; -}; - -struct [[gnu::packed]] LineProgramUnitHeader32V4Ext { - u32 header_length; - u8 min_instruction_length; - u8 max_instruction_length; - u8 default_is_stmt; - i8 line_base; - u8 line_range; - u8 opcode_base; -}; - -struct [[gnu::packed]] LineProgramUnitHeader32V5Ext { - u8 address_size; - u8 segment_selector_size; - u32 header_length; - u8 min_instruction_length; - u8 max_instruction_length; - u8 default_is_stmt; - i8 line_base; - u8 line_range; - u8 opcode_base; -}; - -struct [[gnu::packed]] LineProgramUnitHeader32 { - LineProgramUnitHeader32Common common; - - union { - LineProgramUnitHeader32V4Ext v4; - LineProgramUnitHeader32V5Ext v5; - }; - - u8 std_opcode_lengths[13]; - - size_t header_size() const - { - return sizeof(common) + ((common.version <= 4) ? sizeof(v4) : sizeof(v5)) + (opcode_base() - 1) * sizeof(std_opcode_lengths[0]); - } - - u32 length() const { return common.length; } - u16 version() const { return common.version; } - u32 header_length() const { return (common.version <= 4) ? v4.header_length : v5.header_length; } - u8 min_instruction_length() const { return (common.version <= 4) ? v4.min_instruction_length : v5.min_instruction_length; } - u8 default_is_stmt() const { return (common.version <= 4) ? v4.default_is_stmt : v5.default_is_stmt; } - 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 opcode_base() const { return (common.version <= 4) ? v4.opcode_base : v5.opcode_base; } - - static ErrorOr read_from_stream(Stream& stream) - { - LineProgramUnitHeader32 header; - TRY(stream.read_until_filled(Bytes { &header.common, sizeof(header.common) })); - if (header.common.version <= 4) - TRY(stream.read_until_filled(Bytes { &header.v4, sizeof(header.v4) })); - else - TRY(stream.read_until_filled(Bytes { &header.v5, sizeof(header.v5) })); - TRY(stream.read_until_filled(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 { - Path = 1, - DirectoryIndex = 2, - Timestamp = 3, - Size = 4, - MD5 = 5, - LoUser = 0x2000, - HiUser = 0x3fff, -}; - -struct PathEntryFormat { - ContentType type; - AttributeDataForm form; -}; - -struct PathEntry { - ByteString path; - size_t directory_index { 0 }; -}; - -enum class PathListType { - Directories, - Filenames, -}; - -class LineProgram { - AK_MAKE_NONCOPYABLE(LineProgram); - AK_MAKE_NONMOVABLE(LineProgram); - -public: - static ErrorOr> create(DwarfInfo const& dwarf_info, SeekableStream& stream); - - struct LineInfo { - FlatPtr address { 0 }; - DeprecatedFlyString file; - size_t line { 0 }; - }; - - Vector const& lines() const { return m_lines; } - - struct DirectoryAndFile { - DeprecatedFlyString directory; - DeprecatedFlyString filename; - }; - DirectoryAndFile get_directory_and_file(size_t file_index) const; - - struct FileEntry { - DeprecatedFlyString name; - size_t directory_index { 0 }; - }; - Vector const& source_files() const { return m_source_files; } - - bool looks_like_embedded_resource() const; - -private: - LineProgram(DwarfInfo const& dwarf_info, size_t unit_offset); - - ErrorOr parse_unit_header(SeekableStream& stream); - ErrorOr parse_source_directories(SeekableStream& stream); - ErrorOr parse_source_files(SeekableStream& stream); - ErrorOr run_program(SeekableStream& stream); - - void append_to_line_info(); - void reset_registers(); - - ErrorOr handle_extended_opcode(SeekableStream& stream); - ErrorOr handle_standard_opcode(SeekableStream& stream, u8 opcode); - void handle_special_opcode(u8 opcode); - - ErrorOr parse_path_entries(SeekableStream& stream, Function callback, PathListType list_type); - - enum StandardOpcodes { - Copy = 1, - AdvancePc, - AdvanceLine, - SetFile, - SetColumn, - NegateStatement, - SetBasicBlock, - ConstAddPc, - FixAdvancePc, - SetPrologueEnd, - SetEpilogueBegin, - SetIsa - }; - - enum ExtendedOpcodes { - EndSequence = 1, - SetAddress, - DefineFile, - SetDiscriminator, - }; - - static constexpr u16 MIN_DWARF_VERSION = 3; - static constexpr u16 MAX_DWARF_VERSION = 5; - - DwarfInfo const& m_dwarf_info; - - size_t m_unit_offset { 0 }; - LineProgramUnitHeader32 m_unit_header {}; - Vector m_source_directories; - Vector m_source_files; - - // The registers of the "line program" virtual machine - FlatPtr m_address { 0 }; - size_t m_line { 0 }; - size_t m_file_index { 0 }; - bool m_is_statement { false }; - bool m_basic_block { false }; - bool m_prologue_end { false }; - bool m_epilogue_begin { false }; - - Vector m_lines; -}; - -} diff --git a/Userland/Libraries/LibDebug/LoadedLibrary.h b/Userland/Libraries/LibDebug/LoadedLibrary.h deleted file mode 100644 index f8efef2b62a..00000000000 --- a/Userland/Libraries/LibDebug/LoadedLibrary.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "DebugInfo.h" -#include -#include -#include - -namespace Debug { -struct LoadedLibrary { - ByteString name; - NonnullOwnPtr file; - NonnullOwnPtr image; - NonnullOwnPtr debug_info; - FlatPtr base_address {}; - - LoadedLibrary(ByteString const& name, NonnullOwnPtr file, NonnullOwnPtr image, NonnullOwnPtr&& debug_info, FlatPtr base_address) - : name(name) - , file(move(file)) - , image(move(image)) - , debug_info(move(debug_info)) - , base_address(base_address) - { - } -}; - -} diff --git a/Userland/Libraries/LibDebug/ProcessInspector.cpp b/Userland/Libraries/LibDebug/ProcessInspector.cpp deleted file mode 100644 index 5a564d97577..00000000000 --- a/Userland/Libraries/LibDebug/ProcessInspector.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "ProcessInspector.h" -#include "DebugInfo.h" - -namespace Debug { - -LoadedLibrary const* ProcessInspector::library_at(FlatPtr address) const -{ - LoadedLibrary const* result = nullptr; - for_each_loaded_library([&result, address](auto const& lib) { - if (address >= lib.base_address && address < lib.base_address + lib.debug_info->elf().size()) { - result = &lib; - return IterationDecision::Break; - } - return IterationDecision::Continue; - }); - return result; -} - -Optional ProcessInspector::symbolicate(FlatPtr address) const -{ - auto* lib = library_at(address); - if (!lib) - return {}; - // FIXME: ELF::Image symbolicate() API should return ByteString::empty() if symbol is not found (It currently returns ??) - auto symbol = lib->debug_info->elf().symbolicate(address - lib->base_address); - return { { lib->name, symbol } }; -} - -Optional ProcessInspector::get_address_from_source_position(ByteString const& file, size_t line) const -{ - Optional result; - for_each_loaded_library([file, line, &result](auto& lib) { - // The loader contains its own definitions for LibC symbols, so we don't want to include it in the search. - if (lib.name == "Loader.so") - return IterationDecision::Continue; - - auto source_position_and_address = lib.debug_info->get_address_from_source_position(file, line); - if (!source_position_and_address.has_value()) - return IterationDecision::Continue; - - result = source_position_and_address; - result.value().address += lib.base_address; - return IterationDecision::Break; - }); - return result; -} - -Optional ProcessInspector::get_source_position(FlatPtr address) const -{ - auto* lib = library_at(address); - if (!lib) - return {}; - return lib->debug_info->get_source_position(address - lib->base_address); -} - -} diff --git a/Userland/Libraries/LibDebug/ProcessInspector.h b/Userland/Libraries/LibDebug/ProcessInspector.h deleted file mode 100644 index 4b6a388ae22..00000000000 --- a/Userland/Libraries/LibDebug/ProcessInspector.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (c) 2021, Itamar S. - * Copyright (c) 2022, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "LoadedLibrary.h" -#include -#include - -namespace Debug { - -class ProcessInspector { -public: - virtual ~ProcessInspector() = default; - virtual bool poke(FlatPtr address, FlatPtr data) = 0; - virtual Optional peek(FlatPtr address) const = 0; - virtual PtraceRegisters get_registers() const = 0; - virtual void set_registers(PtraceRegisters const&) = 0; - virtual void for_each_loaded_library(Function) const = 0; - - LoadedLibrary const* library_at(FlatPtr address) const; - struct SymbolicationResult { - ByteString library_name; - ByteString symbol; - }; - Optional symbolicate(FlatPtr address) const; - Optional get_address_from_source_position(ByteString const& file, size_t line) const; - Optional get_source_position(FlatPtr address) const; - -protected: - ProcessInspector() = default; -}; - -};