summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-02-04 23:04:58 +0100
committerAndreas Kling <kling@serenityos.org>2021-02-04 23:20:39 +0100
commitb7d16e3496bc7fde24b2fb4590053b4cd4b1cd5c (patch)
tree86febb8618f483a622d5e068ce6926b58ec6fbbc
parenta5d89ca5dfa39312862928b542819f05fc40df91 (diff)
downloadserenity-b7d16e3496bc7fde24b2fb4590053b4cd4b1cd5c.zip
LibSymbolClient+bt: Move bt logic to SymbolClient::symbolicate_thread()
Since this is useful in many places, let's have a common implementation of walking the stack of a given thread via /proc and symbolicating each of the frames.
-rw-r--r--Userland/Libraries/LibSymbolClient/Client.cpp122
-rw-r--r--Userland/Libraries/LibSymbolClient/Client.h6
-rw-r--r--Userland/Utilities/bt.cpp115
3 files changed, 130 insertions, 113 deletions
diff --git a/Userland/Libraries/LibSymbolClient/Client.cpp b/Userland/Libraries/LibSymbolClient/Client.cpp
index e860493dc8..3ef06b44a4 100644
--- a/Userland/Libraries/LibSymbolClient/Client.cpp
+++ b/Userland/Libraries/LibSymbolClient/Client.cpp
@@ -24,6 +24,10 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#include <AK/JsonArray.h>
+#include <AK/JsonObject.h>
+#include <AK/JsonValue.h>
+#include <LibCore/File.h>
#include <LibSymbolClient/Client.h>
namespace SymbolClient {
@@ -58,4 +62,122 @@ Vector<Symbol> Client::symbolicate(const String& path, const Vector<FlatPtr>& ad
return symbols;
}
+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::IODevice::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::IODevice::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;
+ }
+
+ Vector<FlatPtr> addresses;
+ if (found_region->is_relative)
+ addresses.append(address - found_region->base);
+ else
+ addresses.append(address);
+
+ auto result = client->symbolicate(found_region->path, addresses);
+ if (result.is_empty()) {
+ symbols.append(Symbol {
+ .address = address,
+ });
+ continue;
+ }
+
+ symbols.append(Symbol {
+ .address = address,
+ .name = result[0].name });
+ }
+ return symbols;
+}
+
}
diff --git a/Userland/Libraries/LibSymbolClient/Client.h b/Userland/Libraries/LibSymbolClient/Client.h
index 9faab216ca..8fa1cf75b9 100644
--- a/Userland/Libraries/LibSymbolClient/Client.h
+++ b/Userland/Libraries/LibSymbolClient/Client.h
@@ -34,12 +34,14 @@ namespace SymbolClient {
struct Symbol {
FlatPtr address { 0 };
- String name;
+ String name {};
u32 offset { 0 };
- String filename;
+ 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 {
diff --git a/Userland/Utilities/bt.cpp b/Userland/Utilities/bt.cpp
index 55fbbd6921..0bf569a0ad 100644
--- a/Userland/Utilities/bt.cpp
+++ b/Userland/Utilities/bt.cpp
@@ -24,9 +24,6 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <AK/JsonArray.h>
-#include <AK/JsonObject.h>
-#include <AK/JsonValue.h>
#include <AK/LogStream.h>
#include <LibCore/ArgsParser.h>
#include <LibCore/EventLoop.h>
@@ -63,118 +60,14 @@ int main(int argc, char** argv)
Core::ArgsParser args_parser;
pid_t pid = 0;
args_parser.add_positional_argument(pid, "PID", "pid");
-
args_parser.parse(argc, argv);
- 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 });
-
- {
- // FIXME: Support multiple threads in the same process!
- auto stack_path = String::formatted("/proc/{}/stacks/{}", pid, pid);
- auto file_or_error = Core::File::open(stack_path, Core::IODevice::ReadOnly);
- if (file_or_error.is_error()) {
- warnln("Could not open {}: {}", stack_path, file_or_error.error());
- return 1;
- }
-
- 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 1;
- }
-
- 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::IODevice::ReadOnly);
- if (file_or_error.is_error()) {
- warnln("Could not open {}: {}", vm_path, file_or_error.error());
- return 1;
- }
-
- 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 1;
- }
-
- 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));
- }
- }
-
Core::EventLoop loop;
- auto client = SymbolClient::Client::construct();
-
- 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;
- }
-
- Vector<FlatPtr> addresses;
- if (found_region->is_relative)
- addresses.append(address - found_region->base);
- else
- addresses.append(address);
-
- auto symbols = client->symbolicate(found_region->path, addresses);
- if (symbols.is_empty()) {
- outln("{:p} ??", address);
- continue;
- }
-
- outln("{:p} {}", address, symbols[0].name);
+ // FIXME: Support multiple threads in the same process!
+ auto symbols = SymbolClient::symbolicate_thread(pid, pid);
+ for (auto& symbol : symbols) {
+ outln("{:p} {}", symbol.address, symbol.name);
}
-
return 0;
}