lkml.org 
[lkml]   [2001]   [Apr]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
Subject[SCRIPT] Get potential __init functions from the kernel image
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:matze@camline.com 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

\
 
 \ /
  Last update: 2005-03-22 13:26    [W:0.025 / U:0.856 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site