Thursday, November 19, 2009

Size of all structures in your program

There are some cases when you want to find size of all structures in your program/project. For a given program it is easy because we can manually calculate or put a printf sizeof() to calculate a few structures. But for a project with few hundred files it is difficult. There is noway AFAIK in gcc to dump all the structure sizes while it compiles.


Here is a way todo it using dwarf debugging info if you are using gnu compiler tools. Compile your project output file with -g option, this will generate debugging information in your program. Then run objdump to dump the debug info. This debugging information contains all the information about your program, filter the output for "DW_TAG_structure_type" and you will get only structure information.

Here is how I did it:

objdump -W kernel.debug.reloc > debug.info

grep -e "DW_TAG_structure_type" debug.info --after-context=5 --mmap > structs.txt

Thursday, October 29, 2009

SLOC

Recently I was browsing some open source project's(as usual I forgot the name) web site and the author has put SLOC report for his project. It was pretty cool. I wanted to try it on some of my projects and tried sloccount(http://www.dwheeler.com/sloccount/) in my office but since my office PC doesnt have my personal project sources I was not able to get SLOC report for my projects.


Today I suddenly, I remembered about SLOC and tried it on my Ace project. And here is the output
Sam@samxp /cygdrive/e/Projects
$ sloccount ace_test/src
Creating filelist for app
Creating filelist for drivers
Creating filelist for include
Creating filelist for kernel
Creating filelist for lib
Have a non-directory at the top, so creating directory top_dir
Adding /cygdrive/e/Projects/ace_test/src/wscript to top_dir
Categorizing files.
Finding a working MD5 command....
Found a working MD5 command.
Computing results.


SLOC Directory SLOC-by-Language (Sorted)
13716 include ansic=13699,sh=17
9045 kernel ansic=8810,asm=221,python=14
3712 lib ansic=3691,sh=11,python=10
1062 drivers ansic=1051,python=11
41 top_dir python=41
10 app ansic=6,python=4


Totals grouped by language (dominant language first):
ansic: 27257 (98.81%)
asm: 221 (0.80%)
python: 80 (0.29%)
sh: 28 (0.10%)

Total Physical Source Lines of Code (SLOC) = 27,586
Development Effort Estimate, Person-Years (Person-Months) = 6.51 (78.15)
(Basic COCOMO model, Person-Months = 2.4 * (KSLOC**1.05))
Schedule Estimate, Years (Months) = 1.09 (13.10)
(Basic COCOMO model, Months = 2.5 * (person-months**0.38))
Estimated Average Number of Developers (Effort/Schedule) = 5.97
Total Estimated Cost to Develop = $ 879,761
(average salary = $56,286/year, overhead = 2.40).
SLOCCount, Copyright (C) 2001-2004 David A. Wheeler
SLOCCount is Open Source Software/Free Software, licensed under the GNU GPL.
SLOCCount comes with ABSOLUTELY NO WARRANTY, and you are welcome to
redistribute it under certain conditions as specified by the GNU GPL license;
see the documentation for details.
Please credit this data as "generated using David A. Wheeler's 'SLOCCount'."
Pretty cool isnt it? :)

Tuesday, October 27, 2009

Funny numbers

