1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
/*
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "Process.h"
#include <LibCore/File.h>
namespace Profiler {
Thread* Process::find_thread(pid_t tid, EventSerialNumber serial)
{
auto it = threads.find(tid);
if (it == threads.end())
return nullptr;
for (auto& thread : it->value) {
if (thread.start_valid < serial && (thread.end_valid == EventSerialNumber {} || thread.end_valid > serial))
return &thread;
}
return nullptr;
}
void Process::handle_thread_create(pid_t tid, EventSerialNumber serial)
{
auto it = threads.find(tid);
if (it == threads.end()) {
threads.set(tid, {});
it = threads.find(tid);
}
auto thread = Thread { tid, serial, {} };
it->value.append(move(thread));
}
void Process::handle_thread_exit(pid_t tid, EventSerialNumber serial)
{
auto* thread = find_thread(tid, serial);
if (!thread)
return;
thread->end_valid = serial;
}
HashMap<String, OwnPtr<MappedObject>> g_mapped_object_cache;
static MappedObject* get_or_create_mapped_object(String const& path)
{
if (auto it = g_mapped_object_cache.find(path); it != g_mapped_object_cache.end())
return it->value.ptr();
auto file_or_error = Core::MappedFile::map(path);
if (file_or_error.is_error()) {
g_mapped_object_cache.set(path, {});
return nullptr;
}
auto elf = ELF::Image(file_or_error.value()->bytes());
if (!elf.is_valid()) {
g_mapped_object_cache.set(path, {});
return nullptr;
}
auto new_mapped_object = adopt_own(*new MappedObject {
.file = file_or_error.release_value(),
.elf = elf,
});
auto* ptr = new_mapped_object.ptr();
g_mapped_object_cache.set(path, move(new_mapped_object));
return ptr;
}
void LibraryMetadata::handle_mmap(FlatPtr base, size_t size, String const& name)
{
StringView path;
if (name.contains("Loader.so"sv))
path = "Loader.so"sv;
else if (!name.contains(':'))
return;
else
path = name.substring_view(0, name.view().find(':').value());
// Each loaded object has at least 4 segments associated with it: .rodata, .text, .relro, .data.
// We only want to create a single LibraryMetadata object for each library, so we need to update the
// associated base address and size as new regions are discovered.
// We don't allocate a temporary String object if an entry already exists.
// This assumes that String::hash and StringView::hash return the same result.
auto string_view_compare = [&path](auto& entry) { return path == entry.key.view(); };
if (auto existing_it = m_libraries.find(path.hash(), string_view_compare); existing_it != m_libraries.end()) {
auto& entry = *existing_it->value;
entry.base = min(entry.base, base);
entry.size = max(entry.size + size, base - entry.base + size);
} else {
String path_string = path.to_string();
String full_path;
if (path_string.starts_with('/'))
full_path = path_string;
else if (Core::File::looks_like_shared_library(path_string))
full_path = String::formatted("/usr/lib/{}", path);
else
full_path = path_string;
auto* mapped_object = get_or_create_mapped_object(full_path);
if (!mapped_object) {
full_path = String::formatted("/usr/local/lib/{}", path);
mapped_object = get_or_create_mapped_object(full_path);
if (!mapped_object)
return;
}
m_libraries.set(path_string, adopt_own(*new Library { base, size, path_string, mapped_object, {} }));
}
}
Debug::DebugInfo const& LibraryMetadata::Library::load_debug_info(FlatPtr base_address) const
{
if (debug_info == nullptr)
debug_info = make<Debug::DebugInfo>(object->elf, String::empty(), base_address);
return *debug_info.ptr();
}
String LibraryMetadata::Library::symbolicate(FlatPtr ptr, u32* offset) const
{
if (!object)
return String::formatted("?? <{:p}>", ptr);
return object->elf.symbolicate(ptr - base, offset);
}
LibraryMetadata::Library const* LibraryMetadata::library_containing(FlatPtr ptr) const
{
for (auto& it : m_libraries) {
auto& library = *it.value;
if (ptr >= library.base && ptr < (library.base + library.size))
return &library;
}
return nullptr;
}
}
|