Linux Kernel: Print Callee and Caller

Print the callback function name

If you cannot trace which function gets called when you call from core driver using function pointer, you can print function name using pf format specifier.
Linux maintains symbol table so based on function address, it can identify function name based on address pointed by function pointer.
e.g. Core driver calls hardware specific enable/disable functions:
core->ops->enable(). If you are not sure, which function is executed as a result of this call, you can print them using %pf or %pF:
pr_info("callee function name is: %pf,  core->ops->enable)
%pf prints without offset (e.g. foo) while %pF prints with offset (e.g. foo+0x00/0x80)
Reference: https://www.kernel.org/doc/Documentation/printk-formats.txt.
Thanks Bhargav(br13patel) for sharing this!

Print caller name

There are few ways to trace caller in Linux kernel.
  • Print stack backtrace
    • dump_stack();
      • To enable the dump_stack() function in the kernel config the following options must be set.
        1. Kernel hacking -> Kernel debugging
        2. Kernel hacking -> Verbose kernel error messages
    • WARN_ON(1);
  • Print caller name
    • pr_info(“caller function name is: %pf,  __builtin_return_address(0))

Array Initialise selected indexes

#include <stdio.h>

#define ARRAY_SIZE(n) (sizeof(n)/sizeof(n[0]))

int main()
{
	int i;
	int arr[] = {
		[3] = 3,
		[5] = 5,
	};

	for (i = 0; i < ARRAY_SIZE(arr); i++)
		printf("arr[%d] = %d\n", i, arr[i]);

	return 0;
}

Output:

arr[0] = 0
arr[1] = 0
arr[2] = 0
arr[3] = 3
arr[4] = 0
arr[5] = 5

Update forked repo with remote repo

Auto merge

Add remote repository

# cd <forked-repo>
# git checkout 
# git remote add upstream <upstream-repo-git-link>
#git fetch upstream

Updating fork from remote repo

# git pull upstream <upstream-branch>

Example (This is what I did to sync from remote branch and push to forked repo)

# cd <forked-repo>
# git checkout
# git remote add upstream <upstream-repo-git-link>
# git fetch upstream
# git pull upstream master --rebase

As local repo changes are rebased, faced error while pushing changes to forked repo. Runt these commands to rebase changes for forked branch.

# git pull --rebase
# git push origin <forked-remote-branch>

 

Force Update

If normal merge doesn’t wok and you are ready to do force update of your forked repo branch with original repo branch:

#git remote add upstream <upstream-repo-git-link>
# git fetch upstream
# git checkout <upstream branch>
# git reset --hard upstream/<upstream-branch>  
# git push origin <forked-remote-branch> --force 

 

GCC –gc-sections to remove unused code and data

Sometimes it is required to reduce code size. Code size may be higher due to unused functions and data which are declared but not used. Sometimes it is not easier/possible to modify code and remove that.

There are GCC options which can help here:

  1. -ffunction-sections
  2. -fdata-sections
  3. –gc-sections
  4. –print-gc-sections

First two flags are passed at compilation stage. These flags tells compiler to create separate sections for each functions and data. Third flag is passed to linker which checks each section and remove sections which are not used.

-ffunction-sections

By default every functions are combined into single .text function but when we use “-ffunction-sections” flag, compiler creates different text section for each function (e.g. .text.func1, .text.func2, etc)

-fdata-sections

By default variables belongs .data are combined into single .data function but when we use “-fdata-sections” flag, compiler creates different .data section for each data (e.g. .data.var1, .data.var2, etc)

–gc-sections

This tells linker to remove unused sections.

–print-gc-sections

This flag is useful for debugging and identifying removed sections. This prints sections which are removed.

Example:

Consider below C example:

#include

int globalval = 5;

int main()
{
printf (“Hello World!\n”);
return 0;
}

int func(void)
{
printf(“I am function\n”);
return 0;
}

Case 1: Without GCC flags

When we compile program without above flags, compiler includes all functions and data even if those are not used.

~$ gcc -c test.c -o test.o
~$ gcc -o test.bin test.o

Size of program:

~$ size test.bin
   text   data    bss    dec    hex filename
   1253    556      4   1813    715 test.bin

obj-dump snippet

~$ objdump -x test.o
 - - - - - -
SYMBOL TABLE:
0000000000000000 l    df *ABS*	0000000000000000 test.c
0000000000000000 l    d  .text	0000000000000000 .text
0000000000000000 l    d  .data	0000000000000000 .data
0000000000000000 l    d  .bss	0000000000000000 .bss
0000000000000000 l    d  .rodata	0000000000000000 .rodata
0000000000000000 l    d  .note.GNU-stack	0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame	0000000000000000 .eh_frame
0000000000000000 l    d  .comment	0000000000000000 .comment
0000000000000000 g     O .data	0000000000000004 globalval
0000000000000000 g     F .text	0000000000000015 main
0000000000000000         *UND*	0000000000000000 puts
0000000000000015 g     F .text	0000000000000015 func
 - - - - - -

Case 2: With GCC flags

When we compile program with -ffunction-sections and -fdata-sections flags, compiler creates separate sections for each function and data. When we provide –gc-sections flag while linking, linker removes all unused sections.

~$ gcc -fdata-sections -ffunction-sections -c test.c -o test.o
~$ gcc -Wl,--gc-sections -Wl,--print-gc-sections -o test.bin test.o
/usr/bin/ld: Removing unused section '.rodata.cst4' in file '/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o'
/usr/bin/ld: Removing unused section '.data' in file '/usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o'
/usr/bin/ld: Removing unused section '.data' in file '/usr/lib/gcc/x86_64-linux-gnu/5/crtbegin.o'
/usr/bin/ld: Removing unused section '.data.globalval' in file 'section.o'
/usr/bin/ld: Removing unused section '.text.func' in file 'section.o'

Size of program:

~$ size test.bin
   text   data    bss    dec    hex filename
   1193    536      8   1737    6c9 test.bin

obj-dump snippet

~$ objdump -x test.o
 - - - - - -
SYMBOL TABLE:
0000000000000000 l    df *ABS*	0000000000000000 test.c
0000000000000000 l    d  .text	0000000000000000 .text
0000000000000000 l    d  .data	0000000000000000 .data
0000000000000000 l    d  .bss	0000000000000000 .bss
0000000000000000 l    d  .data.globalval	0000000000000000 .data.globalval
0000000000000000 l    d  .rodata	0000000000000000 .rodata
0000000000000000 l    d  .text.main	0000000000000000 .text.main
0000000000000000 l    d  .text.func	0000000000000000 .text.func
0000000000000000 l    d  .note.GNU-stack	0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame	0000000000000000 .eh_frame
0000000000000000 l    d  .comment	0000000000000000 .comment
0000000000000000 g     O .data.globalval	0000000000000004 globalval
0000000000000000 g     F .text.main	0000000000000015 main
0000000000000000         *UND*	0000000000000000 puts
0000000000000000 g     F .text.func	0000000000000015 func
 - - - - - -

Conclusion

As it can be seen from example, that in second case, different sections for each functions (.text.main and .text.func) and data (.data.globalval) are created. While linking, these are removed ,as they are not used.

Device Tree Debugging

DTB-DTS conversion (Linux kernel)

  • Convert DTS file to DTB
  • ./scripts/dtc/dtc -I dts -O dtb -o .dtb .dts
  • Convert DTB file to DTS

  • ./scripts/dtc/dtc -I dtb -O dts -o .dts .dtb

 U-boot FDT commands

  • print fdt address
  • print $fdt_addr_r (or $fdt_addr)
  • Set FDT node property
  • fdt addr $fdt_addr
    fdt set /testnode testprop testvalue
  • remove FDT node property
  • fdt addr $fdt_addr
    fdt rm /testnode testprop
  • Remove DT node
  • fdt rm /testnode
  • List FDT nodes
  • fdt list                         /* All nodes */
    fdt list /cpus                   /* All nodes under cups node */
  • Create node
  • fdt mknode / testnode

References:

Cross compiling and Linking

  • Compilation
    arm-uclinuxeabi-gcc  -g  -Os   -g2 -mthumb -mcpu=cortex-m3 -fsigned-char -O2 -fno-builtin-puts -fno-common -ffixed-r8 -D__KERNEL__ -I -fno-builtin -ffreestanding -isystem  -pipe  -DCONFIG_ARM -D__ARM__ -D<MACRO="(VALUE)"> -Wall -Wstrict-prototypes -fno-stack-protector   -o   -c
    
  • De-assemble
    arm-uclinuxeabi-objdump -S <O_FILE>
    
  • Library
    arm-uclinuxeabi-ar crv <A_FILENAME> <O_FILES> 
    
  • Linking
    arm-uclinuxeabi-ld -Bstatic -T<LDS_FILENAME> -u<UNDEFINED_SYMBOLS> <O_FILES> <A_FILES> -lgcc -Map <MAP_FILE> -o <OUT_FILENAME>
    

    Example linker script:

    OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
    OUTPUT_ARCH(arm)
    ENTRY(main)
    
    MEMORY
    {
     /* SmartFusion internal eSRAM */
     ram (rwx) : ORIGIN = 0x20000000, LENGTH = 64k
    }
    
    SECTIONS
    {
     .text :
     {
       . = ALIGN(4);
        *(.text*)
    	. = ALIGN(4);
        _etext = .;
     } >ram
    }
    end = .;
  • Other format output
    arm-none-eabi-objcopy --gap-fill=0xff -O ihex myprog  "myprog.hex"
    arm-none-eabi-objcopy --gap-fill=0xff -O binary myprog  "myprog.bin"
    arm-none-eabi-objcopy -O srec myprog "myprog.srec"
    arm-none-eabi-objdump -h -S myprog > "myprog.lst"

Linux Kernel – Tools/Scripts

Here are few tools/scripts which are useful for static analysis of code:

  • Checkpatch
    # ./script/checkpath.pl <patch_file(s)>
    # ./script/checkpatch.pl --file <file_name(s)>
    
  • kmemleak
    Check kernel memory leak using kmemleak:

    # cppcheck <source-dir>

    Kmemleak usage

  • Coccicheck
    • make coccicheck MODE=<mode>

    Where,

    ‘patch’ proposes a fix, when possible.

    ‘report’ generates a list in the following format: file:line:column-column: message

    ‘context’ highlights lines of interest and their context in a diff-like style.Lines of interest are indicated with ‘-‘

    ‘org’ generates a report in the Org mode format of Emacs.

    • To apply Coccinelle to a specific directory, M= can be used.
      For example, to check drivers/net/wireless/ one may write:
    make coccicheck M=drivers/net/wireless/
    • To apply Coccinelle on a file basis, instead of a directory basis, the
      following command may be used:

      make C=1 CHECK="scripts/coccicheck"
    • To check only newly edited code, use the value 2 for the C flag, i.e.
      make C=2 CHECK="scripts/coccicheck"
  • kselftest
    • Run kselftest install tool in tools/testing/selftests
       # cd tools/testing/selftests
       # ./kselftest_install.sh [ install_location ]
    • Default install tool: in tools/testing/selftests
    • Specify install location:
    # ./kselftest_install.sh /tmp
    • Kselftest install creates run_kselftest.sh
    • Run tests:
# cd install_dir
# ./run_kselftest.sh