diff options
author | Andreas Kling <kling@serenityos.org> | 2021-08-22 14:51:04 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-08-23 00:02:09 +0200 |
commit | bcd2025311b97d45aeb23960e17fcae2bc5b7f2e (patch) | |
tree | facb4e412cdfcc5a9f5177c9f3cd0cd1e27a2f67 /Userland/Libraries/LibCoredump/Backtrace.cpp | |
parent | a930877f31fb117ce4b38d4782dd288093700d8a (diff) | |
download | serenity-bcd2025311b97d45aeb23960e17fcae2bc5b7f2e.zip |
Everywhere: Core dump => Coredump
We all know what a coredump is, and it feels more natural to refer to
it as a coredump (most code already does), so let's be consistent.
Diffstat (limited to 'Userland/Libraries/LibCoredump/Backtrace.cpp')
-rw-r--r-- | Userland/Libraries/LibCoredump/Backtrace.cpp | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/Userland/Libraries/LibCoredump/Backtrace.cpp b/Userland/Libraries/LibCoredump/Backtrace.cpp new file mode 100644 index 0000000000..1edbccc256 --- /dev/null +++ b/Userland/Libraries/LibCoredump/Backtrace.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2020, Linus Groh <linusg@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/LexicalPath.h> +#include <AK/MappedFile.h> +#include <AK/Platform.h> +#include <AK/StringBuilder.h> +#include <AK/Types.h> +#include <LibCore/File.h> +#include <LibCoredump/Backtrace.h> +#include <LibCoredump/Reader.h> +#include <LibELF/Core.h> +#include <LibELF/Image.h> + +namespace Coredump { + +ELFObjectInfo const* Backtrace::object_info_for_region(ELF::Core::MemoryRegionInfo const& region) +{ + auto path = region.object_name(); + if (!path.starts_with('/') && path.ends_with(".so"sv)) + path = LexicalPath::join("/usr/lib", path).string(); + + auto maybe_ptr = m_debug_info_cache.get(path); + if (maybe_ptr.has_value()) + return *maybe_ptr; + + if (!Core::File::exists(path)) + return nullptr; + + auto file_or_error = MappedFile::map(path); + if (file_or_error.is_error()) + return nullptr; + + auto image = make<ELF::Image>(file_or_error.value()->bytes()); + auto& image_reference = *image; + auto info = make<ELFObjectInfo>(file_or_error.release_value(), make<Debug::DebugInfo>(image_reference), move(image)); + auto* info_ptr = info.ptr(); + m_debug_info_cache.set(path, move(info)); + return info_ptr; +} + +Backtrace::Backtrace(const Reader& coredump, const ELF::Core::ThreadInfo& thread_info) + : m_thread_info(move(thread_info)) +{ + FlatPtr* bp; + FlatPtr* ip; +#if ARCH(I386) + bp = (FlatPtr*)m_thread_info.regs.ebp; + ip = (FlatPtr*)m_thread_info.regs.eip; +#else + bp = (FlatPtr*)m_thread_info.regs.rbp; + ip = (FlatPtr*)m_thread_info.regs.rip; +#endif + + bool first_frame = true; + while (bp && ip) { + // We use eip - 1 because the return address from a function frame + // is the instruction that comes after the 'call' instruction. + // However, because the first frame represents the faulting + // instruction rather than the return address we don't subtract + // 1 there. + VERIFY((FlatPtr)ip > 0); + add_entry(coredump, (FlatPtr)ip - (first_frame ? 0 : 1)); + first_frame = false; + auto next_ip = coredump.peek_memory((FlatPtr)(bp + 1)); + auto next_bp = coredump.peek_memory((FlatPtr)(bp)); + if (!next_ip.has_value() || !next_bp.has_value()) + break; + ip = (FlatPtr*)next_ip.value(); + bp = (FlatPtr*)next_bp.value(); + } +} + +Backtrace::~Backtrace() +{ +} + +void Backtrace::add_entry(const Reader& coredump, FlatPtr ip) +{ + auto* ip_region = coredump.region_containing((FlatPtr)ip); + if (!ip_region) { + m_entries.append({ ip, {}, {}, {} }); + return; + } + auto object_name = ip_region->object_name(); + if (object_name == "Loader.so") + return; + // We need to find the first region for the object, just in case + // the PT_LOAD header for the .text segment isn't the first one + // in the object file. + auto region = coredump.first_region_for_object(object_name); + auto* object_info = object_info_for_region(*region); + if (!object_info) + return; + + auto function_name = object_info->debug_info->elf().symbolicate(ip - region->region_start); + auto source_position = object_info->debug_info->get_source_position_with_inlines(ip - region->region_start); + m_entries.append({ ip, object_name, function_name, source_position }); +} + +String Backtrace::Entry::to_string(bool color) const +{ + StringBuilder builder; + builder.appendff("{:p}: ", eip); + if (object_name.is_empty()) { + builder.append("???"); + return builder.build(); + } + builder.appendff("[{}] {}", object_name, function_name.is_empty() ? "???" : function_name); + builder.append(" ("); + + Vector<Debug::DebugInfo::SourcePosition> source_positions; + + for (auto& position : source_position_with_inlines.inline_chain) { + if (!source_positions.contains_slow(position)) + source_positions.append(position); + } + + if (source_position_with_inlines.source_position.has_value() && !source_positions.contains_slow(source_position_with_inlines.source_position.value())) { + source_positions.insert(0, source_position_with_inlines.source_position.value()); + } + + for (size_t i = 0; i < source_positions.size(); ++i) { + auto& position = source_positions[i]; + auto fmt = color ? "\033[34;1m{}\033[0m:{}" : "{}:{}"; + builder.appendff(fmt, LexicalPath::basename(position.file_path), position.line_number); + if (i != source_positions.size() - 1) { + builder.append(" => "); + } + } + + builder.append(")"); + + return builder.build(); +} + +} |