mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:12:45 +00:00 
			
		
		
		
	LibELF: Remove ELF::Loader and move everyone to ELF::Image
This commit gets rid of ELF::Loader entirely since its very ambiguous purpose was actually to load executables for the kernel, and that is now handled by the kernel itself. This patch includes some drive-by cleanup in LibDebug and CrashDaemon enabled by the fact that we no longer need to keep the ref-counted ELF::Loader around.
This commit is contained in:
		
							parent
							
								
									7551a66f73
								
							
						
					
					
						commit
						1e4c010643
					
				
					 24 changed files with 178 additions and 318 deletions
				
			
		|  | @ -30,9 +30,10 @@ | |||
| #include <AK/LogStream.h> | ||||
| #include <AK/ScopeGuard.h> | ||||
| #include <LibCore/DirectoryWatcher.h> | ||||
| #include <LibCore/File.h> | ||||
| #include <LibCoreDump/CoreDumpReader.h> | ||||
| #include <LibDebug/DebugInfo.h> | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/Image.h> | ||||
| #include <fcntl.h> | ||||
| #include <stdio.h> | ||||
| #include <sys/stat.h> | ||||
|  | @ -63,78 +64,62 @@ static String object_name(StringView memory_region_name) | |||
|     return memory_region_name.substring_view(0, memory_region_name.find_first_of(":").value()).to_string(); | ||||
| } | ||||
| 
 | ||||
