diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-07-28 12:15:24 +0200 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-07-28 12:15:24 +0200 |
commit | cf57d644818d6a217d4cf055d896bc7261e6f972 (patch) | |
tree | c0a8d9e5313046e76bb21b1052c8e3b1aefd6ed6 /Applications | |
parent | 52a5e34902f5c6d15e8027b281c2a7349ed88162 (diff) | |
download | serenity-cf57d644818d6a217d4cf055d896bc7261e6f972.zip |
ProcessManager: Add a "Memory map" view to show a process's VM layout.
Fetch all the data from /proc/PID/vm for the selected process and show it
in a nice GTableView. :^)
Diffstat (limited to 'Applications')
-rw-r--r-- | Applications/ProcessManager/Makefile | 2 | ||||
-rw-r--r-- | Applications/ProcessManager/ProcessMemoryMapModel.cpp | 98 | ||||
-rw-r--r-- | Applications/ProcessManager/ProcessMemoryMapModel.h | 32 | ||||
-rw-r--r-- | Applications/ProcessManager/ProcessMemoryMapWidget.cpp | 25 | ||||
-rw-r--r-- | Applications/ProcessManager/ProcessMemoryMapWidget.h | 18 | ||||
-rw-r--r-- | Applications/ProcessManager/main.cpp | 6 |
6 files changed, 181 insertions, 0 deletions
diff --git a/Applications/ProcessManager/Makefile b/Applications/ProcessManager/Makefile index 200c2f123e..a67af7d942 100644 --- a/Applications/ProcessManager/Makefile +++ b/Applications/ProcessManager/Makefile @@ -6,6 +6,8 @@ OBJS = \ MemoryStatsWidget.o \ GraphWidget.o \ ProcessStacksWidget.o \ + ProcessMemoryMapWidget.o \ + ProcessMemoryMapModel.o \ main.o APP = ProcessManager diff --git a/Applications/ProcessManager/ProcessMemoryMapModel.cpp b/Applications/ProcessManager/ProcessMemoryMapModel.cpp new file mode 100644 index 0000000000..8d847e8ddd --- /dev/null +++ b/Applications/ProcessManager/ProcessMemoryMapModel.cpp @@ -0,0 +1,98 @@ +#include "ProcessMemoryMapModel.h" +#include <AK/JsonObject.h> +#include <AK/StringBuilder.h> +#include <LibCore/CFile.h> + +void ProcessMemoryMapModel::update() +{ + CFile file(String::format("/proc/%d/vm", m_pid)); + if (!file.open(CIODevice::ReadOnly)) { + dbg() << "Unable to open " << file.filename(); + return; + } + + auto json = JsonValue::from_string(file.read_all()); + + ASSERT(json.is_array()); + m_process_vm = json.as_array(); + + did_update(); +} + +int ProcessMemoryMapModel::row_count(const GModelIndex&) const +{ + return m_process_vm.size(); +} + +String ProcessMemoryMapModel::column_name(int column) const +{ + switch (column) { + case Column::Address: + return "Address"; + case Column::Size: + return "Size"; + case Column::AmountResident: + return "Resident"; + case Column::Access: + return "Access"; + case Column::Name: + return "Name"; + default: + ASSERT_NOT_REACHED(); + } +} + +GModel::ColumnMetadata ProcessMemoryMapModel::column_metadata(int column) const +{ + switch (column) { + case Column::Address: + return { 80 }; + case Column::Size: + return { 60, TextAlignment::CenterRight }; + case Column::AmountResident: + return { 60, TextAlignment::CenterRight }; + case Column::Access: + return { 50 }; + case Column::Name: + return { 200 }; + default: + ASSERT_NOT_REACHED(); + } + return {}; +} + +GVariant ProcessMemoryMapModel::data(const GModelIndex& index, Role role) const +{ + auto& region_object = m_process_vm.at(index.row()).as_object(); + if (role == GModel::Role::Display) { + switch (index.column()) { + case Column::Address: + return String::format("%#x", region_object.get("address").to_u32()); + case Column::Size: + return region_object.get("size").to_int(); + case Column::AmountResident: + return region_object.get("amount_resident").to_int(); + case Column::Access: { + StringBuilder builder; + if (region_object.get("readable").to_bool()) + builder.append('R'); + if (region_object.get("writable").to_bool()) + builder.append('W'); + return builder.to_string(); + } + case Column::Name: + return region_object.get("name").to_string(); + default: + ASSERT_NOT_REACHED(); + } + } + return {}; +} + +void ProcessMemoryMapModel::set_pid(pid_t pid) +{ + if (m_pid == pid) + return; + m_pid = pid; + update(); +} diff --git a/Applications/ProcessManager/ProcessMemoryMapModel.h b/Applications/ProcessManager/ProcessMemoryMapModel.h new file mode 100644 index 0000000000..cc28aef223 --- /dev/null +++ b/Applications/ProcessManager/ProcessMemoryMapModel.h @@ -0,0 +1,32 @@ +#pragma once + +#include <AK/JsonArray.h> +#include <LibGUI/GModel.h> + +class ProcessMemoryMapModel final : public GModel { +public: + enum Column { + Address, + Size, + AmountResident, + Access, + Name, + __Count + }; + + ProcessMemoryMapModel() {} + virtual ~ProcessMemoryMapModel() override {} + + virtual int row_count(const GModelIndex& = GModelIndex()) const override; + virtual int column_count(const GModelIndex& = GModelIndex()) const override { return Column::__Count; } + virtual String column_name(int) const override; + virtual ColumnMetadata column_metadata(int) const override; + virtual GVariant data(const GModelIndex&, Role = Role::Display) const override; + virtual void update() override; + + void set_pid(pid_t); + +private: + JsonArray m_process_vm; + int m_pid { -1 }; +}; diff --git a/Applications/ProcessManager/ProcessMemoryMapWidget.cpp b/Applications/ProcessManager/ProcessMemoryMapWidget.cpp new file mode 100644 index 0000000000..5caeb02dcf --- /dev/null +++ b/Applications/ProcessManager/ProcessMemoryMapWidget.cpp @@ -0,0 +1,25 @@ +#include "ProcessMemoryMapWidget.h" +#include "ProcessMemoryMapModel.h" +#include <LibGUI/GBoxLayout.h> +#include <LibGUI/GTableView.h> + +ProcessMemoryMapWidget::ProcessMemoryMapWidget(GWidget* parent) + : GWidget(parent) +{ + set_layout(make<GBoxLayout>(Orientation::Vertical)); + layout()->set_margins({ 4, 4, 4, 4 }); + m_table_view = new GTableView(this); + m_table_view->set_model(adopt(*new ProcessMemoryMapModel)); +} + +ProcessMemoryMapWidget::~ProcessMemoryMapWidget() +{ +} + +void ProcessMemoryMapWidget::set_pid(pid_t pid) +{ + if (m_pid == pid) + return; + m_pid = pid; + static_cast<ProcessMemoryMapModel*>(m_table_view->model())->set_pid(pid); +} diff --git a/Applications/ProcessManager/ProcessMemoryMapWidget.h b/Applications/ProcessManager/ProcessMemoryMapWidget.h new file mode 100644 index 0000000000..fa1091286e --- /dev/null +++ b/Applications/ProcessManager/ProcessMemoryMapWidget.h @@ -0,0 +1,18 @@ +#pragma once + +#include <LibGUI/GWidget.h> + +class GTableView; + +class ProcessMemoryMapWidget final : public GWidget { + C_OBJECT(ProcessMemoryMapWidget); +public: + explicit ProcessMemoryMapWidget(GWidget* parent); + virtual ~ProcessMemoryMapWidget() override; + + void set_pid(pid_t); + +private: + GTableView* m_table_view { nullptr }; + pid_t m_pid { -1 }; +}; diff --git a/Applications/ProcessManager/main.cpp b/Applications/ProcessManager/main.cpp index 895482ad35..36c15bb753 100644 --- a/Applications/ProcessManager/main.cpp +++ b/Applications/ProcessManager/main.cpp @@ -1,5 +1,6 @@ #include "GraphWidget.h" #include "MemoryStatsWidget.h" +#include "ProcessMemoryMapWidget.h" #include "ProcessStacksWidget.h" #include "ProcessTableView.h" #include <LibCore/CTimer.h> @@ -155,11 +156,16 @@ int main(int argc, char** argv) app.set_menubar(move(menubar)); auto* process_tab_widget = new GTabWidget(process_container_splitter); + + auto* memory_map_widget = new ProcessMemoryMapWidget(nullptr); + process_tab_widget->add_widget("Memory map", memory_map_widget); + auto* stacks_widget = new ProcessStacksWidget(nullptr); process_tab_widget->add_widget("Stacks", stacks_widget); process_table_view->on_process_selected = [&](pid_t pid) { stacks_widget->set_pid(pid); + memory_map_widget->set_pid(pid); }; auto* window = new GWindow; |