Using FTRACE for loadable linux driver module - linux-kernel

I am trying to use FTRACE for tracing and getting function_graph on a loadable driver module.
But, somehow, I did not see any functions in that module being traced.
Here is what I did (I had the kernel configured to have FTRACE already in the menuconfig)
#echo function_graph > /sys/kernel/debug/tracing/current_tracer
#cat /sys/kernel/debug/tracing/current_tracer
function_graph
#echo 1 > tracing_on
#insmod my_module.ko
#echo 0 > tracing_on
#cat trace
Nothing in the trace file has any functions inside my_module.ko
Do I need to enable some compiler flags when compiling my_module.c?
Any ideas what I need to do?
Thanks!

I suspect that you don't see any function at all being traced; usually the dynamic ftrace is enable, so you have to manually choose what you want to trace.
cat available_filter_functions
It shows you all function that you can trace (grep for what you want just to be sure that is there). Of course, your module's function are visible only after module loading. So you load the module and then you add your function.
insmod mymodule.ko
echo my_function >> set_ftrace_filter
You can find all the details in the kernel documentation about ftrace

Try this command:
echo $$ >> /sys/kernel/debug/tracing/set_ftrace_pid

Related

Does "-Wl,-soname" work on MinGW or is there an equivalent?

I'm experimenting a bit with building DLLs on windows using MINGW.
A very good summary (in my opinion) can be found at:
https://www.transmissionzero.co.uk/computing/building-dlls-with-mingw/
There is even a basic project which can be used for the purpose of this discussion:
https://github.com/TransmissionZero/MinGW-DLL-Example/releases/tag/rel%2Fv1.1
Note there is a cosmetic mistake in this project which will make it fail out of the box: the Makefile does not create an "obj" directory - Either adjust the Makefile or create it manually.
So here is the real question.
How to change the Windows DLL name so it differs from the actual DLL file name ??
Essentially I'm trying to achieve on Windows, the effect which is very well described here on Linux:
https://www.man7.org/conf/lca2006/shared_libraries/slide4b.html
Initially I tried changing "InternalName" and ""OriginalFilename" in the resource file used to create the DLL but that does not work.
In a second step, I tried adding "-Wl,-soname,SoName.dll" on the command that performs the final link, to change the Windows DLL name.
However, that does not seem to have the expected effect (I'm using MingW 7.3.0, x86_64-posix-seh-rev0).
Two things makes me say that:
1/ The test executable still works (I would expect it to fail, because it tries to locate SoName.dll but can't find it).
2/ "pexports.exe AddLib.dll" produces the output below, where the library name hasn't changed:
LIBRARY "AddLib.dll"
EXPORTS
Add
bar DATA
foo DATA
Am I doing anything wrong ? Are my expectations wrong perhaps ?
Thanks for your help !
David
First of all, I would like to say it's important to use either a .def file for specifying the exported symbols or use __declspec(dllexport) / __declspec(dllimport), but never mix these two methods. There is also another method using the -Wl,--export-all-symbols linker flag, but I think that's ugly and should only be used when quick and dirty is what you want.
It is possible to tell MinGW to use a DLL filename that does not match the library name. In the link step use -o to specify the DLL and use -Wl,--out-implib, to specify the library file.
Let me illustrate by showing how to build chebyshev as a both static and shared library. Its sources consist of only only 2 files: chebyshev.h and chebyshev.c.
Compile
gcc -c -o chebyshev.o chebyshev.c -I. -O3
Create static library
ar cr libchebyshev.a chebyshev.o
Create a .def file (as it wasn't supplied and __declspec(dllexport) / __declspec(dllimport) wasn't used either). Note that this file doesn't contain a line with LIBRARY allowing the linker to specify the DLL filename later.
There are several ways to do this if the .def file wasn't supplied by the project:
3.1. Get the symbols from the .h file(s). This may be hard as sometimes you need to distinguish for example between type definitions (like typedef, enum, struct) and actual functions and variables that need to be exported;
echo "EXPORTS" > chebyshev.def
sed -n -e "s/^.* \**\(chebyshev_.*\) *(.*$/\1/p" chebyshev.h >> chebyshev.def
3.2. Use nm to list symbols in the library file and filter out the type of symbols you need.
echo "EXPORTS" > chebyshev.def
nm -f posix --defined-only -p libchebyshev.a | sed -n -e "s/^_*\([^ ]*\) T .*$/\1/p" >> chebyshev.def
Link the static library into the shared library.
gcc -shared -s -mwindows -def chebyshev.def -o chebyshev-0.dll -Wl,--out-implib,libchebyshev.dll.a libchebyshev.a
If you have a project that uses __declspec(dllexport) / __declspec(dllimport) things are a lot easier. And you can even have the link step generate a .def file using the -Wl,--output-def, linker flag like this:
gcc -shared -s -mwindows -o myproject.dll -Wl,--out-implib,myproject.dll.a -Wl,--output-def,myproject.def myproject.o
This answer is based on my experiences with C. For C++ you really should use __declspec(dllexport) / __declspec(dllimport).
I believe I have found one mechanism to achieve on Windows, the effect described for Linux in https://www.man7.org/conf/lca2006/shared_libraries/slide4b.html
This involves dll_tool
In the example Makefile there was originally this line:
gcc -o AddLib.dll obj/add.o obj/resource.o -shared -s -Wl,--subsystem,windows,--out-implib,libaddlib.a
I simply replaced it with the 2 lines below instead:
dlltool -e obj/exports.o --dllname soname.dll -l libAddLib.a obj/resource.o obj/add.o
gcc -o AddLib.dll obj/resource.o obj/add.o obj/exports.o -shared -s -Wl,--subsystem,windows
Really, the key seems to be the creation with dlltool of an exports file in conjunction with dllname. This exports file is linked with the object files that make up the body of the DLL and it handles the interface between the DLL and the outside world. Note that dlltool also creates the "import library" at the same time
Now I get the expected effect, and I can see that the "Internal DLL name" (not sure what the correct terminology is) has changed:
First evidence:
>> dlltool.exe -I libAddLib.a
soname.dll
Second evidence:
>> pexports.exe AddLib.dll
LIBRARY "soname.dll"
EXPORTS
Add
bar DATA
foo DATA
Third evidence:
>> AddTest.exe
Error: the code execution cannot proceed because soname.dll was not found.
Although the desired effect is achieved, this still seems to be some sort of workaround. My understanding (but I could well be wrong) is that the gcc option "-Wl,-soname" should achieve exactly the same thing. At least it does on Linux, but is this broken on Windows perhaps ??

Reading memory with GDB vmlinux /proc/kcore

I am trying to use gdb to read memory from vmlinux. The exact syntax is
sudo gdb vmlinux-4.18.0-rc1+ /proc/kcore
I use this file because vmlinux is a symlink to this file.
The result is the following
Reading symbols from vmlinux-4.18.0-rc1+...(no debugging symbols found)...done.
warning: core file may not match specified executable file.
[New process 1]
Core was generated by `root=/dev/mapper/rcs--power9--talos--vg-root ro console=hvc0 quiet'.
#0 0x0000000000000000 in ?? ()
(gdb) x/4xb 0xfffffff0
0xfffffff0: Cannot access memory at address 0xfffffff0
(gdb) print &sys_call_table
No symbol table is loaded. Use the "file" command.
(gdb)
The file vmlinux-4.18.0-rc1+ is in /boot. The file type is as follows:
root#rcs-power9-talos:/boot# file vmlinux-4.18.0-rc1+
vmlinux-4.18.0-rc1+: ELF 64-bit LSB executable, 64-bit PowerPC or cisco 7500, version 1 (SYSV), statically linked, BuildID[sha1]=a1c9f3fe22ff5cbf419787657c878c8a07e559b2, stripped
I modified the config-4.18.0-rc1+ file such that every CONFIG_DEBUG option is set to yes. I then rebooted the system. My questions are:
Do I need to do anything else for the changes I made to /boot/config-4.18.0-rc1+ to take effect?
Based on the file type of vmlinux-4.18.0-rc1+, does it seem that this file should work for debugging?
I did not build the kernel myself. It is a custom build from Raptor Computer Systems.
The config-* file you've modified is just for reference - all these options have already been compiled into the kernel, so changing them will not have any effect.
However, you can get any symbol you want in two steps:
consult /proc/kallsyms (e.g. grep sys_call_table /proc/kallsyms). Get the address. Note, that this might appear as 0x00000000 - which can be fixed by setting /proc/sys/kernel/kptr_restrict to 0
Then use above address as direct argument. You will still run into minor issues (e.g. "print" won't know what datatype it is, but x/20x for example will work) , but these can be resolved with a bit of gdb scripting, or providing an external dwarf file.

I want to replace 'ld' with 'gcc' in my Makefile to link my kernel objects

In my project I have makefiles which build Solaris kernel modules, and they use gcc to compile files but use ld to link all .o files together into a kernel module. I am trying to include some coverage options like gcov (-fprofile-arcs) or tcov (-xprofile=tcov) in my build, hence I want to replace ld with gcc during linking also.
But as soon as I use replace gcc with ld, the builds start failing with lot of "undefined symbol" errors, even if I use some compile flags and get rid of these errors, the kernel module will not load into my Solaris kernel at all.
For example:
$ /usr/ccs/bin/ld -r -dy -Nstrmod/rpcmod -Nfs/nfs \
-Nmisc/rpcsec -Nmisc/klmmod -Nfs/zfs \
-o debug64/nfssrv \
debug64/nfs_server.o debug64/nfs_srv.o debug64/nfs3_srv.o \
debug64/nfs_acl_srv.o debug64/nfs_auth.o obj64/nfs41_srv.o \
obj64/ctl_ds_srv.o obj64/dserv_server.o
ld works fine but with gcc I get following errors:
/opt/gcc-4.4.4/bin/gcc -m64 -z muldefs \
-Lmod/rpcmod -Lfs/nfs -Lmisc/rpcsec \
-Lmisc/klmmod -Lfs/zfs \
-o obj64/nfssrv \
obj64/nfs_server.o obj64/nfs_srv.o obj64/nfs3_srv.o
obj64/nfs_acl_srv.o obj64/nfs_auth.o obj64/nfs41_srv.o
obj64/ctl_ds_srv.o obj64/dserv_server.o
Undefined first referenced
symbol in file
hz obj64/nfs_server.o
p0 obj64/nfs_server.o
nfs_range_set obj64/nfs41_srv.o
getf obj64/nfs_server.o
log2 obj64/nfs4_state.o
main /usr/lib/amd64/crt1.o
stoi obj64/ctl_ds_srv.o
dmu_object_alloc obj64/dserv_server.o
nvpair_name obj64/nfs4_srv.o
__dtrace_probe_nfss41__i__destroy_encap_session obj64/nfs41_srv.o
__dtrace_probe_nfssrv__i__dscp_freeing_device_entries obj64/ctl_ds_srv.o
mod_install obj64/nfs_server.o
xdr_faststatfs obj64/nfs_server.o
xdr_WRITE3res obj64/nfs_server.o
svc_pool_control obj64/nfs_server.o
Warning the option -L allows to specify a path where to search for libraries, to specify a library you want to link with you (also) have to use the option -l
So a priori you have to add the options -lrpcmod -lnfs -lrpcsec -lklmmod -lzfs
More details in GCC Linking Options
By default, the GNU linker called through the gcc compiler driver will try to create a standard executable. Consequently, if you don't tell it otherwise, ld will use its default linker script, the C startup code and it will look for a main() routine and everything else that makes a valid executable.
I'm not too familiar with Solaris, but would bet this will not be suitable to build kernel modules. I would expect kernel modules will at least require some options like -ffreestanding, -nostdlibs and most likely a non-default linker script that's probably very different from the default one used for applications.
Even if you manage to link your kernel modules this way, I seriously doubt you will be finished. The gcov instrumentation routines most likely do not expect to live within a kernel driver but expect a proper C execution environment (e.g. it will at least expect to fopen() a file to fwrite() its findings). A kernel driver, however, does not have this comfort. You'll probably find yourself confronted with the problem to get the gcov data somehow out of your kernel modules.
Not saying this is not doable, but it certainly will be a lot of work.

How to compile to a different location

I am very new to using the a command line to compile code so I was wondering how to make the D compiler compile all its code to a certain location instead of where the source is. As in I want the final .exe and the obj code all in a particular directory. I know you can use the -of command but I currently don't know the format for using it.
Currently I have:
C:\D\dmd2\windows\bin\dmd.exe -w C:\Users\Kyle\Desktop\D\Test.d C:\Users\Kyle\Desktop\D\src\MyMod.d
What do I need to add?
Use -offilename switch. Example:
dmd factorial.d -offilename "d:\test_name.exe"
or short version:
dmd factorial.d "-ofd:\test_name.exe"
Note: The double quotes are necessary if your path contains spaces.
Note2: In short version you can skip .exe, but don't do it in full version, because compiler would search for source file with that name.
I know people do not like RTFM answers, but the following is kind of RTFM answer that answers your question:
Execute dmd --help and you will get the following:
DMD32 D Compiler v2.061
Copyright (c) 1999-2012 by Digital Mars written by Walter Bright
Documentation: http://www.dlang.org/index.html
Usage:
dmd files.d ... { -switch }
files.d D source files
#cmdfile read arguments from cmdfile
-c do not link
-cov do code coverage analysis
-D generate documentation
-Dddocdir write documentation file to docdir directory
-Dffilename write documentation file to filename
-d silently allow deprecated features
-dw show use of deprecated features as warnings (default)
-de show use of deprecated features as errors (halt compilation)
-debug compile in debug code
-debug=level compile in debug code <= level
-debug=ident compile in debug code identified by ident
-debuglib=name set symbolic debug library to name
-defaultlib=name set default library to name
-deps=filename write module dependencies to filename
-g add symbolic debug info
-gc add symbolic debug info, pretend to be C
-gs always emit stack frame
-H generate 'header' file
-Hddirectory write 'header' file to directory
-Hffilename write 'header' file to filename
--help print help
-Ipath where to look for imports
-ignore ignore unsupported pragmas
-inline do function inlining
-Jpath where to look for string imports
-Llinkerflag pass linkerflag to link
-lib generate library rather than object files
-man open web browser on manual page
-map generate linker .map file
-noboundscheck turns off array bounds checking for all functions
-O optimize
-o- do not write object file
-odobjdir write object & library files to directory objdir
-offilename name output file to filename <---- [1]
-op do not strip paths from source file
-profile profile runtime performance of generated code
-property enforce property syntax
-quiet suppress unnecessary messages
-release compile release version
-run srcfile args... run resulting program, passing args
-unittest compile in unit tests
-v verbose
-version=level compile in version code >= level
-version=ident compile in version code identified by ident
-vtls list all variables going into thread local storage
-w warnings as errors (compilation will halt)
-wi warnings as messages (compilation will continue)
-X generate JSON file
-Xffilename write JSON file to filename
I marked the line that answers your question with [1] and an arrow.
Have a look at the -of, -od and -op switches. It's hard to be more specific without knowing what exactly you mean by "compile all its code to a certain location".

kgdb cannot find the source code when debugging kernel module

I want to debug a kernel module with kgdb,do as the following:
gdb: add-symbol-file /home/gaoqiang/kernel-32/fs/ext4/ext4.ko 0xffffffffa0122000 -s .bss 0xffffffffa016b380 -s .data 0xffffffffa0168400
gdb: break ext4_getattr
gdb: c
I successfully get to the break point,but gdb told me :"[ No Source Available ]" then
how to get gdb to find source code for the module?
As per your problem
(gdb) add-symbol-file /home/gaoqiang/kernel-32/fs/ext4/ext4.ko 0xffffffffa0122000 -s .bss 0xffffffffa016b380 -s .data 0xffffffffa0168400
I assume that the module is present in the directory /home/gaoqiang/kernel-32/fs/ext4/. If your source code is also in directory the gdb would not have given the error/warning.
So if the source files for ext4.ko module say ext4.c and the rest are not present in that directory, copy them to the directory.
(gdb)set solib-search-path /home/gaoqiang/kernel-32/fs/ext4/

Resources