Serenity Operating System
1/*
2 * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2021, Kenneth Myhra <kennethmyhra@serenityos.org>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include <AK/LexicalPath.h>
9#include <AK/URL.h>
10#include <LibCore/ArgsParser.h>
11#include <LibCore/DirIterator.h>
12#include <LibCore/EventLoop.h>
13#include <LibCore/System.h>
14#include <LibMain/Main.h>
15#include <LibSymbolication/Symbolication.h>
16#include <unistd.h>
17
18ErrorOr<int> serenity_main(Main::Arguments arguments)
19{
20 TRY(Core::System::pledge("stdio rpath"));
21 auto hostname = TRY(Core::System::gethostname());
22
23 Core::ArgsParser args_parser;
24 pid_t pid = 0;
25 args_parser.add_positional_argument(pid, "PID", "pid");
26 args_parser.parse(arguments);
27 Core::EventLoop loop;
28
29 Core::DirIterator iterator(DeprecatedString::formatted("/proc/{}/stacks", pid), Core::DirIterator::SkipDots);
30 if (iterator.has_error()) {
31 warnln("Error: pid '{}' doesn't appear to exist.", pid);
32 return 1;
33 }
34
35 while (iterator.has_next()) {
36 pid_t tid = iterator.next_path().to_int().value();
37 outln("thread: {}", tid);
38 outln("frames:");
39 auto symbols = Symbolication::symbolicate_thread(pid, tid);
40 auto frame_number = symbols.size() - 1;
41 for (auto& symbol : symbols) {
42 // Make kernel stack frames stand out.
43 auto maybe_kernel_base = Symbolication::kernel_base();
44 int color = maybe_kernel_base.has_value() && symbol.address < maybe_kernel_base.value() ? 35 : 31;
45 out("{:3}: \033[{};1m{:p}\033[0m | ", frame_number, color, symbol.address);
46 if (!symbol.name.is_empty())
47 out("{} ", symbol.name);
48 if (!symbol.source_positions.is_empty()) {
49 out("(");
50
51 for (size_t i = 0; i < symbol.source_positions.size(); i++) {
52 auto& source_position = symbol.source_positions[i];
53 bool linked = false;
54
55 // See if we can find the sources in /usr/src
56 // FIXME: I'm sure this can be improved!
57 auto full_path = LexicalPath::canonicalized_path(DeprecatedString::formatted("/usr/src/serenity/dummy/dummy/{}", source_position.file_path));
58 if (access(full_path.characters(), F_OK) == 0) {
59 linked = true;
60 auto url = URL::create_with_file_scheme(full_path, {}, hostname);
61 url.set_query(DeprecatedString::formatted("line_number={}", source_position.line_number));
62 out("\033]8;;{}\033\\", url.serialize());
63 }
64
65 out("\033[34;1m{}:{}\033[0m", LexicalPath::basename(source_position.file_path), source_position.line_number);
66
67 if (linked)
68 out("\033]8;;\033\\");
69
70 if (i != symbol.source_positions.size() - 1)
71 out(" => ");
72 }
73
74 out(")");
75 }
76 outln("");
77 frame_number--;
78 }
79 outln("");
80 }
81 return 0;
82}