SystemTap lets you view and modify a running Linux kernel. For in-depth information, refer to Don Domingo's Red Hat Enterprise Linux SystemTap Beginners Guide.
On Fedora 33:
sudo dnf install systemtap systemtap-runtime kernel-devel
sudo debuginfo-install kernel
To test that SystemTap is working correctly for a Linux VMware guest that has 3D acceleration enabled, enter the following into a test.stp
file:
probe module("vmwgfx").function("vmw_execbuf_ioctl") {
printf("Successfully entered vmw_execbuf_ioctl\n");
}
This lets us hook the entry of the vmw_execbuf_ioctl()
function, which is located in linux-5.10.22-200.fc33.x86_64/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
.
Run the script and wait. The output should be as follows. If you get no output, resize the terminal window:
$ sudo stap test.stp
Successfully entered vmw_execbuf_ioctl
Successfully entered vmw_execbuf_ioctl
Successfully entered vmw_execbuf_ioctl
...
Consider the vmci_send_datagram()
function from linux-5.10.22-200.fc33.x86_64/drivers/misc/vmw_vmci/vmci_guest.c
:
92 /*
93 * VM to hypervisor call mechanism. We use the standard VMware naming
94 * convention since shared code is calling this function as well.
95 */
96 int vmci_send_datagram(struct vmci_datagram *dg)
97 {
This function accepts a *dg
parameter, which is a pointer to a vmci_datagram
structure. The following shows this structure's definition:
456 struct vmci_datagram {
457 struct vmci_handle dst;
458 struct vmci_handle src;
459 u64 payload_size;
460 };
Parameters can be accessed using $
in SystemTap scripts. If we wanted to view the payload_size
parameter, we would probe the vmw_vmci
module, looking at the entry point of vmci_send_datagram()
, and then using $dg->payload_size
to view the value of payload_size
:
probe module("vmw_vmci").function("vmci_send_datagram") {
printf("vmci_send_datagram() was called\n");
printf("%u\n", $dg->payload_size);
}
If you run this script shortly after the operating system has loaded, the output should be similar to the following:
$ sudo stap test.stp
vmci_send_datagram() was called
32
vmci_send_datagram() was called
32
vmci_send_datagram() was called
32
kernel_string
can be used in a SystemTap script to view the contents of strings, for example the following prints the kernel_commands
variable, which is a void *kernel_commands
string:
printf("%s \n", kernel_string($kernel_commands));
You can hook on line numbers (but not in all places) using a function_name@path_to_file_containing_it:linenumber
statement:
probe module("vmw_vmci").statement("vmci_send_datagram@drivers/misc/vmw_vmci/vmci_guest.c:102") {
printf("Line number break\n");
}
This would hook line 102 here:
96 int vmci_send_datagram(struct vmci_datagram *dg)
97 {
98 unsigned long flags;
99 int result;
100
101 /* Check args. */
102 if (dg == NULL)
Parameters can also be changed. Using the *dg
parameter for vmci_send_datagram()
again:
456 struct vmci_datagram {
457 struct vmci_handle dst;
458 struct vmci_handle src;
459 u64 payload_size;
460 };
The vmci_handle
structure is defined as follows:
123 /*
124 * struct vmci_handle - Ownership information structure
125 * @context: The VMX context ID.
126 * @resource: The resource ID (used for locating in resource hash).
127 *
128 * The vmci_handle structure is used to track resources used within
129 * vmw_vmci.
130 */
131 struct vmci_handle {
132 u32 context;
133 u32 resource;
134 };
The following script will change the destination resource to an invalid value:
probe module("vmw_vmci").function("vmci_send_datagram") {
printf("Changing res\n");
$dg->dst->resource = 4444;
}
Since this will change a value, it must be run in guru mode, stap -g
.
The consequences of changing this can be viewed in the guest's vmware.log
file on the host, for example on macOS:
% tail -f Virtual\ Machines.localized/Fedora\ 64-bit.vmwarevm/vmware.log
2021-03-17T15:45:00.017+11:00| vcpu-1| I005: VMCIDatagram: Destination resource 4444 invalid.
On Fedora, the following steps download a kernel source RPM, extract it, and then apply all patches:
-
$ yumdownloader --source kernel
-
$ rpm -ivh kernel-5.10.22-200.fc33.src.rpm
-
cd ~/rpmbuild/SPECS/
-
rpmbuild -bp --nodeps kernel.spec
-
$ cd ~/rpmbuild/BUILD/kernel-5.10.fc33/linux-5.10.22-200.fc33.x86_64/
cscope
is useful for viewing C code. From step 5, run cscope -R -u
to get started (do not use -u
except for the first time). This lets you find function definitions, where functions are called from, and so on. You can set an editor (that is used when viewing functions) in ~/.bashrc
, for example, export CSCOPE_EDITOR=vim
.