summaryrefslogtreecommitdiff
path: root/Applications
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-07-28 12:15:24 +0200
committerAndreas Kling <awesomekling@gmail.com>2019-07-28 12:15:24 +0200
commitcf57d644818d6a217d4cf055d896bc7261e6f972 (patch)
treec0a8d9e5313046e76bb21b1052c8e3b1aefd6ed6 /Applications
parent52a5e34902f5c6d15e8027b281c2a7349ed88162 (diff)
downloadserenity-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/Makefile2
-rw-r--r--Applications/ProcessManager/ProcessMemoryMapModel.cpp98
-rw-r--r--Applications/ProcessManager/ProcessMemoryMapModel.h32
-rw-r--r--Applications/ProcessManager/ProcessMemoryMapWidget.cpp25
-rw-r--r--Applications/ProcessManager/ProcessMemoryMapWidget.h18
-rw-r--r--Applications/ProcessManager/main.cpp6
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;