diff options
author | Andreas Kling <kling@serenityos.org> | 2021-02-04 23:04:58 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-02-04 23:20:39 +0100 |
commit | b7d16e3496bc7fde24b2fb4590053b4cd4b1cd5c (patch) | |
tree | 86febb8618f483a622d5e068ce6926b58ec6fbbc | |
parent | a5d89ca5dfa39312862928b542819f05fc40df91 (diff) | |
download | serenity-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.cpp | 122 | ||||
-rw-r--r-- | Userland/Libraries/LibSymbolClient/Client.h | 6 | ||||
-rw-r--r-- | Userland/Utilities/bt.cpp | 115 |
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 = ®ion; + 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 = ®ion; - 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; } |