summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibSymbolication
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-05-22 17:15:18 +0200
committerAndreas Kling <kling@serenityos.org>2021-05-22 18:54:22 +0200
commitd783076a30ac62dc64862eb51bf79b144270aa7a (patch)
tree502846730a8355d50a6359fa689bffe37ecae284 /Userland/Libraries/LibSymbolication
parent21cd278b8ab8a8cc3b734e951cea4a26609ade84 (diff)
downloadserenity-d783076a30ac62dc64862eb51bf79b144270aa7a.zip
Userland: Rename LibSymbolClient => LibSymbolication
Diffstat (limited to 'Userland/Libraries/LibSymbolication')
-rw-r--r--Userland/Libraries/LibSymbolication/CMakeLists.txt11
-rw-r--r--Userland/Libraries/LibSymbolication/Client.cpp161
-rw-r--r--Userland/Libraries/LibSymbolication/Client.h41
3 files changed, 213 insertions, 0 deletions
diff --git a/Userland/Libraries/LibSymbolication/CMakeLists.txt b/Userland/Libraries/LibSymbolication/CMakeLists.txt
new file mode 100644
index 0000000000..09f64acbae
--- /dev/null
+++ b/Userland/Libraries/LibSymbolication/CMakeLists.txt
@@ -0,0 +1,11 @@
+set(SOURCES
+ Client.cpp
+)
+
+set(GENERATED_SOURCES
+ ../../Services/SymbolServer/SymbolClientEndpoint.h
+ ../../Services/SymbolServer/SymbolServerEndpoint.h
+)
+
+serenity_lib(LibSymbolication symbolclient)
+target_link_libraries(LibSymbolication LibIPC)
diff --git a/Userland/Libraries/LibSymbolication/Client.cpp b/Userland/Libraries/LibSymbolication/Client.cpp
new file mode 100644
index 0000000000..5d8bf405db
--- /dev/null
+++ b/Userland/Libraries/LibSymbolication/Client.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/JsonArray.h>
+#include <AK/JsonObject.h>
+#include <AK/JsonValue.h>
+#include <LibCore/File.h>
+#include <LibSymbolication/Client.h>
+
+namespace SymbolClient {
+
+Client::Client()
+ : IPC::ServerConnection<SymbolClientEndpoint, SymbolServerEndpoint>(*this, "/tmp/portal/symbol")
+{
+ handshake();
+}
+
+void Client::handshake()
+{
+ greet();
+}
+
+void Client::dummy()
+{
+}
+
+Optional<Symbol> Client::symbolicate(const String& path, FlatPtr address)
+{
+ auto response = IPCProxy::symbolicate(path, address);
+ if (!response.success())
+ return {};
+
+ return Symbol {
+ .address = address,
+ .name = response.name(),
+ .offset = response.offset(),
+ .filename = response.filename(),
+ .line_number = response.line()
+ };
+}
+
+Vector<Symbol> symbolicate_thread(pid_t pid, pid_t tid)
+{
+ struct RegionWithSymbols {
+ FlatPtr base { 0 };
+ size_t size { 0 };
+ String path;
+ bool is_relative { true };
+ };
+
+ Vector<FlatPtr> stack;
+ Vector<RegionWithSymbols> regions;
+
+ regions.append(RegionWithSymbols {
+ .base = 0xc0000000,
+ .size = 0x3fffffff,
+ .path = "/boot/Kernel",
+ .is_relative = false });
+
+ {
+
+ auto stack_path = String::formatted("/proc/{}/stacks/{}", pid, tid);
+ auto file_or_error = Core::File::open(stack_path, Core::OpenMode::ReadOnly);
+ if (file_or_error.is_error()) {
+ warnln("Could not open {}: {}", stack_path, file_or_error.error());
+ return {};
+ }
+
+ auto json = JsonValue::from_string(file_or_error.value()->read_all());
+ if (!json.has_value() || !json.value().is_array()) {
+ warnln("Invalid contents in {}", stack_path);
+ return {};
+ }
+
+ stack.ensure_capacity(json.value().as_array().size());
+ for (auto& value : json.value().as_array().values()) {
+ stack.append(value.to_u32());
+ }
+ }
+
+ {
+ auto vm_path = String::formatted("/proc/{}/vm", pid);
+ auto file_or_error = Core::File::open(vm_path, Core::OpenMode::ReadOnly);
+ if (file_or_error.is_error()) {
+ warnln("Could not open {}: {}", vm_path, file_or_error.error());
+ return {};
+ }
+
+ auto json = JsonValue::from_string(file_or_error.value()->read_all());
+ if (!json.has_value() || !json.value().is_array()) {
+ warnln("Invalid contents in {}", vm_path);
+ return {};
+ }
+
+ for (auto& region_value : json.value().as_array().values()) {
+ auto& region = region_value.as_object();
+ auto name = region.get("name").to_string();
+ auto address = region.get("address").to_u32();
+ auto size = region.get("size").to_u32();
+
+ String path;
+ if (name == "/usr/lib/Loader.so") {
+ path = name;
+ } else if (name.ends_with(": .text")) {
+ auto parts = name.split_view(':');
+ path = parts[0];
+ if (!path.starts_with('/'))
+ path = String::formatted("/usr/lib/{}", path);
+ } else {
+ continue;
+ }
+
+ RegionWithSymbols r;
+ r.base = address;
+ r.size = size;
+ r.path = path;
+ regions.append(move(r));
+ }
+ }
+
+ auto client = SymbolClient::Client::construct();
+
+ Vector<Symbol> symbols;
+
+ for (auto address : stack) {
+ const RegionWithSymbols* found_region = nullptr;
+ for (auto& region : regions) {
+ if (address >= region.base && address < (region.base + region.size)) {
+ found_region = &region;
+ break;
+ }
+ }
+
+ if (!found_region) {
+ outln("{:p} ??", address);
+ continue;
+ }
+
+ FlatPtr adjusted_address;
+ if (found_region->is_relative)
+ adjusted_address = address - found_region->base;
+ else
+ adjusted_address = address;
+
+ auto result = client->symbolicate(found_region->path, adjusted_address);
+ if (!result.has_value()) {
+ symbols.append(Symbol {
+ .address = address,
+ });
+ continue;
+ }
+
+ symbols.append(result.value());
+ }
+ return symbols;
+}
+
+}
diff --git a/Userland/Libraries/LibSymbolication/Client.h b/Userland/Libraries/LibSymbolication/Client.h
new file mode 100644
index 0000000000..b0e2390a43
--- /dev/null
+++ b/Userland/Libraries/LibSymbolication/Client.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <LibIPC/ServerConnection.h>
+#include <SymbolServer/SymbolClientEndpoint.h>
+#include <SymbolServer/SymbolServerEndpoint.h>
+
+namespace SymbolClient {
+
+struct Symbol {
+ FlatPtr address { 0 };
+ String name {};
+ u32 offset { 0 };
+ String filename {};
+ u32 line_number { 0 };
+};
+
+Vector<Symbol> symbolicate_thread(pid_t pid, pid_t tid);
+
+class Client
+ : public IPC::ServerConnection<SymbolClientEndpoint, SymbolServerEndpoint>
+ , public SymbolClientEndpoint {
+ C_OBJECT(Client);
+
+public:
+ virtual void handshake() override;
+
+ Optional<Symbol> symbolicate(const String& path, FlatPtr address);
+
+private:
+ Client();
+
+ virtual void dummy() override;
+};
+
+}