Hi! I got bored over Easter and wrote this little script to get all users of a function using objdump on a vmlinux image. "users" are functions that do ordinary calls to that function, EXPORT_SYMBOL declarations, functions which get called by initcall and setup functions. Moreover a special character is prepended to each function - either if it is a function in the .text.init segment or a normal .text function. What is the benefit of this script? I think there are a lot of benefits but I used it to get functions which are not in the .text.init segment but should be moved to because the only users of this function are initfuncs themselves. To get a view of this invoke the script using $ ./create_user_map <vmlinux image> It creates a file user_map which contains the results. Additionally the list of _potential_ __init functions in this image is displayed. Why potential? The primary reason is, that the information is taken from an image. Maybe there are other callers of this function which are not compiled in. But this can be verified easily using a find-xargs-grep combo on the kernel source tree. First results of this are already in the ac-tree, namely some aha1542_* functions and rand_initialize(). I also sent another bunch of functions to Alan which are not included in any tree yet, namely mcheck_init(), init_irq_proc(), start_context_thread() and init_timervecs(). The other reason for _potential_ is, that there are function which use exceptions and thus they cannot get into the .init section, namely do_test_wp_bit(). I just wanted to provide this script to the community to encourage everyone to run this on his latest image. Doing this, we can finally get all functions which could be trown away after the initialization phase and shrink the size of unswappable kernel memory. Comments? Have fun, Matze P.S.: Maybe there are other interesting things to look at. E.g. all functions which are only exported using EXPORT_SYMBOL but only used in rare configurations. In this case, we could add a config option which disables this EXPORT_SYMBOL declarations and the linker would throw them away automatically. -- Matthias Hanisch mailto:[EMAIL PROTECTED] phone: +49 8137 935-219
#!/bin/sh if [ $# -lt 1 ]; then echo "Usage: $0 <vmlinux-image>" exit 1 fi image=$1 if [ ! -r $image ]; then echo "Image $image not readable" exit 1 fi objdump -hD $image | awk ' BEGIN { init_start="ffffffff" init_end="ffffffff" } / .text.init/ { # # Get the start address of init section of section header information # if (init_start == "ffffffff") { init_start=$4 printf("Start of init section: %s\n", init_start) >> "/dev/tty" } } / .data.page_aligned/ { # # Get the end address of init section of section header information # if (init_end == "ffffffff") { init_end=$4 printf("End of init section: %s\n", init_end) >> "/dev/tty" } } />:$/ { # # Start of a function # current_func = $2 gsub("[<>:]", "", current_func) in_address = $1 if (in_address >= init_start && in_address < init_end) function_prefix = "@"; else function_prefix = "&"; export_definition = index(current_func, "__kstrtab_"); init_call = index(current_func, "__initcall_"); setup_call = index(current_func, "__setup_"); if (export_definition) { current_func = substr(current_func, export_definition + 10) current_func = function_prefix current_func user[current_func] = user[current_func] " EXPORT" } else if (init_call) { current_func = substr(current_func, init_call + 11) current_func = function_prefix current_func user[current_func] = user[current_func] " INITCALL" } else if (setup_call) { current_func = substr(current_func, setup_call + 8) current_func = function_prefix current_func user[current_func] = user[current_func] " SETUPCALL" } else { current_func = function_prefix current_func user[current_func] = ": " user[current_func] } printf("%s: %s\n", in_address, current_func) >> "/dev/tty" } /call / { # # A call instruction of a function # stmt = substr($0, index($0, "call ")) num = split(stmt, col); if (num == 3) { name = col[3] address = col[2] gsub("[<>]", "", name) if (address >= init_start && address < init_end) name = "@" name else name = "&" name user[name] = user[name] " " current_func } } END { for (fnc in user) printf("%s%s\n", fnc, user[fnc]) } ' > user_map echo "" echo "" echo "List of all functions with their users are in file user_map." echo " Function prefix '@' means: function is in .text.init section" echo " Function prefix '&' means: function is in ordinary .text section" echo "" echo "TODO List:" echo "1. Deal with collisions in function name space" echo "2. Deal with data" echo "3. Deal with function pointers in structs or function parameters" echo "" echo "" echo "List of all potential init functions:" echo "-------------------------------------" grep "^&" user_map | cut -c2- | grep -v "&" | grep -v ": $" | grep -v EXPORT