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