Using kallsyms to Obtain Any Kernel Symbol
Suppose that you want to call a Linux kernel function such as ptrace_request() from your guru mode SystemTap script. You can see it in the headers, you can see it in /proc/kallsyms, but when you reference it from a SystemTap script the generated code fails to compile with a linker error.
The reason is that ptrace_request() is missing from the kernel's Module.symvers (which can be found in /usr/src/). A symbol must be added to Module.symvers for the linker to be able to find it when building an out-of-tree kernel module, which is what SystemTap modules are.
A symbol is only added to Module.symvers if it was declared with EXPORT_SYMBOL*(). You can see other functions in the linux source code have an EXPORT_SYMBOL*() annotation but ptrace_request() does not:
https://github.com/torvalds/linux/blob/96d4f267e40f9509e8a66e2b39e8b95655617693/kernel/ptrace.c#L883 is not exported
In the SystemTap runtime, we do call a few of the non-EXPORTed symbols. (An example can be found in the stp_utrace code.) The workaround we employ is to explicitly look up the address of the function with kallsyms_lookup_name() and then cast it to a function type copied from the kernel-internal header file, as follows:
%{ // Copy original declaration from the header: extern int ptrace_request(struct task_struct *child, long request, unsigned long addr, unsigned long data); // First typedef from the original decl, then #define as typecasted call. typedef typeof(&ptrace_request) ptrace_request_fn; #define ptrace_request (* (ptrace_request_fn)kallsyms_ptrace_request) void *kallsyms_ptrace_request = NULL; %} // Make sure to put this code somewhere that will execute // before your first call to the function: function init() %{ kallysms_ptrace_request = (void*)kallsyms_lookup_name("ptrace_request"); %}
You can also use this trick in a guru-mode SystemTap script.