Index: gdb/symfile.c =================================================================== RCS file: /cvs/src/src/gdb/symfile.c,v retrieving revision 1.246 diff -u -r1.246 symfile.c --- gdb/symfile.c 18 Sep 2009 17:33:51 -0000 1.246 +++ gdb/symfile.c 24 Sep 2009 19:27:58 -0000 @@ -2068,6 +2068,194 @@ ui_out_text (uiout, ".\n"); } +/* + Read symboles of a module file(.ko) of Linux kernel +*/ +/* taken from kernel source code */ +struct list_head { + CORE_ADDR next; + CORE_ADDR prev; +}; +struct module; +typedef unsigned int __kernel_mode_t; +typedef __kernel_mode_t mode_t; + +struct attribute { + const char *name; + struct module *owner; + mode_t mode; +}; + +struct module_attribute { + struct attribute attr; + ssize_t (*show)(struct module_attribute *, struct module *, char *); + ssize_t (*store)(struct module_attribute *, struct module *, + const char *, size_t count); + void (*setup)(struct module *, const char *); + int (*test)(struct module *); + void (*free)(struct module *); +}; + +struct attribute_group { + const char *name; + mode_t (*is_visible)(); + struct attribute **attrs; +}; + +struct module_sect_attr +{ + struct module_attribute mattr; + char *name; + unsigned long address; +}; + +struct module_sect_attrs +{ + struct attribute_group grp; + unsigned int nsections; + struct module_sect_attr attrs[0]; +}; + +#define MODULE_NAME_LEN (64 - sizeof(CORE_ADDR)) +struct module +{ + CORE_ADDR unused_state; + struct list_head list; + char name[MODULE_NAME_LEN]; +}; +#define OFFSET(structure, field) ((CORE_ADDR)(&((struct structure *)0)->field)) + +static char * +add_addr_on_linux_module (char *module_name) +{ + char *module_base_name, *s; + struct expression *expr; + struct value *val; + int offset_sect_attrs, ret, n; + struct symbol *modules; + struct module module; + CORE_ADDR module_addr, _msas; + struct module_sect_attrs msas; + struct module_sect_attr *kmsas; + char section_name[MODULE_NAME_LEN], *arg_str; + + /* Get base name of module. */ + s = strrchr (module_name, '/'); + if (s == NULL) /* not found */ + s = module_name; + else + s++; + module_base_name = xmalloc (strlen(s) + 1); + if (module_base_name == NULL) + { + warning ("can't allocate module_base_name"); + return NULL; + } + make_cleanup (xfree, module_base_name); + strcpy(module_base_name, s); + /* Discard .ko */ + s = strchr(module_base_name, '.'); + if (s != NULL) + *s = '\0'; + + /* Find whether the module is loaded. */ + /* Check to see if Linux is the supported version. */ + expr = parse_expression ("&((struct module *)0)->sect_attrs"); + val = evaluate_expression (expr); + offset_sect_attrs = unpack_long (value_type(val), value_contents_all(val)); + expr = parse_expression ("&((struct module_sect_attrs *)0)->attrs[1]"); + val = evaluate_expression (expr); + if (unpack_long (value_type(val), value_contents_all(val)) != + (long)&((struct module_sect_attrs *)0)->attrs[1]) { + warning ("your target kernel has difference struct module_sect_attrs"); + return NULL; + } + + /* Modules are in the linked list pointed by "modules" */ + modules = lookup_symbol ("modules", NULL, VAR_DOMAIN, NULL); + if (modules == NULL) { + warning ("can't find the address of modules"); + return NULL; + } + module_addr = SYMBOL_VALUE_ADDRESS(modules) - OFFSET(module, list.next); + do { + ret = target_read_memory(module_addr, + (gdb_byte *)&module, sizeof(module)); + if (ret != 0) + { + warning("can't read module"); + return NULL; + } + if (strcmp(module_base_name, module.name) == 0) /* found the module */ + break; + module_addr = module.list.next - OFFSET(module, list.next); + } while (module_addr + OFFSET(module, list.next) != + SYMBOL_VALUE_ADDRESS(modules)); + if (module_addr + OFFSET(module, list.next) == + SYMBOL_VALUE_ADDRESS(modules)) /* not found the module */ + { + warning("can't find %s in the linked list of Linux modules", + module_base_name); + return NULL; + } + + ret = target_read_memory (module_addr + offset_sect_attrs, + (gdb_byte *)&_msas, sizeof(_msas)); + if (ret != 0) + { + warning("can't read _msas on %s", module.name); + return NULL; + } + ret = target_read_memory (_msas, + (gdb_byte *)&msas, sizeof(msas)); + if (ret != 0) + { + warning("can't read msas on %s", module.name); + return NULL; + } + kmsas = xmalloc (sizeof(struct module_sect_attr) * msas.nsections); + if (kmsas == NULL) + { + warning ("can't allocate kmsas"); + return NULL; + } + make_cleanup (xfree, kmsas); + ret = target_read_memory (_msas + OFFSET(module_sect_attrs, attrs[0]), + (char *)kmsas, + sizeof(*kmsas) * msas.nsections); + if (ret != 0) + { + warning ("can't read kmsas"); + return NULL; + } + /* Look for .text section */ + for (n = 0; n < msas.nsections; n++, kmsas++) + { + ret = target_read_memory((CORE_ADDR)kmsas->name, + section_name, MODULE_NAME_LEN); + if (ret != 0) + { + warning ("can't read kmsas->name"); + return NULL; + } + if (strcmp(section_name, ".text") == 0) + break; + } + if (n < msas.nsections) /* found .text section */ + { + /* " 0x%016lx" + terminating '\0' */ + arg_str = xmalloc (strlen(module_name) + 1 + 2 + 16 + 1); + if (arg_str == NULL) { + warning ("can't allocate arg_str"); + return NULL; + } + sprintf (arg_str, "%s 0x%016lx", module_name, kmsas->address); + /* No need to free arg_str. make_cleanup_freeargv() takes care. */ + } + + return arg_str; +} + /* This function allows the addition of incrementally linked object files. It does not modify any state in the target, only in the debugger. */ /* Note: ezannoni 2000-04-13 This function/command used to have a @@ -2110,12 +2298,25 @@ dont_repeat (); - if (args == NULL) - error (_("add-symbol-file takes a file name and an address")); + if (args == NULL || *args == '\0') + error (_("Usage: add-symbol-file FILE [ADDR [-s -s ...] ]")); argv = gdb_buildargv (args); make_cleanup_freeargv (argv); + if (argv[1] == NULL) /* no ADDR */ + { + if (remote_break_mode != remote_break_sysrq_g) + { + error (_("Don't you forget \"set remotebreak sysrq-g\"?")); + } + args = add_addr_on_linux_module (args); + if (args == NULL) + return; + argv = gdb_buildargv (args); + make_cleanup_freeargv (argv); + } + for (arg = argv[0], argcnt = 0; arg != NULL; arg = argv[++argcnt]) { /* Process the argument. */ @@ -2222,8 +2423,11 @@ so we can't determine what section names are valid. */ } - if (from_tty && (!query ("%s", ""))) - error (_("Not confirmed.")); + if (remote_break_mode != remote_break_sysrq_g) /* Not module loading */ + { + if (from_tty && (!query ("%s", ""))) + error (_("Not confirmed.")); + } symbol_file_add (filename, from_tty ? SYMFILE_VERBOSE : 0, section_addrs, flags);