Updated kerneldb & rebuild parsers.
[virt-mem.git] / HACKING
1 Source files
2 ------------
3
4 We build all the tools into a single virt-mem executable, in order to
5 share the most runtime.  Almost all the code between individual tools
6 is shared anyway.
7
8 lib/
9
10  - The common core of all the tools.  Library, kernel symbols, command
11    line handling, memory images, etc.
12
13    lib/virt_mem.ml contains most of the important 'glue' code.
14
15 uname/
16 dmesg/
17   etc.
18
19  - The code specific to each tool.  This is usually rather small because
20    the code in lib/ does the hard work.
21
22 mem/
23
24  - This brings everything together and links it into a single executable.
25    Other than that purpose, there is almost nothing in this directory.
26
27 kernels/
28
29  - The database of known kernels and the layout of their structures.
30
31 extract/
32
33  - Tools to extract the structure layout data from kernels.  Various
34    subdirectories here correspond to the different Linux distributions
35    and methods of getting at their kernels.
36
37 extract/codegen/
38
39  - Tools to turn the kernel database into generated code which parses
40    the kernel structures.
41
42 General structure of lib/virt_mem.ml
43 ------------------------------------
44
45 We start with a bare kernel memory image ('Virt_mem_types.image0')
46 which gets successively enhanced with extra data along the way:
47
48         Parse command line arguments,
49         work out what virtual machines to
50         process, load kernel images
51
52                 |
53                 |       (passes a 'Virt_mem_types.image0')
54                 V
55
56         Find kernel symbols
57
58                 |
59                 |       (enhanced into a 'Virt_mem_types.image1')
60                 V
61
62         Find kernel version (uname)
63
64                 |
65                 |       (enhanced into a 'Virt_mem_types.image2')
66                 V
67
68         Call tool's "run" function.
69
70 Tools can register other callbacks which get called at earlier stages.
71
72 How it works
73 ------------
74
75 (1) Getting the kernel image
76
77 This is pretty easy (on QEMU/KVM anyway): There is a QEMU monitor
78 command which reads out memory from the guest, and this is made
79 available through the virDomainMemoryPeek call in libvirt.
80
81 Kernel images are generally located at small number of known addresses
82 (eg. 0xC010_0000 on x86).
83
84 (2) Getting the kernel symbols.
85
86 The Linux kernel contains two tables of kernel symbols - the usual
87 kernel symbols used for exporting symbols to loadable modules, and
88 'kallsyms' which is used for error reporting.  (Of course, specific
89 Linux kernels may be compiled without one or other of these tables).
90
91 The functions in modules lib/virt_mem_ksyms.ml and
92 lib/virt_mem_kallsyms.ml deal with searching kernel memory for these
93 two tables.
94
95 (3) Getting the kernel version.
96
97 The kernel has the kernel version information compiled in at a known
98 symbol address, so once we have the kernel symbols it is relatively
99 straightforward to get the kernel version.
100
101 See lib/virt_mem_utsname.ml.
102
103 (4) Process table / memory / network info etc.
104
105 Note that we have the kernel symbols and the kernel version (and that
106 information is pretty reliable).
107
108 If we take the process table as an example, then it consists of a
109 linked list of 'struct task_struct', starting at the symbol
110 'init_task' (which corresponds to the "hidden" PID 0 / swapper task),
111 and linked through a double-linked list in the 'tasks' member of this
112 structure.
113
114 We have the location of 'init_task', but struct task_struct varies
115 greatly depending on: word size, kernel version, CONFIG_* settings,
116 and vendor/additional patches.
117
118 The problem is to work out the "shape" of task_struct, and we do this
119 in two different ways:
120
121 (Method 1) Precompiled task_struct.  We can easily and reliably
122 determine the Linux kernel version (see virt-uname).  In theory we
123 could compile a list of known kernel versions, check out their sources
124 beforehand, and find the absolute layout of the task_struct (eg. using
125 CIL).  This method would only work for known kernel versions, but has
126 the advantage that all fields in the task_struct would be known.
127
128 (Method 2) Fuzzy matched task_struct.  The task_struct has a certain
129 internal structure which is stable even over many kernel revisions.
130 For example, groups of pointers always occur together.  We search
131 through init_task looking for these characteristic features and where
132 a pointer is found to another task_struct we search that (recursively)
133 on the assumption that those contain the same features at the same
134 location.  This works well for pointers, but not so well for finding
135 other fields (eg. uids, process name, etc).  We can defray the cost of
136 searches by caching the results between runs.
137
138 Currently we use Method 1, deriving the database of known kernels from
139 gdb debugging information generated by Linux distributions when they
140 build their kernels, and processing that with 'pahole' (from dwarves
141 library).
142
143 We have experimented with Method 2.  Currently work on it is postponed
144 to a research project for a keen student at some point in the near
145 future.  There are some early implementations of method 2 if you look
146 back over the version control history.
147
148 The database of known kernels is stored in kernels/ subdirectory.
149
150 The functions to build the database by extracting debug information
151 from Linux distributions is stored in extract/ subdirectory.