Linux kernel 3.x call-graphs with ncc-2.8

ncc  is a compiler, built specifically to extracts call-graph information from source code. One strong feature is analysis of function pointers. Call graphs can help explore and learn large code bases, which makes it especially useful for the Linux kernel. ncc comes with documentation on extracting call-graphs from 2.6 kernels, apparently tested circa 2008. We set out to test ncc on newer kernels (3.10.25)

Summary

ncc needs work to support the Linux kernel, while I solved some problems, more work needs to be done to complete the kernel compile.

__asm__ volatile and goto

ncc 1.8 does not support “__asm__ volatile” and __asm__ goto”, used in one of the first files compiled, kernel/bounds.c. To fix, add these to the function “__asm___statement” in ncc’s “parser.C”:

BUILD_BUG_ON_ZERO and BUILD_BUG_ON_NULL

The ncc compiler doesn’t handle these compile-time checks well. Disabled them in include/linux/bug.h:

nccar argument parsing

ncc emulates ar to link together collections of collected metadata. In the process, ncc makes assumptions on archive names (ending with .a or .o), however the kernel makefiles use filenames like “.28948.tmp”. This causes a segfault in ncc’s ar code. To fix, see highlighted lines below in “preproc.C”:

Turning off compiler optimizations

For some big files, ncc sputters and segfaults; I saw this with “init/init_task.c”. The core dump doesn’t help much in finding the root cause of this segfault. When I compiled ncc with -O0 with icc, the segfault never came and ncc carried on. When I recompiled ncc with the default optimization, the kernel compilation continued.

Running ncc on the kernel

After copying a .config file to the desired directory, ran the kernel compilation with:

 A typeof error

The compilation encounters these types of problems (“* not effective”):

Apparently ncc doesn’t like the rcu_assign_pointer in kvm/vmx.c

Which seems to be defined in include/linux/rcupdate.h:

To work-around, I’ve removed the parentheses containing the typeof here and in include/asm-generic/percpu.h:

and also in “arch/x86/include/asm/percpu.h”:

Fix low limits in aeqn

The aeqn class in ncc’s “cdb.C” has a hard-coded buffer size that is insufficient for processing “net/core/net_namespace.c”, resulting in a segfault. Increasing it seems to solve the problem:

Current fail

lib/vsprintf.c causes a segfault in cc_int_expression. The stack trace:

 

 

Posted in Tech Blog.

2 Comments

  1. Hello,

    I was trying to build the linux kernel v4.3 with ncc and this summary helped me a lot, especially the ncc patches, thanks! The following patch, at least in my case, seems to avoid the crash of ncc in lib/vsprintf.c:


    diff –git a/lib/vsprintf.c b/lib/vsprintf.c
    index 95cd63b..313ef58 100644
    — a/lib/vsprintf.c
    +++ b/lib/vsprintf.c
    @@ -695,8 +695,8 @@ char *resource_string(char *buf, char *end, struct resource *res,
    #define FLAG_BUF_SIZE (2 * sizeof(res->flags))
    #define DECODED_BUF_SIZE sizeof(“[mem – 64bit pref window disabled]”)
    #define RAW_BUF_SIZE sizeof(“[mem – flags 0x]”)
    – char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE,
    – 2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)];
    + const int _size = max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE, 2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE);
    + char sym[_size];

    char *p = sym, *pend = sym + sizeof(sym);
    int decode = (fmt[0] == ‘R’) ? 1 : 0;

Leave a Reply

Your email address will not be published. Required fields are marked *