| struct ElfObjectInfo : public RefCounted<ElfObjectInfo> { | ||||
| 
 | ||||
|     ElfObjectInfo(MappedFile&& file, NonnullRefPtr<ELF::Loader>&& loader, Debug::DebugInfo&& debug_info) | ||||
| struct ElfObjectInfo { | ||||
|     ElfObjectInfo(MappedFile&& file, Debug::DebugInfo&& debug_info) | ||||
|         : file(move(file)) | ||||
|         , loader(move(loader)) | ||||
|         , debug_info(move(debug_info)) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     MappedFile file; | ||||
|     NonnullRefPtr<ELF::Loader> loader; | ||||
|     Debug::DebugInfo debug_info; | ||||
| }; | ||||
| 
 | ||||
| // FIXME: This cache has to be invalidated when libraries/programs are re-compiled.
 | ||||
| // We can store the last-modified timestamp of the elf files in ElfObjectInfo to invalidate cache entries.
 | ||||
| static HashMap<String, RefPtr<ElfObjectInfo>> s_debug_info_cache; | ||||
| static HashMap<String, NonnullOwnPtr<ElfObjectInfo>> s_debug_info_cache; | ||||
| 
 | ||||
| static RefPtr<ElfObjectInfo> object_info_for_region(const ELF::Core::MemoryRegionInfo* region) | ||||
| static const ElfObjectInfo* object_info_for_region(const ELF::Core::MemoryRegionInfo* region) | ||||
| { | ||||
|     StringView region_name { region->region_name }; | ||||
| 
 | ||||
|     auto name = object_name(region_name); | ||||
|     auto name = object_name(region->region_name); | ||||
| 
 | ||||
|     String path; | ||||
|     if (name.contains(".so")) | ||||
|         path = String::format("/usr/lib/%s", name.characters()); | ||||
|         path = String::formatted("/usr/lib/{}", name); | ||||
|     else { | ||||
|         path = name; | ||||
|     } | ||||
| 
 | ||||
|     auto cached_value = s_debug_info_cache.get(path); | ||||
|     if (cached_value.has_value()) | ||||
|         return cached_value.value(); | ||||
|     if (auto it = s_debug_info_cache.find(path); it != s_debug_info_cache.end()) | ||||
|         return it->value.ptr(); | ||||
| 
 | ||||
|     struct stat st; | ||||
|     if (stat(path.characters(), &st)) { | ||||
|     if (!Core::File::exists(path.characters())) | ||||
|         return nullptr; | ||||
|     } | ||||
| 
 | ||||
|     MappedFile object_file(path); | ||||
|     if (!object_file.is_valid()) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     auto loader = ELF::Loader::create((const u8*)object_file.data(), object_file.size()); | ||||
|     Debug::DebugInfo debug_info(loader); | ||||
| 
 | ||||
|     RefPtr<ElfObjectInfo> info = adopt(*new ElfObjectInfo( | ||||
|         move(object_file), | ||||
|         move(loader), | ||||
|         move(debug_info))); | ||||
| 
 | ||||
|     s_debug_info_cache.set(path, info); | ||||
|     return info; | ||||
|     auto info = make<ElfObjectInfo>(move(object_file), Debug::DebugInfo { make<ELF::Image>((const u8*)object_file.data(), object_file.size()) }); | ||||
|     auto* info_ptr = info.ptr(); | ||||
|     s_debug_info_cache.set(path, move(info)); | ||||
|     return info_ptr; | ||||
| } | ||||
| 
 | ||||
| static String backtrace_line(const CoreDumpReader& coredump, FlatPtr eip) | ||||
| { | ||||
|     auto* region = coredump.region_containing((FlatPtr)eip); | ||||
|     if (!region) { | ||||
|     if (!region) | ||||
|         return String::format("%p: ???", eip); | ||||
|     } | ||||
| 
 | ||||
|     StringView region_name { region->region_name }; | ||||
|     if (region_name.contains("Loader.so")) | ||||
|     if (StringView { region->region_name }.contains("Loader.so")) | ||||
|         return {}; | ||||
| 
 | ||||
|     auto object_info = object_info_for_region(region); | ||||
|     if (object_info.is_null()) | ||||
|     auto* object_info = object_info_for_region(region); | ||||
|     if (!object_info) | ||||
|         return {}; | ||||
| 
 | ||||
|     auto func_name = object_info->loader->symbolicate(eip - region->region_start); | ||||
|     auto func_name = object_info->debug_info.elf().symbolicate(eip - region->region_start); | ||||
| 
 | ||||
|     auto source_position = object_info->debug_info.get_source_position(eip - region->region_start); | ||||
| 
 | ||||
|  | @ -142,7 +127,7 @@ static String backtrace_line(const CoreDumpReader& coredump, FlatPtr eip) | |||
|     if (source_position.has_value()) | ||||
|         source_position_string = String::format(" (\033[34;1m%s\033[0m:%u)", LexicalPath(source_position.value().file_path).basename().characters(), source_position.value().line_number); | ||||
| 
 | ||||
|     return String::format("%p: [%s] %s%s", eip, object_name(region_name).characters(), func_name.is_null() ? "???" : func_name.characters(), source_position_string.characters()); | ||||
|     return String::format("%p: [%s] %s%s", eip, object_name(region->region_name).characters(), func_name.is_null() ? "???" : func_name.characters(), source_position_string.characters()); | ||||
| } | ||||
| 
 | ||||
| static void backtrace(const String& coredump_path) | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ | |||
| #include <AK/MappedFile.h> | ||||
| #include <AK/StringBuilder.h> | ||||
| #include <LibDebug/DebugSession.h> | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/Image.h> | ||||
| #include <LibX86/Disassembler.h> | ||||
| #include <LibX86/ELFSymbolProvider.h> | ||||
| #include <ctype.h> | ||||
|  | @ -44,25 +44,27 @@ DisassemblyModel::DisassemblyModel(const Debug::DebugSession& debug_session, con | |||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     RefPtr<ELF::Loader> elf_loader; | ||||
|     OwnPtr<ELF::Image> kernel_elf; | ||||
|     const ELF::Image* elf = nullptr; | ||||
| 
 | ||||
|     if (containing_function.value().address_low >= 0xc0000000) { | ||||
|         auto kernel_file = make<MappedFile>("/boot/Kernel"); | ||||
|         if (!kernel_file->is_valid()) | ||||
|             return; | ||||
|         elf_loader = ELF::Loader::create((const u8*)kernel_file->data(), kernel_file->size()); | ||||
|         kernel_elf = make<ELF::Image>((const u8*)kernel_file->data(), kernel_file->size()); | ||||
|         elf = kernel_elf.ptr(); | ||||
|     } else { | ||||
|         elf_loader = debug_session.elf(); | ||||
|         elf = &debug_session.elf(); | ||||
|     } | ||||
| 
 | ||||
|     auto symbol = elf_loader->find_symbol(containing_function.value().address_low); | ||||
|     auto symbol = elf->find_symbol(containing_function.value().address_low); | ||||
|     if (!symbol.has_value()) | ||||
|         return; | ||||
|     ASSERT(symbol.has_value()); | ||||
| 
 | ||||
|     auto view = symbol.value().raw_data(); | ||||
| 
 | ||||
|     X86::ELFSymbolProvider symbol_provider(*elf_loader); | ||||
|     X86::ELFSymbolProvider symbol_provider(*elf); | ||||
|     X86::SimpleInstructionStream stream((const u8*)view.characters_without_null_termination(), view.length()); | ||||
|     X86::Disassembler disassembler(stream); | ||||
| 
 | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ | |||
| #include "DisassemblyModel.h" | ||||
| #include "Profile.h" | ||||
| #include <AK/MappedFile.h> | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/Image.h> | ||||
| #include <LibGUI/Painter.h> | ||||
| #include <LibX86/Disassembler.h> | ||||
| #include <LibX86/ELFSymbolProvider.h> | ||||
|  | @ -65,16 +65,16 @@ DisassemblyModel::DisassemblyModel(Profile& profile, ProfileNode& node) | |||
|     if (!m_file->is_valid()) | ||||
|         return; | ||||
| 
 | ||||
|     auto elf_loader = ELF::Loader::create((const u8*)m_file->data(), m_file->size()); | ||||
|     auto elf = ELF::Image((const u8*)m_file->data(), m_file->size()); | ||||
| 
 | ||||
|     auto symbol = elf_loader->find_symbol(node.address()); | ||||
|     auto symbol = elf.find_symbol(node.address()); | ||||
|     if (!symbol.has_value()) | ||||
|         return; | ||||
|     ASSERT(symbol.has_value()); | ||||
| 
 | ||||
|     auto view = symbol.value().raw_data(); | ||||
| 
 | ||||
|     X86::ELFSymbolProvider symbol_provider(*elf_loader); | ||||
|     X86::ELFSymbolProvider symbol_provider(elf); | ||||
|     X86::SimpleInstructionStream stream((const u8*)view.characters_without_null_termination(), view.length()); | ||||
|     X86::Disassembler disassembler(stream); | ||||
| 
 | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ | |||
| #include <AK/RefPtr.h> | ||||
| #include <LibCore/File.h> | ||||
| #include <LibCoreDump/CoreDumpReader.h> | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/Image.h> | ||||
| #include <stdio.h> | ||||
| #include <sys/stat.h> | ||||
| 
 | ||||
|  | @ -58,7 +58,7 @@ static String object_name(StringView memory_region_name) | |||
| 
 | ||||
| struct CachedLibData { | ||||
|     OwnPtr<MappedFile> file; | ||||
|     NonnullRefPtr<ELF::Loader> lib_elf; | ||||
|     ELF::Image lib_elf; | ||||
| }; | ||||
| 
 | ||||
| static String symbolicate(FlatPtr eip, const ELF::Core::MemoryRegionInfo* region, u32& offset) | ||||
|  | @ -86,13 +86,13 @@ static String symbolicate(FlatPtr eip, const ELF::Core::MemoryRegionInfo* region | |||
|         auto lib_file = make<MappedFile>(path); | ||||
|         if (!lib_file->is_valid()) | ||||
|             return {}; | ||||
|         auto loader = ELF::Loader::create((const u8*)lib_file->data(), lib_file->size()); | ||||
|         cached_libs.set(path, make<CachedLibData>(move(lib_file), loader)); | ||||
|         auto image = ELF::Image((const u8*)lib_file->data(), lib_file->size()); | ||||
|         cached_libs.set(path, make<CachedLibData>(move(lib_file), move(image))); | ||||
|     } | ||||
| 
 | ||||
|     auto lib_data = cached_libs.get(path).value(); | ||||
| 
 | ||||
|     return String::format("[%s] %s", name.characters(), lib_data->lib_elf->symbolicate(eip - region->region_start, &offset).characters()); | ||||
|     return String::format("[%s] %s", name.characters(), lib_data->lib_elf.symbolicate(eip - region->region_start, &offset).characters()); | ||||
| } | ||||
| 
 | ||||
| static String symbolicate_from_coredump(CoreDumpReader& coredump, u32 ptr, [[maybe_unused]] u32& offset) | ||||
|  | @ -288,9 +288,9 @@ OwnPtr<Profile> Profile::load_from_perfcore_file(const StringView& path) | |||
|     } | ||||
| 
 | ||||
