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