summaryrefslogtreecommitdiffstats
path: root/gnu
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-01-28 21:40:10 +0000
committerjhb <jhb@FreeBSD.org>2008-01-28 21:40:10 +0000
commita92e1fcff274750e78b998b94ab8233e321d8493 (patch)
tree797c45d041545b24b2ab94562383eaf645ef02ee /gnu
parentd3871c9ec16a02271112e072ff1471dbea642803 (diff)
downloadFreeBSD-src-a92e1fcff274750e78b998b94ab8233e321d8493.zip
FreeBSD-src-a92e1fcff274750e78b998b94ab8233e321d8493.tar.gz
Add support for automatically loading symbols for kld's on startup:
- Add a new 'kgdb_auto_load_klds()' routine which is invoked during startup that walks the list of linker files and tries to find a matching kld on disk for each non-kernel kld. If a kld file is found, then it is added as if the 'add-kld' command is invoked. One change from 'add-kld' is that this method attempts to use the 'pathname' from the linker_file structure first to try to load the file. If that fails it then looks in the kernel directory followed by the directories in the module path. - Move the kld file suffix handling into a separate routine so that it can be called standalone and to reduce duplicate code in find_kld_path(). - Cache the offsets of members of 'struct linker_file' during startup instead of computing them for each 'add-kld'. - Use GDB's target_read_string() instead of direct KVM access. - Add all resident sections from a kld by using bfd_map_over_sections() to build the section list rather than just adding symbols for ".text", ".data", ".bss", and ".rodata". - Change the 'add-kld' command to do a y/n prompt before adding the symbols when run interactively to match 'add-symbol-file'. MFC after: 1 week
Diffstat (limited to 'gnu')
-rw-r--r--gnu/usr.bin/gdb/kgdb/kgdb.h1
-rw-r--r--gnu/usr.bin/gdb/kgdb/kld.c386
-rw-r--r--gnu/usr.bin/gdb/kgdb/trgt.c1
3 files changed, 248 insertions, 140 deletions
diff --git a/gnu/usr.bin/gdb/kgdb/kgdb.h b/gnu/usr.bin/gdb/kgdb/kgdb.h
index 32f9a1e..14b220b 100644
--- a/gnu/usr.bin/gdb/kgdb/kgdb.h
+++ b/gnu/usr.bin/gdb/kgdb/kgdb.h
@@ -48,6 +48,7 @@ struct kthr {
extern struct kthr *curkthr;
void kgdb_add_kld_cmd(char *, int);
+void kgdb_auto_load_klds(void);
void kgdb_target(void);
void kgdb_trgt_fetch_registers(int);
void kgdb_trgt_store_registers(int);
diff --git a/gnu/usr.bin/gdb/kgdb/kld.c b/gnu/usr.bin/gdb/kgdb/kld.c
index 46aee96..e0e0110 100644
--- a/gnu/usr.bin/gdb/kgdb/kld.c
+++ b/gnu/usr.bin/gdb/kgdb/kld.c
@@ -41,6 +41,16 @@ __FBSDID("$FreeBSD$");
#include "kgdb.h"
+/*
+ * TODO
+ *
+ * - Use 'target_read_memory()' instead of kvm_read().
+ * - Hook into the solib stuff perhaps?
+ */
+
+/* Offsets of fields in linker_file structure. */
+static CORE_ADDR off_address, off_filename, off_pathname, off_next;
+
static int
kld_ok (char *path)
{
@@ -52,68 +62,72 @@ kld_ok (char *path)
}
/*
- * Look for a matching file in the following order:
+ * Look for a matching file checking for debug suffixes before the raw file:
* - filename + ".symbols" (e.g. foo.ko.symbols)
* - filename + ".debug" (e.g. foo.ko.debug)
* - filename (e.g. foo.ko)
- * - dirname(kernel) + filename + ".symbols" (e.g. /boot/kernel/foo.ko.symbols)
- * - dirname(kernel) + filename + ".debug" (e.g. /boot/kernel/foo.ko.debug)
- * - dirname(kernel) + filename (e.g. /boot/kernel/foo.ko)
- * - iterate over each path in the module path looking for:
- * - dir + filename + ".symbols" (e.g. /boot/modules/foo.ko.symbols)
- * - dir + filename + ".debug" (e.g. /boot/modules/foo.ko.debug)
- * - dir + filename (e.g. /boot/modules/foo.ko)
+ */
+static const char *kld_suffixes[] = {
+ ".symbols",
+ ".debug",
+ "",
+ NULL
+};
+
+static int
+check_kld_path (char *path, size_t path_size)
+{
+ const char **suffix;
+ char *ep;
+
+ ep = path + strlen(path);
+ suffix = kld_suffixes;
+ while (*suffix != NULL) {
+ if (strlcat(path, *suffix, path_size) < path_size) {
+ if (kld_ok(path))
+ return (1);
+ }
+
+ /* Restore original path to remove suffix. */
+ *ep = '\0';
+ suffix++;
+ }
+ return (0);
+}
+
+/*
+ * Try to find the path for a kld by looking in the kernel's directory and
+ * in the various paths in the module path.
*/
static int
find_kld_path (char *filename, char *path, size_t path_size)
{
CORE_ADDR module_path_addr;
- char module_path[PATH_MAX];
+ char *module_path;
char *kernel_dir, *module_dir, *cp;
+ int error;
- snprintf(path, path_size, "%s.symbols", filename);
- if (kld_ok(path))
- return (1);
- snprintf(path, path_size, "%s.debug", filename);
- if (kld_ok(path))
- return (1);
- snprintf(path, path_size, "%s", filename);
- if (kld_ok(path))
- return (1);
kernel_dir = dirname(kernel);
if (kernel_dir != NULL) {
- snprintf(path, path_size, "%s/%s.symbols", kernel_dir,
- filename);
- if (kld_ok(path))
- return (1);
- snprintf(path, path_size, "%s/%s.debug", kernel_dir, filename);
- if (kld_ok(path))
- return (1);
snprintf(path, path_size, "%s/%s", kernel_dir, filename);
- if (kld_ok(path))
+ if (check_kld_path(path, path_size))
return (1);
}
module_path_addr = kgdb_parse("linker_path");
- if (module_path_addr != 0 &&
- kvm_read(kvm, module_path_addr, module_path, sizeof(module_path)) ==
- sizeof(module_path)) {
- module_path[PATH_MAX - 1] = '\0';
- cp = module_path;
- while ((module_dir = strsep(&cp, ";")) != NULL) {
- snprintf(path, path_size, "%s/%s.symbols", module_dir,
- filename);
- if (kld_ok(path))
- return (1);
- snprintf(path, path_size, "%s/%s.debug", module_dir,
- filename);
- if (kld_ok(path))
- return (1);
- snprintf(path, path_size, "%s/%s", module_dir,
- filename);
- if (kld_ok(path))
- return (1);
+ if (module_path_addr != 0) {
+ target_read_string(module_path_addr, &module_path, PATH_MAX,
+ &error);
+ if (error == 0) {
+ make_cleanup(xfree, module_path);
+ cp = module_path;
+ while ((module_dir = strsep(&cp, ";")) != NULL) {
+ snprintf(path, path_size, "%s/%s", module_dir,
+ filename);
+ if (check_kld_path(path, path_size))
+ return (1);
+ }
}
- }
+ }
return (0);
}
@@ -150,36 +164,29 @@ read_pointer (CORE_ADDR address)
static int
find_kld_address (char *arg, CORE_ADDR *address)
{
- CORE_ADDR kld, filename_addr;
- CORE_ADDR off_address, off_filename, off_next;
- char kld_filename[PATH_MAX];
+ CORE_ADDR kld;
+ char *kld_filename;
char *filename;
- size_t filelen;
+ int error;
- /* Compute offsets of relevant members in struct linker_file. */
- off_address = kgdb_parse("&((struct linker_file *)0)->address");
- off_filename = kgdb_parse("&((struct linker_file *)0)->filename");
- off_next = kgdb_parse("&((struct linker_file *)0)->link.tqe_next");
if (off_address == 0 || off_filename == 0 || off_next == 0)
return (0);
filename = basename(arg);
- filelen = strlen(filename) + 1;
kld = kgdb_parse("linker_files.tqh_first");
while (kld != 0) {
/* Try to read this linker file's filename. */
- filename_addr = read_pointer(kld + off_filename);
- if (filename_addr == 0)
- goto next_kld;
- if (kvm_read(kvm, filename_addr, kld_filename, filelen) !=
- filelen)
+ target_read_string(read_pointer(kld + off_filename),
+ &kld_filename, PATH_MAX, &error);
+ if (error)
goto next_kld;
/* Compare this kld's filename against our passed in name. */
- if (kld_filename[filelen - 1] != '\0')
- goto next_kld;
- if (strcmp(kld_filename, filename) != 0)
+ if (strcmp(kld_filename, filename) != 0) {
+ xfree(kld_filename);
goto next_kld;
+ }
+ xfree(kld_filename);
/*
* We found a match, use its address as the base
@@ -196,109 +203,208 @@ find_kld_address (char *arg, CORE_ADDR *address)
return (0);
}
+struct add_section_info {
+ struct section_addr_info *section_addrs;
+ int sect_index;
+ CORE_ADDR base_addr;
+ int add_kld_command;
+};
+
static void
-add_section(struct section_addr_info *section_addrs, int *sect_indexp,
- char *name, CORE_ADDR address)
+add_section (bfd *bfd, asection *sect, void *arg)
{
- int sect_index;
+ struct add_section_info *asi = arg;
+ CORE_ADDR address;
+ char *name;
- sect_index = *sect_indexp;
- section_addrs->other[sect_index].name = name;
- section_addrs->other[sect_index].addr = address;
- printf_unfiltered("\t%s_addr = %s\n", name,
- local_hex_string(address));
- sect_index++;
- *sect_indexp = sect_index;
+ /* Ignore non-resident sections. */
+ if ((bfd_get_section_flags(bfd, sect) & (SEC_ALLOC | SEC_LOAD)) == 0)
+ return;
+
+ name = xstrdup(bfd_get_section_name(bfd, sect));
+ make_cleanup(xfree, name);
+ address = asi->base_addr + bfd_get_section_vma(bfd, sect);
+ asi->section_addrs->other[asi->sect_index].name = name;
+ asi->section_addrs->other[asi->sect_index].addr = address;
+ asi->section_addrs->other[asi->sect_index].sectindex = sect->index;
+ if (asi->add_kld_command)
+ printf_unfiltered("\t%s_addr = %s\n", name,
+ local_hex_string(address));
+ asi->sect_index++;
}
-void
-kgdb_add_kld_cmd (char *arg, int from_tty)
+static void
+load_kld (char *path, CORE_ADDR base_addr, int from_tty, int add_kld_command)
{
- struct section_addr_info *section_addrs;
+ struct add_section_info asi;
struct cleanup *cleanup;
- char path[PATH_MAX];
- asection *sect;
- CORE_ADDR base_addr;
bfd *bfd;
- CORE_ADDR text_addr, data_addr, bss_addr, rodata_addr;
- int sect_count, sect_index;
-
- if (!find_kld_path(arg, path, sizeof(path))) {
- error("unable to locate kld");
- return;
- }
- if (!find_kld_address(arg, &base_addr)) {
- error("unable to find kld in kernel");
- return;
- }
-
- /* Open the kld and find the offsets of the various sections. */
+ /* Open the kld. */
bfd = bfd_openr(path, gnutarget);
- if (bfd == NULL) {
+ if (bfd == NULL)
error("\"%s\": can't open: %s", path,
bfd_errmsg(bfd_get_error()));
- return;
- }
cleanup = make_cleanup_bfd_close(bfd);
- if (!bfd_check_format(bfd, bfd_object)) {
- do_cleanups(cleanup);
+ if (!bfd_check_format(bfd, bfd_object))
error("\%s\": not an object file", path);
- return;
- }
- data_addr = bss_addr = rodata_addr = 0;
- sect = bfd_get_section_by_name (bfd, ".text");
- if (sect == NULL) {
- do_cleanups(cleanup);
+ /* Make sure we have a .text section. */
+ if (bfd_get_section_by_name (bfd, ".text") == NULL)
error("\"%s\": can't find text section", path);
- return;
- }
- text_addr = bfd_get_section_vma(bfd, sect);
- sect_count = 1;
-
- /* Save the offsets of relevant sections. */
- sect = bfd_get_section_by_name (bfd, ".data");
- if (sect != NULL) {
- data_addr = bfd_get_section_vma(bfd, sect);
- sect_count++;
+
+ if (add_kld_command)
+ printf_unfiltered("add symbol table from file \"%s\" at\n",
+ path);
+
+ /* Build a section table for symbol_file_add() from the bfd sections. */
+ asi.section_addrs = alloc_section_addr_info(bfd_count_sections(bfd));
+ cleanup = make_cleanup(xfree, asi.section_addrs);
+ asi.sect_index = 0;
+ asi.base_addr = base_addr;
+ asi.add_kld_command = add_kld_command;
+ bfd_map_over_sections(bfd, add_section, &asi);
+
+ if (from_tty && (!query("%s", "")))
+ error("Not confirmed.");
+
+ symbol_file_add(path, from_tty, asi.section_addrs, 0,
+ add_kld_command ? OBJF_USERLOADED : 0);
+
+ do_cleanups(cleanup);
+}
+
+void
+kgdb_add_kld_cmd (char *arg, int from_tty)
+{
+ char path[PATH_MAX];
+ CORE_ADDR base_addr;
+
+ /* Try to open the raw path to handle absolute paths first. */
+ snprintf(path, sizeof(path), "%s", arg);
+ if (!check_kld_path(path, sizeof(path))) {
+
+ /*
+ * If that didn't work, look in the various possible
+ * paths for the module.
+ */
+ if (!find_kld_path(arg, path, sizeof(path))) {
+ error("Unable to locate kld");
+ return;
+ }
}
- sect = bfd_get_section_by_name (bfd, ".bss");
- if (sect != NULL) {
- bss_addr = bfd_get_section_vma(bfd, sect);
- sect_count++;
+ if (!find_kld_address(arg, &base_addr)) {
+ error("Unable to find kld in kernel");
+ return;
}
- sect = bfd_get_section_by_name (bfd, ".rodata");
- if (sect != NULL) {
- rodata_addr = bfd_get_section_vma(bfd, sect);
- sect_count++;
+ load_kld(path, base_addr, from_tty, 1);
+
+ reinit_frame_cache();
+}
+
+static void
+dummy_cleanup (void *arg)
+{
+}
+
+static void
+load_single_kld (CORE_ADDR kld)
+{
+ CORE_ADDR address;
+ char kldpath[PATH_MAX];
+ char *path, *filename;
+ int errcode, path_ok;
+
+ /* Try to read this linker file's filename. */
+ target_read_string(read_pointer(kld + off_filename), &filename,
+ PATH_MAX, &errcode);
+ if (errcode)
+ error("Unable to read kld filename");
+
+ make_cleanup(xfree, filename);
+ path_ok = 0;
+
+ /* Try to read this linker file's pathname. */
+ if (off_pathname != 0) {
+ target_read_string(read_pointer(kld + off_pathname), &path,
+ PATH_MAX, &errcode);
+ if (errcode == 0) {
+ make_cleanup(xfree, path);
+
+ /*
+ * If we have a pathname, try to load the kld
+ * from there.
+ */
+ strlcpy(kldpath, path, sizeof(kldpath));
+ if (check_kld_path(kldpath, sizeof(kldpath)))
+ path_ok = 1;
+ }
}
- do_cleanups(cleanup);
+ /*
+ * If we didn't get a pathname from the linker file path, try
+ * to find this kld in the various search paths.
+ */
+ if (!path_ok && !find_kld_path(filename, kldpath, sizeof(kldpath)))
+ error("Unable to find kld file for \"%s\".", filename);
- printf_unfiltered("add symbol table from file \"%s\" at\n", path);
-
- /* Build a section table for symbol_file_add(). */
- section_addrs = alloc_section_addr_info(sect_count);
- cleanup = make_cleanup(xfree, section_addrs);
- sect_index = 0;
- add_section(section_addrs, &sect_index, ".text", base_addr + text_addr);
- if (data_addr != 0)
- add_section(section_addrs, &sect_index, ".data",
- base_addr + data_addr);
- if (bss_addr != 0)
- add_section(section_addrs, &sect_index, ".bss",
- base_addr + bss_addr);
- if (rodata_addr != 0)
- add_section(section_addrs, &sect_index, ".rodata",
- base_addr + rodata_addr);
-
- symbol_file_add(path, from_tty, section_addrs, 0, OBJF_USERLOADED);
+ /* Read this kld's base address and add its symbols. */
+ address = read_pointer(kld + off_address);
+ if (address == 0)
+ error("Invalid address for kld \"%s\"", filename);
- reinit_frame_cache();
+ load_kld(kldpath, address, 0, 0);
+
+ printf_unfiltered("Loaded symbols for kld \"%s\" from \"%s\"\n",
+ filename, path);
+}
+
+static int
+load_kld_stub (void *arg)
+{
+ CORE_ADDR kld = *(CORE_ADDR *)arg;
+
+ load_single_kld(kld);
+
+ return (1);
+}
+
+void
+kgdb_auto_load_klds (void)
+{
+ struct cleanup *cleanup;
+ CORE_ADDR kld, kernel;
+ int loaded_kld;
+
+ /* Compute offsets of relevant members in struct linker_file. */
+ off_address = kgdb_parse("&((struct linker_file *)0)->address");
+ off_filename = kgdb_parse("&((struct linker_file *)0)->filename");
+ off_pathname = kgdb_parse("&((struct linker_file *)0)->pathname");
+ off_next = kgdb_parse("&((struct linker_file *)0)->link.tqe_next");
+ if (off_address == 0 || off_filename == 0 || off_next == 0)
+ return;
+
+ /* Walk the list of linker files auto-loading klds. */
+ cleanup = make_cleanup(dummy_cleanup, NULL);
+ loaded_kld = 0;
+ kld = kgdb_parse("linker_files.tqh_first");
+ kernel = kgdb_parse("linker_kernel_file");
+ for (kld = kgdb_parse("linker_files.tqh_first"); kld != 0;
+ kld = read_pointer(kld + off_next)) {
+ /* Skip the main kernel file. */
+ if (kld == kernel)
+ continue;
+
+ if (catch_errors(load_kld_stub, &kld,
+ "Error while reading kld symbols:\n", RETURN_MASK_ALL))
+ loaded_kld = 1;
+ }
do_cleanups(cleanup);
+
+ if (loaded_kld)
+ reinit_frame_cache();
}
diff --git a/gnu/usr.bin/gdb/kgdb/trgt.c b/gnu/usr.bin/gdb/kgdb/trgt.c
index 502ef45..47e96bb 100644
--- a/gnu/usr.bin/gdb/kgdb/trgt.c
+++ b/gnu/usr.bin/gdb/kgdb/trgt.c
@@ -239,4 +239,5 @@ kgdb_target(void)
add_com ("add-kld", class_files, kgdb_add_kld_cmd,
"Usage: add-kld FILE\n\
Load the symbols from the kernel loadable module FILE.");
+ kgdb_auto_load_klds();
}
OpenPOWER on IntegriCloud