1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 16:47:44 +00:00

Libraries: Move to Userland/Libraries/

This commit is contained in:
Andreas Kling 2021-01-12 12:17:30 +01:00
parent dc28c07fa5
commit 13d7c09125
1857 changed files with 266 additions and 274 deletions

View file

@ -0,0 +1,128 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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 <AK/LexicalPath.h>
#include <AK/MappedFile.h>
#include <AK/StringBuilder.h>
#include <AK/Types.h>
#include <LibCore/File.h>
#include <LibCoreDump/Backtrace.h>
#include <LibCoreDump/Reader.h>
#include <LibELF/CoreDump.h>
#include <LibELF/Image.h>
namespace CoreDump {
// 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, NonnullOwnPtr<ELFObjectInfo>> s_debug_info_cache;
static const ELFObjectInfo* object_info_for_region(const ELF::Core::MemoryRegionInfo& region)
{
auto name = region.object_name();
String path;
if (name.contains(".so"))
path = String::formatted("/usr/lib/{}", name);
else {
path = name;
}
if (auto it = s_debug_info_cache.find(path); it != s_debug_info_cache.end())
return it->value.ptr();
if (!Core::File::exists(path.characters()))
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 info = make<ELFObjectInfo>(file_or_error.release_value(), Debug::DebugInfo { move(image) });
auto* info_ptr = info.ptr();
s_debug_info_cache.set(path, move(info));
return info_ptr;
}
Backtrace::Backtrace(const Reader& coredump)
{
coredump.for_each_thread_info([this, &coredump](const ELF::Core::ThreadInfo& thread_info) {
uint32_t* ebp = (uint32_t*)thread_info.regs.ebp;
uint32_t* eip = (uint32_t*)thread_info.regs.eip;
while (ebp && eip) {
add_backtrace_entry(coredump, (FlatPtr)eip);
auto next_eip = coredump.peek_memory((FlatPtr)(ebp + 1));
auto next_ebp = coredump.peek_memory((FlatPtr)(ebp));
if (!next_eip.has_value() || !next_ebp.has_value())
break;
eip = (uint32_t*)next_eip.value();
ebp = (uint32_t*)next_ebp.value();
}
return IterationDecision::Continue;
});
}
Backtrace::~Backtrace()
{
}
void Backtrace::add_backtrace_entry(const Reader& coredump, FlatPtr eip)
{
auto* region = coredump.region_containing((FlatPtr)eip);
if (!region) {
m_entries.append({ eip, {}, {}, {} });
return;
}
auto object_name = region->object_name();
if (object_name == "Loader.so")
return;
auto* object_info = object_info_for_region(*region);
if (!object_info)
return;
auto function_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);
m_entries.append({ eip, 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);
if (source_position.has_value()) {
auto& source_position = this->source_position.value();
auto fmt = color ? " (\033[34;1m{}\033[0m:{})" : " ({}:{})";
builder.appendff(fmt, LexicalPath(source_position.file_path).basename(), source_position.line_number);
}
return builder.build();
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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/Types.h>
#include <LibCoreDump/Reader.h>
#include <LibDebug/DebugInfo.h>
namespace CoreDump {
struct ELFObjectInfo {
ELFObjectInfo(NonnullRefPtr<MappedFile> file, Debug::DebugInfo&& debug_info)
: file(move(file))
, debug_info(move(debug_info))
{
}
NonnullRefPtr<MappedFile> file;
Debug::DebugInfo debug_info;
};
class Backtrace {
public:
struct Entry {
FlatPtr eip;
String object_name;
String function_name;
Optional<Debug::DebugInfo::SourcePosition> source_position;
String to_string(bool color = false) const;
};
Backtrace(const Reader&);
~Backtrace();
const Vector<Entry> entries() const { return m_entries; }
private:
void add_backtrace_entry(const Reader&, FlatPtr eip);
Vector<Entry> m_entries;
};
}

View file

@ -0,0 +1,7 @@
set(SOURCES
Backtrace.cpp
Reader.cpp
)
serenity_lib(LibCoreDump coredump)
target_link_libraries(LibCoreDump LibC LibCore LibDebug)

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2020, Linus Groh <mail@linusgroh.de>
* 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
namespace CoreDump {
class Backtrace;
class Reader;
}

View file

@ -0,0 +1,215 @@
/*
* Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
* 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 <AK/JsonObject.h>
#include <AK/JsonValue.h>
#include <LibCoreDump/Backtrace.h>
#include <LibCoreDump/Reader.h>
#include <string.h>
#include <sys/stat.h>
namespace CoreDump {
OwnPtr<Reader> Reader::create(const String& path)
{
auto file_or_error = MappedFile::map(path);
if (file_or_error.is_error())
return {};
return adopt_own(*new Reader(file_or_error.release_value()));
}
Reader::Reader(NonnullRefPtr<MappedFile> coredump_file)
: m_coredump_file(move(coredump_file))
, m_coredump_image(m_coredump_file->bytes())
{
size_t index = 0;
m_coredump_image.for_each_program_header([this, &index](auto pheader) {
if (pheader.type() == PT_NOTE) {
m_notes_segment_index = index;
return IterationDecision::Break;
}
++index;
return IterationDecision::Continue;
});
ASSERT(m_notes_segment_index != -1);
}
Reader::~Reader()
{
}
Reader::NotesEntryIterator::NotesEntryIterator(const u8* notes_data)
: m_current((const ELF::Core::NotesEntry*)notes_data)
, start(notes_data)
{
}
ELF::Core::NotesEntryHeader::Type Reader::NotesEntryIterator::type() const
{
ASSERT(m_current->header.type == ELF::Core::NotesEntryHeader::Type::ProcessInfo
|| m_current->header.type == ELF::Core::NotesEntryHeader::Type::MemoryRegionInfo
|| m_current->header.type == ELF::Core::NotesEntryHeader::Type::ThreadInfo
|| m_current->header.type == ELF::Core::NotesEntryHeader::Type::Metadata
|| m_current->header.type == ELF::Core::NotesEntryHeader::Type::Null);
return m_current->header.type;
}
const ELF::Core::NotesEntry* Reader::NotesEntryIterator::current() const
{
return m_current;
}
void Reader::NotesEntryIterator::next()
{
ASSERT(!at_end());
switch (type()) {
case ELF::Core::NotesEntryHeader::Type::ProcessInfo: {
const auto* current = reinterpret_cast<const ELF::Core::ProcessInfo*>(m_current);
m_current = reinterpret_cast<const ELF::Core::NotesEntry*>(current->executable_path + strlen(current->executable_path) + 1);
break;
}
case ELF::Core::NotesEntryHeader::Type::ThreadInfo: {
const auto* current = reinterpret_cast<const ELF::Core::ThreadInfo*>(m_current);
m_current = reinterpret_cast<const ELF::Core::NotesEntry*>(current + 1);
break;
}
case ELF::Core::NotesEntryHeader::Type::MemoryRegionInfo: {
const auto* current = reinterpret_cast<const ELF::Core::MemoryRegionInfo*>(m_current);
m_current = reinterpret_cast<const ELF::Core::NotesEntry*>(current->region_name + strlen(current->region_name) + 1);
break;
}
case ELF::Core::NotesEntryHeader::Type::Metadata: {
const auto* current = reinterpret_cast<const ELF::Core::Metadata*>(m_current);
m_current = reinterpret_cast<const ELF::Core::NotesEntry*>(current->json_data + strlen(current->json_data) + 1);
break;
}
default:
ASSERT_NOT_REACHED();
}
}
bool Reader::NotesEntryIterator::at_end() const
{
return type() == ELF::Core::NotesEntryHeader::Type::Null;
}
Optional<uint32_t> Reader::peek_memory(FlatPtr address) const
{
const auto* region = region_containing(address);
if (!region)
return {};
FlatPtr offset_in_region = address - region->region_start;
const char* region_data = image().program_header(region->program_header_index).raw_data();
return *(const uint32_t*)(&region_data[offset_in_region]);
}
const ELF::Core::ProcessInfo& Reader::process_info() const
{
for (NotesEntryIterator it((const u8*)m_coredump_image.program_header(m_notes_segment_index).raw_data()); !it.at_end(); it.next()) {
if (it.type() != ELF::Core::NotesEntryHeader::Type::ProcessInfo)
continue;
return reinterpret_cast<const ELF::Core::ProcessInfo&>(*it.current());
}
ASSERT_NOT_REACHED();
}
const ELF::Core::MemoryRegionInfo* Reader::region_containing(FlatPtr address) const
{
const ELF::Core::MemoryRegionInfo* ret = nullptr;
for_each_memory_region_info([&ret, address](const ELF::Core::MemoryRegionInfo& region_info) {
if (region_info.region_start <= address && region_info.region_end >= address) {
ret = &region_info;
return IterationDecision::Break;
}
return IterationDecision::Continue;
});
return ret;
}
const Backtrace Reader::backtrace() const
{
return Backtrace(*this);
}
const HashMap<String, String> Reader::metadata() const
{
const ELF::Core::Metadata* metadata_notes_entry = nullptr;
for (NotesEntryIterator it((const u8*)m_coredump_image.program_header(m_notes_segment_index).raw_data()); !it.at_end(); it.next()) {
if (it.type() != ELF::Core::NotesEntryHeader::Type::Metadata)
continue;
metadata_notes_entry = reinterpret_cast<const ELF::Core::Metadata*>(it.current());
break;
}
if (!metadata_notes_entry)
return {};
auto metadata_json_value = JsonValue::from_string(metadata_notes_entry->json_data);
if (!metadata_json_value.has_value())
return {};
if (!metadata_json_value.value().is_object())
return {};
HashMap<String, String> metadata;
metadata_json_value.value().as_object().for_each_member([&](auto& key, auto& value) {
metadata.set(key, value.as_string_or({}));
});
return metadata;
}
struct LibraryData {
String name;
OwnPtr<MappedFile> file;
ELF::Image lib_elf;
};
const Reader::LibraryData* Reader::library_containing(FlatPtr address) const
{
static HashMap<String, OwnPtr<LibraryData>> cached_libs;
auto* region = region_containing(address);
if (!region)
return {};
auto name = region->object_name();
String path;
if (name.contains(".so"))
path = String::format("/usr/lib/%s", name.characters());
else {
path = name;
}
if (!cached_libs.contains(path)) {
auto file_or_error = MappedFile::map(path);
if (file_or_error.is_error())
return {};
auto image = ELF::Image(file_or_error.value()->bytes());
cached_libs.set(path, make<LibraryData>(name, region->region_start, file_or_error.release_value(), move(image)));
}
auto lib_data = cached_libs.get(path).value();
return lib_data;
}
}

View file

@ -0,0 +1,120 @@
/*
* Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
* 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/HashMap.h>
#include <AK/MappedFile.h>
#include <AK/Noncopyable.h>
#include <AK/OwnPtr.h>
#include <LibCoreDump/Forward.h>
#include <LibELF/CoreDump.h>
#include <LibELF/Image.h>
namespace CoreDump {
class Reader {
AK_MAKE_NONCOPYABLE(Reader);
AK_MAKE_NONMOVABLE(Reader);
public:
static OwnPtr<Reader> create(const String&);
~Reader();
const ELF::Core::ProcessInfo& process_info() const;
template<typename Func>
void for_each_memory_region_info(Func func) const;
template<typename Func>
void for_each_thread_info(Func func) const;
const ELF::Image& image() const { return m_coredump_image; }
Optional<uint32_t> peek_memory(FlatPtr address) const;
const ELF::Core::MemoryRegionInfo* region_containing(FlatPtr address) const;
struct LibraryData {
String name;
FlatPtr base_address { 0 };
NonnullRefPtr<MappedFile> file;
ELF::Image lib_elf;
};
const LibraryData* library_containing(FlatPtr address) const;
const Backtrace backtrace() const;
const HashMap<String, String> metadata() const;
private:
Reader(NonnullRefPtr<MappedFile>);
class NotesEntryIterator {
public:
NotesEntryIterator(const u8* notes_data);
ELF::Core::NotesEntryHeader::Type type() const;
const ELF::Core::NotesEntry* current() const;
void next();
bool at_end() const;
private:
const ELF::Core::NotesEntry* m_current { nullptr };
const u8* start { nullptr };
};
NonnullRefPtr<MappedFile> m_coredump_file;
ELF::Image m_coredump_image;
ssize_t m_notes_segment_index { -1 };
};
template<typename Func>
void Reader::for_each_memory_region_info(Func func) const
{
for (NotesEntryIterator it((const u8*)m_coredump_image.program_header(m_notes_segment_index).raw_data()); !it.at_end(); it.next()) {
if (it.type() != ELF::Core::NotesEntryHeader::Type::MemoryRegionInfo)
continue;
auto& memory_region_info = reinterpret_cast<const ELF::Core::MemoryRegionInfo&>(*it.current());
IterationDecision decision = func(memory_region_info);
if (decision == IterationDecision::Break)
return;
}
}
template<typename Func>
void Reader::for_each_thread_info(Func func) const
{
for (NotesEntryIterator it((const u8*)m_coredump_image.program_header(m_notes_segment_index).raw_data()); !it.at_end(); it.next()) {
if (it.type() != ELF::Core::NotesEntryHeader::Type::ThreadInfo)
continue;
auto& thread_info = reinterpret_cast<const ELF::Core::ThreadInfo&>(*it.current());
IterationDecision decision = func(thread_info);
if (decision == IterationDecision::Break)
return;
}
}
}