use process memory file to read process memory (instant scan instead of ~50 seconds)
[nyatools.git] / mregs.d
blob37a5346cbc7c4532fa42a71b473b47548920603d
1 module mregs;
3 import iv.vfs;
4 import iv.vfs.io;
6 public align(1) struct MemoryRegionInfo {
7 align(1):
8 uint start, end;
9 string name;
13 public MemoryRegionInfo[] readMemoryRegions (uint pid, bool includeStack=false) {
14 import std.format : format;
16 static byte hexDigit (char ch) pure nothrow @safe @nogc {
17 pragma(inline, true);
18 return
19 ch >= '0' && ch <= '9' ? cast(byte)(ch-'0') :
20 ch >= 'A' && ch <= 'F' ? cast(byte)(ch-'A'+10) :
21 ch >= 'a' && ch <= 'f' ? cast(byte)(ch-'a'+10) :
22 -1;
25 static uint parseHex(T : const(char)[]) (ref T s) {
26 while (s.length > 0 && s.ptr[0] <= ' ') s = s[1..$];
27 if (s.length == 0 || hexDigit(s.ptr[0]) < 0) throw new Exception("hex number expected");
28 uint res = 0;
29 while (s.length) {
30 auto d = hexDigit(s.ptr[0]);
31 if (d < 0) break;
32 uint nr = res*16+d;
33 if (nr < res) throw new Exception("hex overflow");
34 res = nr;
35 s = s[1..$];
37 return res;
40 static void consume(T : const(char)[]) (ref T s, char ch) {
41 if (s.length == 0 && s.ptr[0] != ch) throw new Exception("'"~ch~"' expected");
42 s = s[1..$];
45 static void skipSpaces(T : const(char)[]) (ref T s) {
46 if (s.length == 0 && s.ptr[0] > ' ') throw new Exception("space expected");
47 while (s.length > 0 && s.ptr[0] <= ' ') s = s[1..$];
50 MemoryRegionInfo[] res;
51 foreach (char[] ln; VFile("/proc/%s/maps".format(pid)).byLine) {
52 uint start, end;
53 string name;
54 try {
55 start = parseHex(ln);
56 consume(ln, '-');
57 end = parseHex(ln);
58 skipSpaces(ln);
59 if (start >= end) continue;
60 // skip regions with less than 16 bytes of data
61 if (end-start < 16) continue;
62 if (ln.length < 5) throw new Exception("invalid region description");
63 // skip non-writeable, executable and shared regions
64 if (ln.ptr[0] != 'r' || ln.ptr[1] != 'w' || ln.ptr[2] == 'x' || ln.ptr[3] != 'p') continue;
65 ln = ln[4..$];
66 skipSpaces(ln);
67 // if offset is not 0, it is mmaped region, skip it
68 if (parseHex(ln) != 0) continue;
69 // if devicehi or devilelo is not 0, it is mmaped region, skip it
70 skipSpaces(ln);
71 if (parseHex(ln) != 0) continue;
72 consume(ln, ':');
73 if (parseHex(ln) != 0) continue;
74 // if inode is not 0, it is mmaped region, skip it
75 skipSpaces(ln);
76 if (parseHex(ln) != 0) continue;
77 // get region name
78 if (ln.length > 0) {
79 skipSpaces(ln);
80 name = ln.idup;
81 while (name.length && name[$-1] <= ' ') name = name[0..$-1];
83 } catch (Exception) {
84 // can't parse this region, skip it
85 continue;
87 if (includeStack) {
88 if (name.length > 6 && name[0..6] == "[stack") continue;
90 if (name.length > 0 && name.ptr[0] == '[') {
91 // specials; allow only "heap"
92 //writefln("**** %08X:%08X <%s>", start, end, name);
93 if (name.length < 6 || name[0..5] != "[heap") continue;
95 //writefln("%08X:%08X <%s>", start, end, name);
96 res ~= MemoryRegionInfo(start, end, name);
98 return res;
103 void main (string[] args) {
104 uint pid = 30329;
105 if (args.length > 1) {
106 import std.conv : to;
107 pid = to!uint(args[1]);
109 auto regs = readMemoryRegions(pid);
110 uint total = 0;
111 foreach (const ref reg; regs) total += reg.end-reg.start;
112 writeln(cast(double)total/1024/1024, " megabytes");