Freebsd kernel source files count vs Makefile count. Just from the numbers it looks like for every 4 source files there is an Makefile. I ran these commands when I thought of converting FreeBSD build system(make) to use waf(http://code.google.com/p/waf/) or scons(http://www.scons.org/).

root@freebsd-sam:/sys#find . -name "*.c" | wc -l
3171
root@freebsd-sam:/sys#find . -name "*.h" | wc -l
3004
root@freebsd-sam:/sys#find . -name "*.s" | wc -l
44

root@freebsd-sam:/sys#find . -name "Makefile*" | wc -l
746

And yes, after seeing this number I let me thought to stay inside for sometime.

Sunday, October 04, 2009

Call Trace without modifying the source

While investigating about gcc flag "-fprofile-arcs", I came to know about a new(to me) gcc flag and this blog entry is about it. For any large C project it is hard to learn/find call graph through code walk. From C prospective unless otherwise you put a printf in each function entry/exit it is hard to find the call trace.

GCC and ICC has a wonderful option "-finstrument-functions" to solve this. This option instructs the compiler to emit instructions to call a external function on each function's entry/exit. Defining these two functions like the following and adding the above option -finstrument-function to your makefile will do the magic.

void noinstrument
__cyg_profile_func_enter(void *this_fn, void *call_site)
{
printf("%p called from %p\n", this_fn, call_site);
}

void noinstrument
__cyg_profile_func_exit(void *this_fn, void *call_site)
{
printf("%p returns\n", this_fn);
}

Of course, you can do anything in these functions, for simplicity sake I just defined them as printfs.

Friday, September 04, 2009

Tracing ld

I was trying to do something with customized FreeBSD kernel which required constructors(.ctors) and destructor(.dtors) sections to be included in the final binary. So I used the normal gnu practice of including the following code into my linker script(/sys/conf/ldscript.i386).
.data.gcov :
{
__CTOR_LIST__ = .;
LONG((__CTOR_END__ - __CTOR_LIST__) /
(__CTOR_LIST2__ - __CTOR_LIST__) - 2 )
__CTOR_LIST2__ = .;
KEEP(*(.ctors))
LONG(0)
__CTOR_END__ = .;
__DTOR_LIST__ = .;
LONG(( __DTOR_END__ - __DTOR_LIST__ )/
(__CTOR_LIST2__ - __CTOR_LIST__) - 2)
KEEP(*(.dtors))
LONG(0)
__DTOR_END__ = .;
}
But when I tried to see the contents of of the linked kernel there were no constructors. Because
__CTOR_LIST__ and __CTOR_END__ are placed next to each other, from the linker script you can see the .ctors comes in between them.
$objdump -t kernel | grep __CTOR
c049cb8c g .data.gcov 00000000 __CTOR_LIST__
c049cb94 g .data.gcov 00000000 __CTOR_END__
c049cb90 g .data.gcov 00000000 __CTOR_LIST2__

$objdump -s -j .data.gcov kernel | head

kernel: file format elf32-i386-freebsd

Contents of section .data.gcov:
c049cb8c 00000000 00000000 00000000 00000000 ................
c049cb9c 5f090000 e7124ac0 e7124ac0 1b4a4ac0 _.....J...J..JJ.
c049cbac 1b4a4ac0 085c4ac0 085c4ac0 06234bc0 .JJ..\J..\J..#K.
c049cbbc 06234bc0 1f374bc0 1f374bc0 d43b4bc0 .#K..7K..7K..;K.
c049cbcc d43b4bc0 b1414bc0 b1414bc0 b2494bc0 .;K..AK..AK..IK.
c049cbdc b2494bc0 d77b4bc0 d77b4bc0 0e894bc0 .IK..{K..{K...K.
I tried to find what ld is doing by enabling --verbose option in SYSTEM_LD (/sys/conf/kern.pre.mk) but it did not help. Then I tried -Map option to ask ld to generate map file and it helped me.

In my environment the kernel is generated in step. First all system objects are partially linked(-r/-Ur option) to generate relocatable kernel. Then this relocatable kernel is linked with some other static modules to create the kernel. From the map files I could see the constructors are present in the relocatable kernel and dropped while creating the proper kernel. I guess it is a bug with ld. So I merged the two step process into one and it worked.

$objdump -t kernel | grep __CTOR
c049cf50 g .data.gcov 00000000 __CTOR_LIST__
c049f4e4 g .data.gcov 00000000 __CTOR_END__
c049cf54 g .data.gcov 00000000 __CTOR_LIST2__

$objdump -s -j .data.gcov kernel | head

kernel: file format elf32-i386-freebsd

Contents of section .data.gcov:
c049cf50 63090000 a7164ac0 a7164ac0 db4d4ac0 c.....J...J..MJ.
c049cf60 db4d4ac0 c85f4ac0 c85f4ac0 c6264bc0 .MJ.._J.._J..&K.
c049cf70 c6264bc0 df3a4bc0 df3a4bc0 943f4bc0 .&K..:K..:K..?K.
c049cf80 943f4bc0 71454bc0 71454bc0 724d4bc0 .?K.qEK.qEK.rMK.
c049cf90 724d4bc0 977f4bc0 977f4bc0 ce8c4bc0 rMK...K...K...K.
c049cfa0 ce8c4bc0 bbf74bc0 bbf74bc0 bb0a4cc0 ..K...K...K...L.