|     MappedFile kernel_elf_file("/boot/Kernel"); | ||||
|     RefPtr<ELF::Loader> kernel_elf_loader; | ||||
|     OwnPtr<ELF::Image> kernel_elf; | ||||
|     if (kernel_elf_file.is_valid()) | ||||
|         kernel_elf_loader = ELF::Loader::create(static_cast<const u8*>(kernel_elf_file.data()), kernel_elf_file.size()); | ||||
|         kernel_elf = make<ELF::Image>(static_cast<const u8*>(kernel_elf_file.data()), kernel_elf_file.size()); | ||||
| 
 | ||||
|     auto events_value = object.get("events"); | ||||
|     if (!events_value.is_array()) | ||||
|  | @ -325,8 +325,8 @@ OwnPtr<Profile> Profile::load_from_perfcore_file(const StringView& path) | |||
|             String symbol; | ||||
| 
 | ||||
|             if (ptr >= 0xc0000000) { | ||||
|                 if (kernel_elf_loader) { | ||||
|                     symbol = kernel_elf_loader->symbolicate(ptr, &offset); | ||||
|                 if (kernel_elf) { | ||||
|                     symbol = kernel_elf->symbolicate(ptr, &offset); | ||||
|                 } else { | ||||
|                     symbol = "??"; | ||||
|                 } | ||||
|  |  | |||
|  | @ -309,14 +309,13 @@ String Emulator::create_backtrace_line(FlatPtr address) | |||
|         if (!mapped_file.is_valid()) | ||||
|             return minimal; | ||||
| 
 | ||||
|         auto loader = ELF::Loader::create((const u8*)mapped_file.data(), mapped_file.size()); | ||||
|         auto debug_info = make<Debug::DebugInfo>(loader); | ||||
|         m_dynamic_library_cache.set(lib_path, CachedELF { move(mapped_file), move(loader), move(debug_info) }); | ||||
|         auto debug_info = make<Debug::DebugInfo>(make<ELF::Image>((const u8*)mapped_file.data(), mapped_file.size())); | ||||
|         m_dynamic_library_cache.set(lib_path, CachedELF { move(mapped_file), move(debug_info) }); | ||||
|     } | ||||
| 
 | ||||
|     auto it = m_dynamic_library_cache.find(lib_path); | ||||
|     auto& loader = *it->value.elf_loader; | ||||
|     String symbol = loader.symbolicate(address - region->base()); | ||||
|     auto& elf = it->value.debug_info->elf(); | ||||
|     String symbol = elf.symbolicate(address - region->base()); | ||||
| 
 | ||||
|     auto line_without_source_info = String::format("=={%d}==    %p  [%s]: %s", getpid(), address, lib_name.characters(), symbol.characters()); | ||||
| 
 | ||||
|  |  | |||
|  | @ -34,7 +34,7 @@ | |||
| #include <AK/Types.h> | ||||
| #include <LibDebug/DebugInfo.h> | ||||
| #include <LibELF/AuxiliaryVector.h> | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/Image.h> | ||||
| #include <LibX86/Instruction.h> | ||||
| #include <signal.h> | ||||
| #include <sys/types.h> | ||||
|  | @ -208,8 +208,7 @@ private: | |||
| 
 | ||||
|     struct CachedELF { | ||||
|         MappedFile mapped_file; | ||||
|         NonnullRefPtr<ELF::Loader> elf_loader; | ||||
|         OwnPtr<Debug::DebugInfo> debug_info; | ||||
|         NonnullOwnPtr<Debug::DebugInfo> debug_info; | ||||
|     }; | ||||
| 
 | ||||
|     HashMap<String, CachedELF> m_dynamic_library_cache; | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ | |||
| #include <AK/StringBuilder.h> | ||||
| #include <LibCore/ArgsParser.h> | ||||
| #include <LibCore/DirIterator.h> | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/Image.h> | ||||
| #include <getopt.h> | ||||
| #include <pthread.h> | ||||
| #include <string.h> | ||||
|  |  | |||
|  | @ -224,7 +224,6 @@ set(AK_SOURCES | |||
| 
 | ||||
| set(ELF_SOURCES | ||||
|     ../Libraries/LibELF/Image.cpp | ||||
|     ../Libraries/LibELF/Loader.cpp | ||||
|     ../Libraries/LibELF/Validation.cpp | ||||
| ) | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ | |||
| #include <Kernel/KSyms.h> | ||||
| #include <Kernel/Module.h> | ||||
| #include <Kernel/Process.h> | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/Image.h> | ||||
| 
 | ||||
| namespace Kernel { | ||||
| 
 | ||||
|  |  | |||
|  | @ -35,9 +35,9 @@ | |||
| 
 | ||||
| namespace Debug { | ||||
| 
 | ||||
| DebugInfo::DebugInfo(NonnullRefPtr<const ELF::Loader> elf) | ||||
|     : m_elf(elf) | ||||
|     , m_dwarf_info(Dwarf::DwarfInfo::create(m_elf)) | ||||
| DebugInfo::DebugInfo(NonnullOwnPtr<const ELF::Image> elf) | ||||
|     : m_elf(move(elf)) | ||||
|     , m_dwarf_info(*m_elf) | ||||
| { | ||||
|     prepare_variable_scopes(); | ||||
|     prepare_lines(); | ||||
|  | @ -45,7 +45,7 @@ DebugInfo::DebugInfo(NonnullRefPtr<const ELF::Loader> elf) | |||
| 
 | ||||
| void DebugInfo::prepare_variable_scopes() | ||||
| { | ||||
|     m_dwarf_info->for_each_compilation_unit([&](const Dwarf::CompilationUnit& unit) { | ||||
|     m_dwarf_info.for_each_compilation_unit([&](const Dwarf::CompilationUnit& unit) { | ||||
|         auto root = unit.root_die(); | ||||
|         parse_scopes_impl(root); | ||||
|     }); | ||||
|  | @ -102,7 +102,7 @@ void DebugInfo::parse_scopes_impl(const Dwarf::DIE& die) | |||
| 
 | ||||
| void DebugInfo::prepare_lines() | ||||
| { | ||||
|     auto section = m_elf->image().lookup_section(".debug_line"); | ||||
|     auto section = elf().lookup_section(".debug_line"); | ||||
|     if (section.is_undefined()) | ||||
|         return; | ||||
| 
 | ||||
|  |  | |||
|  | @ -33,14 +33,16 @@ | |||
| #include <LibDebug/Dwarf/DIE.h> | ||||
| #include <LibDebug/Dwarf/DwarfInfo.h> | ||||
| #include <LibDebug/Dwarf/LineProgram.h> | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/Image.h> | ||||
| #include <sys/arch/i386/regs.h> | ||||
| 
 | ||||
| namespace Debug { | ||||
| 
 | ||||
| class DebugInfo { | ||||
| public: | ||||
|     explicit DebugInfo(NonnullRefPtr<const ELF::Loader> elf); | ||||
|     explicit DebugInfo(NonnullOwnPtr<const ELF::Image>); | ||||
| 
 | ||||
|     const ELF::Image& elf() const { return *m_elf; } | ||||
| 
 | ||||
|     struct SourcePosition { | ||||
|         FlyString file_path; | ||||
|  | @ -117,8 +119,8 @@ private: | |||
|     void parse_scopes_impl(const Dwarf::DIE& die); | ||||
|     OwnPtr<VariableInfo> create_variable_info(const Dwarf::DIE& variable_die, const PtraceRegisters&) const; | ||||
| 
 | ||||
|     NonnullRefPtr<const ELF::Loader> m_elf; | ||||
|     NonnullRefPtr<Dwarf::DwarfInfo> m_dwarf_info; | ||||
|     NonnullOwnPtr<const ELF::Image> m_elf; | ||||
|     Dwarf::DwarfInfo m_dwarf_info; | ||||
| 
 | ||||
|     Vector<VariablesScope> m_scopes; | ||||
|     Vector<Dwarf::LineProgram::LineInfo> m_sorted_lines; | ||||
|  |  | |||
|  | @ -33,8 +33,7 @@ namespace Debug { | |||
| DebugSession::DebugSession(pid_t pid) | ||||
|     : m_debuggee_pid(pid) | ||||
|     , m_executable(map_executable_for_process(pid)) | ||||
|     , m_elf(ELF::Loader::create(reinterpret_cast<const u8*>(m_executable.data()), m_executable.size())) | ||||
|     , m_debug_info(m_elf) | ||||
|     , m_debug_info(make<ELF::Image>(reinterpret_cast<const u8*>(m_executable.data()), m_executable.size())) | ||||
| { | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -35,7 +35,6 @@ | |||
| #include <AK/String.h> | ||||
| #include <LibC/sys/arch/i386/regs.h> | ||||
| #include <LibDebug/DebugInfo.h> | ||||
| #include <LibELF/Loader.h> | ||||
| #include <signal.h> | ||||
| #include <stdio.h> | ||||
| #include <sys/ptrace.h> | ||||
|  | @ -99,8 +98,7 @@ public: | |||
|     template<typename Callback> | ||||
|     void run(Callback callback); | ||||
| 
 | ||||
|     const ELF::Loader& elf() const { return *m_elf; } | ||||
|     NonnullRefPtr<const ELF::Loader> elf_ref() const { return m_elf; } | ||||
|     const ELF::Image& elf() const { return m_debug_info.elf(); } | ||||
|     const MappedFile& executable() const { return m_executable; } | ||||
|     const DebugInfo& debug_info() const { return m_debug_info; } | ||||
| 
 | ||||
|  | @ -130,7 +128,6 @@ private: | |||
|     bool m_is_debuggee_dead { false }; | ||||
| 
 | ||||
|     MappedFile m_executable; | ||||
|     NonnullRefPtr<const ELF::Loader> m_elf; | ||||
|     DebugInfo m_debug_info; | ||||
| 
 | ||||
|     HashMap<void*, BreakPoint> m_breakpoints; | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ | |||
| 
 | ||||
| namespace Debug::Dwarf { | ||||
| 
 | ||||
| DwarfInfo::DwarfInfo(NonnullRefPtr<const ELF::Loader> elf) | ||||
| DwarfInfo::DwarfInfo(const ELF::Image& elf) | ||||
|     : m_elf(elf) | ||||
| { | ||||
|     m_debug_info_data = section_data(".debug_info"); | ||||
|  | @ -42,7 +42,7 @@ DwarfInfo::DwarfInfo(NonnullRefPtr<const ELF::Loader> elf) | |||
| 
 | ||||
| ReadonlyBytes DwarfInfo::section_data(const String& section_name) const | ||||
| { | ||||
|     auto section = m_elf->image().lookup_section(section_name); | ||||
|     auto section = m_elf.lookup_section(section_name); | ||||
|     if (section.is_undefined()) | ||||
|         return {}; | ||||
|     return section.bytes(); | ||||
|  |  | |||
|  | @ -32,13 +32,13 @@ | |||
| #include <AK/NonnullRefPtr.h> | ||||
| #include <AK/RefCounted.h> | ||||
| #include <AK/String.h> | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/Image.h> | ||||
| 
 | ||||
| namespace Debug::Dwarf { | ||||
| 
 | ||||
| class DwarfInfo : public RefCounted<DwarfInfo> { | ||||
| class DwarfInfo { | ||||
| public: | ||||
|     static NonnullRefPtr<DwarfInfo> create(NonnullRefPtr<const ELF::Loader> elf) { return adopt(*new DwarfInfo(move(elf))); } | ||||
|     explicit DwarfInfo(const ELF::Image&); | ||||
| 
 | ||||
|     ReadonlyBytes debug_info_data() const { return m_debug_info_data; } | ||||
|     ReadonlyBytes abbreviation_data() const { return m_abbreviation_data; } | ||||
|  | @ -48,12 +48,11 @@ public: | |||
|     void for_each_compilation_unit(Callback) const; | ||||
| 
 | ||||
| private: | ||||
|     explicit DwarfInfo(NonnullRefPtr<const ELF::Loader> elf); | ||||
|     void populate_compilation_units(); | ||||
| 
 | ||||
|     ReadonlyBytes section_data(const String& section_name) const; | ||||
| 
 | ||||
|     NonnullRefPtr<const ELF::Loader> m_elf; | ||||
|     const ELF::Image& m_elf; | ||||
|     ReadonlyBytes m_debug_info_data; | ||||
|     ReadonlyBytes m_abbreviation_data; | ||||
|     ReadonlyBytes m_debug_strings_data; | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ | |||
| 
 | ||||
| #include <AK/Demangle.h> | ||||
| #include <AK/Memory.h> | ||||
| #include <AK/QuickSort.h> | ||||
| #include <AK/StringBuilder.h> | ||||
| #include <AK/StringView.h> | ||||
| #include <LibELF/Image.h> | ||||
|  | @ -323,4 +324,84 @@ Optional<Image::Symbol> Image::find_demangled_function(const String& name) const | |||
|     return found; | ||||
| } | ||||
| 
 | ||||
| Optional<Image::Symbol> Image::find_symbol(u32 address, u32* out_offset) const | ||||
| { | ||||
|     auto symbol_count = this->symbol_count(); | ||||
|     if (!symbol_count) | ||||
|         return {}; | ||||
| 
 | ||||
|     SortedSymbol* sorted_symbols = nullptr; | ||||
|     if (m_sorted_symbols.is_empty()) { | ||||
|         m_sorted_symbols.ensure_capacity(symbol_count); | ||||
|         for_each_symbol([this](auto& symbol) { | ||||
|             m_sorted_symbols.append({ symbol.value(), symbol.name(), {}, symbol }); | ||||
|             return IterationDecision::Continue; | ||||
|         }); | ||||
|         quick_sort(m_sorted_symbols, [](auto& a, auto& b) { | ||||
|             return a.address < b.address; | ||||
|         }); | ||||
|     } | ||||
|     sorted_symbols = m_sorted_symbols.data(); | ||||
| 
 | ||||
|     for (size_t i = 0; i < symbol_count; ++i) { | ||||
|         if (sorted_symbols[i].address > address) { | ||||
|             if (i == 0) | ||||
|                 return {}; | ||||
|             auto& symbol = sorted_symbols[i - 1]; | ||||
|             if (out_offset) | ||||
|                 *out_offset = address - symbol.address; | ||||
|             return symbol.symbol; | ||||
|         } | ||||
|     } | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| String Image::symbolicate(u32 address, u32* out_offset) const | ||||
| { | ||||
|     auto symbol_count = this->symbol_count(); | ||||
|     if (!symbol_count) { | ||||
|         if (out_offset) | ||||
|             *out_offset = 0; | ||||
|         return "??"; | ||||
|     } | ||||
|     SortedSymbol* sorted_symbols = nullptr; | ||||
| 
 | ||||
|     if (m_sorted_symbols.is_empty()) { | ||||
|         m_sorted_symbols.ensure_capacity(symbol_count); | ||||
|         for_each_symbol([this](auto& symbol) { | ||||
|             m_sorted_symbols.append({ symbol.value(), symbol.name(), {}, {} }); | ||||
|             return IterationDecision::Continue; | ||||
|         }); | ||||
|         quick_sort(m_sorted_symbols, [](auto& a, auto& b) { | ||||
|             return a.address < b.address; | ||||
|         }); | ||||
|     } | ||||
|     sorted_symbols = m_sorted_symbols.data(); | ||||
| 
 | ||||
|     for (size_t i = 0; i < symbol_count; ++i) { | ||||
|         if (sorted_symbols[i].address > address) { | ||||
|             if (i == 0) { | ||||
|                 if (out_offset) | ||||
|                     *out_offset = 0; | ||||
|                 return "!!"; | ||||
|             } | ||||
|             auto& symbol = sorted_symbols[i - 1]; | ||||
| 
 | ||||
|             auto& demangled_name = symbol.demangled_name; | ||||
|             if (demangled_name.is_null()) { | ||||
|                 demangled_name = demangle(symbol.name); | ||||
|             } | ||||
| 
 | ||||
|             if (out_offset) { | ||||
|                 *out_offset = address - symbol.address; | ||||
|                 return demangled_name; | ||||
|             } | ||||
|             return String::format("%s +%u", demangled_name.characters(), address - symbol.address); | ||||
|         } | ||||
|     } | ||||
|     if (out_offset) | ||||
|         *out_offset = 0; | ||||
|     return "??"; | ||||
| } | ||||
| 
 | ||||
| } // end namespace ELF
 | ||||
|  |  | |||
|  | @ -210,6 +210,10 @@ public: | |||
| 
 | ||||
|     Optional<Symbol> find_demangled_function(const String& name) const; | ||||
| 
 | ||||
|     bool has_symbols() const { return symbol_count(); } | ||||
|     String symbolicate(u32 address, u32* offset = nullptr) const; | ||||
|     Optional<Image::Symbol> find_symbol(u32 address, u32* offset = nullptr) const; | ||||
| 
 | ||||
| private: | ||||
|     const char* raw_data(unsigned offset) const; | ||||
|     const Elf32_Ehdr& header() const; | ||||
|  | @ -227,6 +231,15 @@ private: | |||
|     bool m_valid { false }; | ||||
|     unsigned m_symbol_table_section_index { 0 }; | ||||
|     unsigned m_string_table_section_index { 0 }; | ||||
| 
 | ||||
|     struct SortedSymbol { | ||||
|         u32 address; | ||||
|         StringView name; | ||||
|         String demangled_name; | ||||
|         Optional<Image::Symbol> symbol; | ||||
|     }; | ||||
| 
 | ||||
|     mutable Vector<SortedSymbol> m_sorted_symbols; | ||||
| }; | ||||
| 
 | ||||
| template<typename F> | ||||
|  |  | |||
|  | @ -1,128 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  * | ||||
|  * 1. Redistributions of source code must retain the above copyright notice, this | ||||
|  *    list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||
|  *    this list of conditions and the following disclaimer in the documentation | ||||
|  *    and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
|  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
|  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
|  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
|  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
|  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
|  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
|  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| #include "Loader.h" | ||||
| #include <AK/Demangle.h> | ||||
| #include <AK/Memory.h> | ||||
| #include <AK/QuickSort.h> | ||||
| 
 | ||||
| //#define Loader_DEBUG
 | ||||
| 
 | ||||
| namespace ELF { | ||||
| 
 | ||||
| Loader::Loader(const u8* buffer, size_t size, String&&, bool verbose_logging) | ||||
|     : m_image(buffer, size, verbose_logging) | ||||
| { | ||||
|     if (m_image.is_valid()) | ||||
|         m_symbol_count = m_image.symbol_count(); | ||||
| } | ||||
| 
 | ||||
| Loader::~Loader() | ||||
| { | ||||
| } | ||||
| 
 | ||||
| #ifndef KERNEL | ||||
| Optional<Image::Symbol> Loader::find_symbol(u32 address, u32* out_offset) const | ||||
| { | ||||
|     if (!m_symbol_count) | ||||
|         return {}; | ||||
| 
 | ||||
|     SortedSymbol* sorted_symbols = nullptr; | ||||
|     if (m_sorted_symbols.is_empty()) { | ||||
|         m_sorted_symbols.ensure_capacity(m_symbol_count); | ||||
|         m_image.for_each_symbol([this](auto& symbol) { | ||||
|             m_sorted_symbols.append({ symbol.value(), symbol.name(), {}, symbol }); | ||||
|             return IterationDecision::Continue; | ||||
|         }); | ||||
|         quick_sort(m_sorted_symbols, [](auto& a, auto& b) { | ||||
|             return a.address < b.address; | ||||
|         }); | ||||
|     } | ||||
|     sorted_symbols = m_sorted_symbols.data(); | ||||
| 
 | ||||
|     for (size_t i = 0; i < m_symbol_count; ++i) { | ||||
|         if (sorted_symbols[i].address > address) { | ||||
|             if (i == 0) | ||||
|                 return {}; | ||||
|             auto& symbol = sorted_symbols[i - 1]; | ||||
|             if (out_offset) | ||||
|                 *out_offset = address - symbol.address; | ||||
|             return symbol.symbol; | ||||
|         } | ||||
|     } | ||||
|     return {}; | ||||
| } | ||||
| 
 | ||||
| String Loader::symbolicate(u32 address, u32* out_offset) const | ||||
| { | ||||
|     if (!m_symbol_count) { | ||||
|         if (out_offset) | ||||
|             *out_offset = 0; | ||||
|         return "??"; | ||||
|     } | ||||
|     SortedSymbol* sorted_symbols = nullptr; | ||||
| 
 | ||||
|     if (m_sorted_symbols.is_empty()) { | ||||
|         m_sorted_symbols.ensure_capacity(m_symbol_count); | ||||
|         m_image.for_each_symbol([this](auto& symbol) { | ||||
|             m_sorted_symbols.append({ symbol.value(), symbol.name(), {}, {} }); | ||||
|             return IterationDecision::Continue; | ||||
|         }); | ||||
|         quick_sort(m_sorted_symbols, [](auto& a, auto& b) { | ||||
|             return a.address < b.address; | ||||
|         }); | ||||
|     } | ||||
|     sorted_symbols = m_sorted_symbols.data(); | ||||
| 
 | ||||
|     for (size_t i = 0; i < m_symbol_count; ++i) { | ||||
|         if (sorted_symbols[i].address > address) { | ||||
|             if (i == 0) { | ||||
|                 if (out_offset) | ||||
|                     *out_offset = 0; | ||||
|                 return "!!"; | ||||
|             } | ||||
|             auto& symbol = sorted_symbols[i - 1]; | ||||
| 
 | ||||
|             auto& demangled_name = symbol.demangled_name; | ||||
|             if (demangled_name.is_null()) { | ||||
|                 demangled_name = demangle(symbol.name); | ||||
|             } | ||||
| 
 | ||||
|             if (out_offset) { | ||||
|                 *out_offset = address - symbol.address; | ||||
|                 return demangled_name; | ||||
|             } | ||||
|             return String::format("%s +%u", demangled_name.characters(), address - symbol.address); | ||||
|         } | ||||
|     } | ||||
|     if (out_offset) | ||||
|         *out_offset = 0; | ||||
|     return "??"; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| 
 | ||||
| } // end namespace ELF
 | ||||
|  | @ -1,85 +0,0 @@ | |||
| /*
 | ||||
|  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions are met: | ||||
|  * | ||||
|  * 1. Redistributions of source code must retain the above copyright notice, this | ||||
|  *    list of conditions and the following disclaimer. | ||||
|  * | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright notice, | ||||
|  *    this list of conditions and the following disclaimer in the documentation | ||||
|  *    and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||||
|  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||||
|  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||||
|  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
|  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||||
|  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||||
|  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
|  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
|  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <AK/Function.h> | ||||
| #include <AK/HashMap.h> | ||||
| #include <AK/NonnullRefPtr.h> | ||||
| #include <AK/OwnPtr.h> | ||||
| #include <AK/StringView.h> | ||||
| #include <AK/Vector.h> | ||||
| #include <LibELF/Image.h> | ||||
| 
 | ||||
| #ifdef KERNEL | ||||
| #    include <Kernel/VirtualAddress.h> | ||||
| namespace Kernel { | ||||
| class Region; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| namespace ELF { | ||||
| 
 | ||||
| class Loader : public RefCounted<Loader> { | ||||
| public: | ||||
|     static NonnullRefPtr<Loader> create(const u8* data, size_t size, String&& name = String::empty(), bool verbose_logging = true) { return adopt(*new Loader(data, size, move(name), verbose_logging)); } | ||||
|     ~Loader(); | ||||
| 
 | ||||
|     VirtualAddress entry() const | ||||
|     { | ||||
|         return m_image.entry(); | ||||
|     } | ||||
|     const Image& image() const { return m_image; } | ||||
|     Optional<Image::Symbol> find_demangled_function(const String& name) const | ||||
|     { | ||||
|         return m_image.find_demangled_function(name); | ||||
|     } | ||||
| 
 | ||||
|     bool has_symbols() const { return m_symbol_count; } | ||||
| 
 | ||||
|     String symbolicate(u32 address, u32* offset = nullptr) const; | ||||
|     Optional<Image::Symbol> find_symbol(u32 address, u32* offset = nullptr) const; | ||||
| 
 | ||||
| private: | ||||
|     explicit Loader(const u8*, size_t, String&& name, bool verbose_logging); | ||||
| 
 | ||||
|     bool layout(); | ||||
| 
 | ||||
|     Image m_image; | ||||
| 
 | ||||
|     size_t m_symbol_count { 0 }; | ||||
| 
 | ||||
|     struct SortedSymbol { | ||||
|         u32 address; | ||||
|         StringView name; | ||||
|         String demangled_name; | ||||
|         Optional<Image::Symbol> symbol; | ||||
|     }; | ||||
| 
 | ||||
|     mutable Vector<SortedSymbol> m_sorted_symbols; | ||||
| }; | ||||
| 
 | ||||
| } // end namespace ELF
 | ||||
|  | @ -26,23 +26,23 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/Image.h> | ||||
| 
 | ||||
| namespace X86 { | ||||
| 
 | ||||
| class ELFSymbolProvider final : public SymbolProvider { | ||||
| public: | ||||
|     ELFSymbolProvider(ELF::Loader& loader) | ||||
|         : m_loader(loader) | ||||
|     ELFSymbolProvider(const ELF::Image& elf) | ||||
|         : m_elf(elf) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|     virtual String symbolicate(FlatPtr address, u32* offset = nullptr) const override | ||||
|     { | ||||
|         return m_loader.symbolicate(address, offset); | ||||
|         return m_elf.symbolicate(address, offset); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     ELF::Loader& m_loader; | ||||
|     const ELF::Image& m_elf; | ||||
| }; | ||||
| } | ||||
|  |  | |||
|  | @ -24,12 +24,12 @@ | |||
|  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
|  */ | ||||
| 
 | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/Image.h> | ||||
| #include <stddef.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) | ||||
| { | ||||
|     ELF::Loader::create(data, size, /*name=*/ {}, /*verbose_logging=*/false); | ||||
|     ELF::Image elf(data, size, /*verbose_logging=*/false); | ||||
|     return 0; | ||||
| } | ||||
|  |  | |||
|  | @ -38,7 +38,6 @@ | |||
| #include <LibELF/DynamicLoader.h> | ||||
| #include <LibELF/DynamicObject.h> | ||||
| #include <LibELF/Image.h> | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/exec_elf.h> | ||||
| #include <dlfcn.h> | ||||
| #include <string.h> | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ | |||
| #include <AK/QuickSort.h> | ||||
| #include <AK/Vector.h> | ||||
| #include <LibCore/ArgsParser.h> | ||||
| #include <LibELF/Loader.h> | ||||
| #include <LibELF/Image.h> | ||||
| #include <LibX86/Disassembler.h> | ||||
| #include <LibX86/ELFSymbolProvider.h> | ||||
| #include <stdio.h> | ||||
|  | @ -70,14 +70,13 @@ int main(int argc, char** argv) | |||
|     size_t asm_size = file.size(); | ||||
|     size_t file_offset = 0; | ||||
|     Vector<Symbol>::Iterator current_symbol = symbols.begin(); | ||||
|     RefPtr<ELF::Loader> elf; | ||||
|     OwnPtr<X86::ELFSymbolProvider> symbol_provider; // nullptr for non-ELF disassembly.
 | ||||
|     OwnPtr<ELF::Image> elf; | ||||
|     if (asm_size >= 4 && strncmp((const char*)asm_data, "\u007fELF", 4) == 0) { | ||||
|         NonnullRefPtr<ELF::Loader> elf_loader = ELF::Loader::create(asm_data, asm_size); | ||||
|         if (elf_loader->image().is_valid()) { | ||||
|             elf = elf_loader; | ||||
|         elf = make<ELF::Image>(asm_data, asm_size); | ||||
|         if (elf->is_valid()) { | ||||
|             symbol_provider = make<X86::ELFSymbolProvider>(*elf); | ||||
|             elf->image().for_each_section_of_type(SHT_PROGBITS, [&](const ELF::Image::Section& section) { | ||||
|             elf->for_each_section_of_type(SHT_PROGBITS, [&](const ELF::Image::Section& section) { | ||||
|                 // FIXME: Disassemble all SHT_PROGBITS sections, not just .text.
 | ||||
|                 if (section.name() != ".text") | ||||
|                     return IterationDecision::Continue; | ||||
|  | @ -86,9 +85,9 @@ int main(int argc, char** argv) | |||
|                 file_offset = section.address(); | ||||
|                 return IterationDecision::Break; | ||||
|             }); | ||||
|             symbols.ensure_capacity(elf->image().symbol_count() + 1); | ||||
|             symbols.ensure_capacity(elf->symbol_count() + 1); | ||||
|             symbols.append({ 0, 0, StringView() }); // Sentinel.
 | ||||
|             elf->image().for_each_symbol([&](const ELF::Image::Symbol& symbol) { | ||||
|             elf->for_each_symbol([&](const ELF::Image::Symbol& symbol) { | ||||
|                 symbols.append({ symbol.value(), symbol.size(), symbol.name() }); | ||||
|                 return IterationDecision::Continue; | ||||
|             }); | ||||
|  |  | |||
|  | @ -86,7 +86,7 @@ static NonnullOwnPtr<HashMap<void*, X86::Instruction>> instrument_code() | |||
| { | ||||
|     [[maybe_unused]] auto r = demangle("foo"); // Required for linked with __cxa_demangle
 | ||||
|     auto instrumented = make<HashMap<void*, X86::Instruction>>(); | ||||
|     g_debug_session->elf().image().for_each_section_of_type(SHT_PROGBITS, [&](const ELF::Image::Section& section) { | ||||
|     g_debug_session->elf().for_each_section_of_type(SHT_PROGBITS, [&](const ELF::Image::Section& section) { | ||||
|         if (section.name() != ".text") | ||||
|             return IterationDecision::Continue; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling