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.
