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