+Source files
+------------
+
We build all the tools into a single virt-mem executable, in order to
share the most runtime. Almost all the code between individual tools
is shared anyway.
- The common core of all the tools. Library, kernel symbols, command
line handling, memory images, etc.
+ lib/virt_mem.ml contains most of the important 'glue' code.
+
uname/
dmesg/
etc.
- - The code specific to each tool, usually rather small.
+ - The code specific to each tool. This is usually rather small because
+ the code in lib/ does the hard work.
mem/
- This brings everything together and links it into a single executable.
Other than that purpose, there is almost nothing in this directory.
+
+kernels/
+
+ - The database of known kernels and the layout of their structures.
+
+extract/
+
+ - Tools to extract the structure layout data from kernels. Various
+ subdirectories here correspond to the different Linux distributions
+ and methods of getting at their kernels.
+
+extract/codegen/
+
+ - Tools to turn the kernel database into generated code which parses
+ the kernel structures.
+
+General structure of lib/virt_mem.ml
+------------------------------------
+
+We start with a bare kernel memory image ('Virt_mem_types.image0')
+which gets successively enhanced with extra data along the way:
+
+ Parse command line arguments,
+ work out what virtual machines to
+ process, load kernel images
+
+ |
+ | (passes a 'Virt_mem_types.image0')
+ V
+
+ Find kernel symbols
+
+ |
+ | (enhanced into a 'Virt_mem_types.image1')
+ V
+
+ Find kernel version (uname)
+
+ |
+ | (enhanced into a 'Virt_mem_types.image2')
+ V
+
+ Call tool's "run" function.
+
+Tools can register other callbacks which get called at earlier stages.
+
+How it works
+------------
+
+(1) Getting the kernel image
+
+This is pretty easy (on QEMU/KVM anyway): There is a QEMU monitor
+command which reads out memory from the guest, and this is made
+available through the virDomainMemoryPeek call in libvirt.
+
+Kernel images are generally located at small number of known addresses
+(eg. 0xC010_0000 on x86).
+
+(2) Getting the kernel symbols.
+
+The Linux kernel contains two tables of kernel symbols - the usual
+kernel symbols used for exporting symbols to loadable modules, and
+'kallsyms' which is used for error reporting. (Of course, specific
+Linux kernels may be compiled without one or other of these tables).
+
+The functions in modules lib/virt_mem_ksyms.ml and
+lib/virt_mem_kallsyms.ml deal with searching kernel memory for these
+two tables.
+
+(3) Getting the kernel version.
+
+The kernel has the kernel version information compiled in at a known
+symbol address, so once we have the kernel symbols it is relatively
+straightforward to get the kernel version.
+
+See lib/virt_mem_utsname.ml.
+
+(4) Process table / memory / network info etc.
+
+Note that we have the kernel symbols and the kernel version (and that
+information is pretty reliable).
+
+If we take the process table as an example, then it consists of a
+linked list of 'struct task_struct', starting at the symbol
+'init_task' (which corresponds to the "hidden" PID 0 / swapper task),
+and linked through a double-linked list in the 'tasks' member of this
+structure.
+
+We have the location of 'init_task', but struct task_struct varies
+greatly depending on: word size, kernel version, CONFIG_* settings,
+and vendor/additional patches.
+
+The problem is to work out the "shape" of task_struct, and we do this
+in two different ways:
+
+(Method 1) Precompiled task_struct. We can easily and reliably
+determine the Linux kernel version (see virt-uname). In theory we
+could compile a list of known kernel versions, check out their sources
+beforehand, and find the absolute layout of the task_struct (eg. using
+CIL). This method would only work for known kernel versions, but has
+the advantage that all fields in the task_struct would be known.
+
+(Method 2) Fuzzy matched task_struct. The task_struct has a certain
+internal structure which is stable even over many kernel revisions.
+For example, groups of pointers always occur together. We search
+through init_task looking for these characteristic features and where
+a pointer is found to another task_struct we search that (recursively)
+on the assumption that those contain the same features at the same
+location. This works well for pointers, but not so well for finding
+other fields (eg. uids, process name, etc). We can defray the cost of
+searches by caching the results between runs.
+
+Currently we use Method 1, deriving the database of known kernels from
+gdb debugging information generated by Linux distributions when they
+build their kernels, and processing that with 'pahole' (from dwarves
+library).
+
+We have experimented with Method 2. Currently work on it is postponed
+to a research project for a keen student at some point in the near
+future. There are some early implementations of method 2 if you look
+back over the version control history.
+
+The database of known kernels is stored in kernels/ subdirectory.
+
+The functions to build the database by extracting debug information
+from Linux distributions is stored in extract/ subdirectory.
\ No newline at end of file