Re: A script that used by GDB to load the symbols from Linux kernel modules

From: Hui Zhu
Date: Thu Aug 18 2011 - 04:25:24 EST


Add a menu for select directory and a check.

Thanks,
Hui

On Wed, Aug 17, 2011 at 13:45, Hui Zhu <teawater@xxxxxxxxx> wrote:
> Hi,
>
> When use GDB to debug or trace your kernel with KGDB, QEMU debug
> interface or KGTP.  You must get some trouble with LKM symbols.  For
> example:
> (gdb) target remote localhost:12345
> Remote debugging using localhost:12345
> native_safe_halt () at
> /home/teawater/big/kernel/linux-2.6/arch/x86/include/asm/irqflags.h:50
> 50      }
> (gdb) b e100_poll
> Function "e100_poll" not defined.
> Make breakpoint pending on future shared library load? (y or [n])
> This is because GDB didn't get the LKM symbols.  You can do it with
> your hand.  But if you have a lot of LKMs, it will need some time.
>
> Now, GDB support python script.  The attachment is a script to load
> all symbols from Linux kernel modules to GDB.
> For example:
> (gdb) target remote localhost:12345
> Remote debugging using localhost:12345
> native_safe_halt () at
> /home/teawater/big/kernel/linux-2.6/arch/x86/include/asm/irqflags.h:50
> 50      }
> (gdb) so ~/kernel/svn/branches/teawater/getmod.py
> (gdb) b e100_poll
> Breakpoint 1 at 0xc889db40: file
> /home/teawater/big/kernel/linux-2.6/drivers/net/e100.c, line 2165.
>
> This script will include in KGTP(https://code.google.com/p/kgtp/) source.
>
> Thanks,
> Hui
>
#!/usr/bin/python

# This script is used by GDB to load the symbols from Linux kernel modules
# GPL
# Copyright(C) Hui Zhu (teawater@xxxxxxxxx), 2011

#Set special mod_search_dir
#set $mod_search_dir="dir"
#Clear special mod_search_dir
#set $mod_search_dir=(void)1

import gdb;
import os;

def format_file(name):
tmp = "";
for c in name:
if c == "_":
c = "-";
tmp += c;
return tmp;

#Check if the target is available
if str(gdb.selected_thread()) == "None":
raise gdb.error("Please connect to Linux Kernel before use the script.");

#Output the help
print "Use GDB command \"set $mod_search_dir=dir\" to set an directory for search the modules."

#Get the mod_search_dir
mod_search_dir_list = [];
#Get dir from $mod_search_dir
tmp_dir = gdb.parse_and_eval("$mod_search_dir");
if tmp_dir.type.code == gdb.TYPE_CODE_ARRAY:
tmp_dir = str(tmp_dir);
tmp_dir = tmp_dir[1:len(tmp_dir)];
tmp_dir = tmp_dir[0:tmp_dir.index("\"")];
mod_search_dir_list.append(tmp_dir);
#Get dir that same with current vmlinux
tmp_dir = str(gdb.execute("info files", False, True));
tmp_dir = tmp_dir[tmp_dir.index("Symbols from \"")+len("Symbols from \""):len(tmp_dir)];
tmp_dir = tmp_dir[0:tmp_dir.index("\"")];
tmp_dir = tmp_dir[0:tmp_dir.rindex("/")];
mod_search_dir_list.append(tmp_dir);
#Get the dir of current Kernel
tmp_dir = "/lib/modules/" + str(os.uname()[2]);
if os.path.isdir(tmp_dir):
mod_search_dir_list.append(tmp_dir);
#Let user choice dir
mod_search_dir = "";
while mod_search_dir == "":
for i in range(0, len(mod_search_dir_list)):
print str(i)+". "+mod_search_dir_list[i];
try:
s = input('Select a directory for search the modules [0]:');
except SyntaxError:
s = 0;
except:
continue;
if s < 0 or s >= len(mod_search_dir_list):
continue;
mod_search_dir = mod_search_dir_list[i];

mod_list_offset = long(gdb.parse_and_eval("((size_t) &(((struct module *)0)->list))"));
mod_list = long(gdb.parse_and_eval("(&modules)"));
mod_list_current = mod_list;

while 1:
mod_list_current = long(gdb.parse_and_eval("((struct list_head *) "+str(mod_list_current)+")->next"));

#check if need break the loop
if mod_list == mod_list_current:
break;

mod = mod_list_current - mod_list_offset;

#get mod_name
mod_name = str(gdb.parse_and_eval("((struct module *)"+str(mod)+")->name"));
mod_name = mod_name[mod_name.index("\"")+1:len(mod_name)];
mod_name = mod_name[0:mod_name.index("\"")];
mod_name += ".ko"
mod_name = format_file(mod_name);

#get mod_dir_name
mod_dir_name = "";
for root, dirs, files in os.walk(mod_search_dir):
for afile in files:
tmp_file = format_file(afile);
if tmp_file == mod_name:
mod_dir_name = os.path.join(root,afile);
break;
if mod_dir_name != "":
break;

command = " ";

#Add module_core to command
command += str(gdb.parse_and_eval("((struct module *)"+str(mod)+")->module_core"));

#Add each sect_attrs->attrs to command
#get nsections
nsections = int(gdb.parse_and_eval("((struct module *)"+str(mod)+")->sect_attrs->nsections"));
sect_attrs = long(gdb.parse_and_eval("(u64)((struct module *)"+str(mod)+")->sect_attrs"));
for i in range(0, nsections):
command += " -s";
tmp = str(gdb.parse_and_eval("((struct module_sect_attrs *)"+str(sect_attrs)+")->attrs["+str(i)+"].name"));
tmp = tmp[tmp.index("\"")+1:len(tmp)];
tmp = tmp[0:tmp.index("\"")];
command += " "+tmp;
tmp = str(gdb.parse_and_eval("((struct module_sect_attrs *)"+str(sect_attrs)+")->attrs["+str(i)+"].address"));
command += " "+tmp;

if mod_dir_name == "":
print "Can find out",mod_name,"from directory.";
print "Please use following command load the symbols from it:"
print "add-symbol-file some_dir/"+mod_name+command;
else:
#print "add-symbol-file "+mod_dir_name+command;
gdb.execute("add-symbol-file "+mod_dir_name+command, False, False);