From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11005 invoked by alias); 18 Dec 2008 17:19:12 -0000 Received: (qmail 10840 invoked by uid 22791); 18 Dec 2008 17:19:09 -0000 X-SWARE-Spam-Status: No, hits=-0.8 required=5.0 tests=AWL,BAYES_50 X-Spam-Check-By: sourceware.org Received: from igw1.br.ibm.com (HELO igw1.br.ibm.com) (32.104.18.24) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 18 Dec 2008 17:18:25 +0000 Received: from d24relay01.br.ibm.com (unknown [9.8.31.16]) by igw1.br.ibm.com (Postfix) with ESMTP id 7F6BD32C005 for ; Thu, 18 Dec 2008 15:13:54 -0200 (BRDT) Received: from d24av01.br.ibm.com (d24av01.br.ibm.com [9.18.232.46]) by d24relay01.br.ibm.com (8.13.8/8.13.8/NCO v9.1) with ESMTP id mBIIHrEx3301452 for ; Thu, 18 Dec 2008 15:17:53 -0300 Received: from d24av01.br.ibm.com (loopback [127.0.0.1]) by d24av01.br.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id mBIHIJeM024864 for ; Thu, 18 Dec 2008 15:18:19 -0200 Received: from [9.18.238.245] ([9.18.238.245]) by d24av01.br.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id mBIHIJTo024859 for ; Thu, 18 Dec 2008 15:18:19 -0200 Subject: RFC: "info proc map" for corefiles From: =?ISO-8859-1?Q?S=E9rgio?= Durigan =?ISO-8859-1?Q?J=FAnior?= To: gdb-patches@sourceware.org Content-Type: multipart/mixed; boundary="=-lGNkQ/XlzS47sa4dzG+H" Date: Thu, 18 Dec 2008 17:19:00 -0000 Message-Id: <1229620702.6602.12.camel@miki> Mime-Version: 1.0 X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-12/txt/msg00322.txt.bz2 --=-lGNkQ/XlzS47sa4dzG+H Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 8bit Content-length: 2741 Hi guys and girls, This little patch o' mine implements the command "info proc map" for corefiles in GDB. Initially, this feature is only provided for live process being debugged. We decided that it would be good to have such functionality for corefiles as well, since this information (the memory mappings) is available inside them. This was something that Thiago and I have discussed for some time, and it took a little while for me to figure out how things worked in this part of the code. I really don't know if this is the right way to implement this, so I'd be glad if you could take a look and give your opinions. It's not architecture-dependend so this time you'll be able to test without problems. Comments and reviews are welcome, as always. This is a little example of this feature working: sergio@miki ~/work/gdb/build-32/gdb $ ./gdb /tmp/teste core.13754 GNU gdb (GDB) 6.8.50.20081218-cvs ... (gdb) info proc map exe = '/tmp/teste' Mapped address spaces: Start Addr End Addr Size objfile 0x8048000 0x8049000 0x1000 /tmp/teste 0x8049000 0x804a000 0x1000 /tmp/teste 0x804a000 0x804b000 0x1000 /tmp/teste 0xb7e93000 0xb7e94000 0x1000 0xb7e94000 0xb7fbe000 0x12a000 0xb7fbe000 0xb7fc0000 0x2000 0xb7fc0000 0xb7fc1000 0x1000 0xb7fc1000 0xb7fc5000 0x4000 0xb7fe4000 0xb7ffe000 0x1a000 /lib/ld-linux.so.2 0xb7ffe000 0xb7fff000 0x1000 /lib/ld-linux.so.2 0xb7fff000 0xb8000000 0x1000 /lib/ld-linux.so.2 0xbffeb000 0xc0000000 0x15000 0xffffe000 0xfffff000 0x1000 system-supplied DSO at 0xffffe000 The corefile used here (core.13754) was generated using the "gcore" command inside GDB. Regards, -- Sérgio Durigan Júnior Linux on Power Toolchain - Software Engineer Linux Technology Center - LTC IBM Brazil 2008-12-18 Sergio Durigan Junior * corelow.c: Including extra header files in order to be able to use proper data structures for the "info proc map". (print_proc_map_iter): New function. (core_print_proc_map): Likewise. (init_core_ops): Initializing to_print_proc_map method for corefile target_ops. * linux-nat.c (linux_nat_print_proc_map): New function. (linux_nat_info_proc_cmd): Handling the "info proc map" for corefiles. (linux_nat_add_target): Initializing to_print_proc_map method for Linux target_ops. * target.c (update_current_target): Inherit to_print_proc_map. (dummy_print_proc_map): New function. (init_dummy_target): Initializing to_print_proc_map method for dummy target_ops. * target.h (struct target_ops): Adding method to_print_proc_map. (target_print_proc_map): New define. --=-lGNkQ/XlzS47sa4dzG+H Content-Disposition: attachment; filename=corefile.patch Content-Type: text/x-patch; name=corefile.patch; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-length: 14933 diff --git a/gdb/corelow.c b/gdb/corelow.c index 35c998c..c9b22e5 100644 --- a/gdb/corelow.c +++ b/gdb/corelow.c @@ -33,6 +33,8 @@ #include "symtab.h" #include "command.h" #include "bfd.h" +#include "elf-bfd.h" +#include "elf/internal.h" #include "target.h" #include "gdbcore.h" #include "gdbthread.h" @@ -45,6 +47,7 @@ #include "exceptions.h" #include "solib.h" #include "filenames.h" +#include "objfiles.h" #ifndef O_LARGEFILE @@ -692,6 +695,161 @@ core_pid_to_str (ptid_t ptid) return buf; } +/* Helper function for 'core_print_proc_map'. It is used to iterate + over the corefile's sections and print proper information about + memory-mappings. + + BFD is the bfd used to get the sections. + SECT is the current section being "visited". + OBJ is not used. */ + +static void +print_proc_map_iter (bfd *bfd, asection *sect, void *obj) +{ + /* We're interested in matching sections' names beginning with + "load", because they are the sections containing information + about the process' memory regions. */ + static const char *proc_map_match = "load"; + int proc_map_match_size = strlen (proc_map_match); + /* A little flag to indicate whether we have found something. */ + int found = 0; + /* The section's size. */ + bfd_size_type secsize; + /* We have to know the bitness of this architecture. */ + struct gdbarch *gdbarch = gdbarch_from_bfd (bfd); + int bitness = gdbarch_addr_bit (gdbarch); + /* We'll use these later. They are basically used for iterating + over every objfile in the system so that we can find needed + information about the memory region being examinated. */ + struct obj_section *s = NULL; + struct objfile *objfile = NULL; + /* Fields to be printed for the proc map. */ + unsigned long start = 0, end = 0; + unsigned int size = 0; + char *filename = NULL; + + if (strncmp (proc_map_match, sect->name, proc_map_match_size) != 0) + /* This section is not useful. */ + return; + + /* Unfortunately, some sections in the corefile don't have any + content inside. This is bad because we need to print, among + other things, its final address in the memory (which is + impossible to know if we don't have a size). That's why we + first need to check if the section's got anything inside it. */ + secsize = bfd_section_size (bfd, sect); + + if (secsize == 0) + { + /* Ok, the section if empty. In this case, we must look inside + ELF's Program Header, because (at least) there we have + information about the section's size. That's what we're doing + here. */ + Elf_Internal_Phdr *p = elf_tdata (bfd)->phdr; + if (p != NULL) + { + int i; + unsigned int n = elf_elfheader (bfd)->e_phnum; + for (i = 0; i < n; i++, p++) + /* For each entry in the Program Header, we have to + check if the section's initial address is equal to + the entry's virtual address. If it is, then we + have just found the section's entry in the Program + Header, and can use the entry's information to + complete missing data from the section. */ + if (sect->vma == p->p_vaddr) + { + found = 1; + break; + } + if (found) + secsize = p->p_memsz; + } + } + + size = secsize; + start = sect->vma; + end = (unsigned long) (sect->vma + size); + + /* Now begins a new part of the work. We still don't have complete + information about the memory region. For example, we still need + to know the filename which is represented by the region. Such + info can be gathered from the objfile's data structure, and for + that we must iterate over all the objsections and check if the + objsection's initial address is inside the section we have at hand. + If it is, then we can use this specific objsection to obtain the + missing data. */ + found = 0; + ALL_OBJSECTIONS (objfile, s) + if (obj_section_addr (s) >= start + && obj_section_addr (s) <= end) + { + found = 1; + goto out; + } + +out: + if (found) + filename = s->objfile->name; + + if (bitness == 32) + { + printf_filtered ("\t%#10lx %#10lx %#10x %7s\n", + start, + end, + (int) size, + (filename != NULL) ? filename : ""); + } + else + { + printf_filtered (" %#18lx %#18lx %#10x %7s\n", + start, + end, + (int) size, + (filename != NULL) ? filename : ""); + } +} + +/* Implements the "info proc map" command when the user has provided + a corefile. In this case, the PID argument will not be used. */ + +static void +core_print_proc_map (long long pid) +{ + struct gdbarch *gdbarch; + const char *exe; + int bitness; + + gdb_assert (core_bfd != NULL); + + gdbarch = gdbarch_from_bfd (core_bfd); + bitness = gdbarch_addr_bit (gdbarch); + + /* Getting the executable name. */ + exe = bfd_core_file_failing_command (core_bfd); + + printf_filtered (_("exe = '%s'\n"), exe); + printf_filtered (_("Mapped address spaces:\n\n")); + if (bitness == 32) + { + printf_filtered ("\t%10s %10s %10s %7s\n", + "Start Addr", + " End Addr", + " Size", "objfile"); + } + else + { + printf_filtered (" %18s %18s %10s %7s\n", + "Start Addr", + " End Addr", + " Size", "objfile"); + } + + bfd_map_over_sections (core_bfd, + print_proc_map_iter, + NULL); +} + /* Fill in core_ops with its defined operations and properties. */ static void @@ -714,6 +872,7 @@ init_core_ops (void) core_ops.to_create_inferior = find_default_create_inferior; core_ops.to_thread_alive = core_file_thread_alive; core_ops.to_read_description = core_read_description; + core_ops.to_print_proc_map = core_print_proc_map; core_ops.to_pid_to_str = core_pid_to_str; core_ops.to_stratum = core_stratum; core_ops.to_has_memory = 1; diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index a2cb39d..2e3fcbc 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -3586,6 +3586,75 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size) return note_data; } +/* Implement the "info proc map" command when the process + being debugged is running (i.e., a corefile is not being + used. */ +static void +linux_nat_print_proc_map (long long pid) +{ + char fname1[MAXPATHLEN]; + FILE *procfile; + + sprintf (fname1, "/proc/%lld/maps", pid); + if ((procfile = fopen (fname1, "r")) != NULL) + { + long long addr, endaddr, size, offset, inode; + char permissions[8], device[8], filename[MAXPATHLEN]; + struct cleanup *cleanup; + + cleanup = make_cleanup_fclose (procfile); + printf_filtered (_("Mapped address spaces:\n\n")); + if (gdbarch_addr_bit (current_gdbarch) == 32) + { + printf_filtered ("\t%10s %10s %10s %10s %7s\n", + "Start Addr", + " End Addr", + " Size", " Offset", "objfile"); + } + else + { + printf_filtered (" %18s %18s %10s %10s %7s\n", + "Start Addr", + " End Addr", + " Size", " Offset", "objfile"); + } + + while (read_mapping (procfile, &addr, &endaddr, &permissions[0], + &offset, &device[0], &inode, &filename[0])) + { + size = endaddr - addr; + + /* FIXME: carlton/2003-08-27: Maybe the printf_filtered + calls here (and possibly above) should be abstracted + out into their own functions? Andrew suggests using + a generic local_address_string instead to print out + the addresses; that makes sense to me, too. */ + + if (gdbarch_addr_bit (current_gdbarch) == 32) + { + printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n", + (unsigned long) addr, /* FIXME: pr_addr */ + (unsigned long) endaddr, + (int) size, + (unsigned int) offset, + filename[0] ? filename : ""); + } + else + { + printf_filtered (" %#18lx %#18lx %#10x %#10x %7s\n", + (unsigned long) addr, /* FIXME: pr_addr */ + (unsigned long) endaddr, + (int) size, + (unsigned int) offset, + filename[0] ? filename : ""); + } + } + do_cleanups (cleanup); + } + else + warning (_("unable to open /proc file '%s'"), fname1); +} + /* Implement the "info proc" command. */ static void @@ -3621,6 +3690,12 @@ linux_nat_info_proc_cmd (char *args, int from_tty) else if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0) { mappings_f = 1; + if (current_target.to_stratum == core_stratum) + { + cmdline_f = 0; + cwd_f = 0; + exe_f = 0; + } } else if (strcmp (argv[0], "status") == 0) { @@ -3652,14 +3727,17 @@ linux_nat_info_proc_cmd (char *args, int from_tty) } argv++; } - if (pid == 0) - error (_("No current process: you must name one.")); + if (current_target.to_stratum != core_stratum) + { + if (pid == 0) + error (_("No current process: you must name one.")); - sprintf (fname1, "/proc/%lld", pid); - if (stat (fname1, &dummy) != 0) - error (_("No /proc directory: '%s'"), fname1); + sprintf (fname1, "/proc/%lld", pid); + if (stat (fname1, &dummy) != 0) + error (_("No /proc directory: '%s'"), fname1); - printf_filtered (_("process %lld\n"), pid); + printf_filtered (_("process %lld\n"), pid); + } if (cmdline_f || all) { sprintf (fname1, "/proc/%lld/cmdline", pid); @@ -3693,65 +3771,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty) } if (mappings_f || all) { - sprintf (fname1, "/proc/%lld/maps", pid); - if ((procfile = fopen (fname1, "r")) != NULL) - { - long long addr, endaddr, size, offset, inode; - char permissions[8], device[8], filename[MAXPATHLEN]; - struct cleanup *cleanup; - - cleanup = make_cleanup_fclose (procfile); - printf_filtered (_("Mapped address spaces:\n\n")); - if (gdbarch_addr_bit (current_gdbarch) == 32) - { - printf_filtered ("\t%10s %10s %10s %10s %7s\n", - "Start Addr", - " End Addr", - " Size", " Offset", "objfile"); - } - else - { - printf_filtered (" %18s %18s %10s %10s %7s\n", - "Start Addr", - " End Addr", - " Size", " Offset", "objfile"); - } - - while (read_mapping (procfile, &addr, &endaddr, &permissions[0], - &offset, &device[0], &inode, &filename[0])) - { - size = endaddr - addr; - - /* FIXME: carlton/2003-08-27: Maybe the printf_filtered - calls here (and possibly above) should be abstracted - out into their own functions? Andrew suggests using - a generic local_address_string instead to print out - the addresses; that makes sense to me, too. */ - - if (gdbarch_addr_bit (current_gdbarch) == 32) - { - printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n", - (unsigned long) addr, /* FIXME: pr_addr */ - (unsigned long) endaddr, - (int) size, - (unsigned int) offset, - filename[0] ? filename : ""); - } - else - { - printf_filtered (" %#18lx %#18lx %#10x %#10x %7s\n", - (unsigned long) addr, /* FIXME: pr_addr */ - (unsigned long) endaddr, - (int) size, - (unsigned int) offset, - filename[0] ? filename : ""); - } - } - - do_cleanups (cleanup); - } - else - warning (_("unable to open /proc file '%s'"), fname1); + target_print_proc_map (pid); } if (status_f || all) { @@ -4620,6 +4640,7 @@ linux_nat_add_target (struct target_ops *t) t->to_async_mask = linux_nat_async_mask; t->to_terminal_inferior = linux_nat_terminal_inferior; t->to_terminal_ours = linux_nat_terminal_ours; + t->to_print_proc_map = linux_nat_print_proc_map; /* Methods for non-stop support. */ t->to_stop = linux_nat_stop; diff --git a/gdb/target.c b/gdb/target.c index c16b55c..ad1a611 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -484,6 +484,7 @@ update_current_target (void) INHERIT (to_async_mask, t); INHERIT (to_find_memory_regions, t); INHERIT (to_make_corefile_notes, t); + INHERIT (to_print_proc_map, t); INHERIT (to_get_thread_local_address, t); INHERIT (to_can_execute_reverse, t); /* Do not inherit to_read_description. */ @@ -2501,6 +2502,13 @@ static char * dummy_make_corefile_notes (bfd *ignore1, int *ignore2) return NULL; } +/* Error-catcher for target_print_proc_map. */ +static void +dummy_print_proc_map (long long pid) +{ + error (_("No target.")); +} + /* Set up the handful of non-empty slots needed by the dummy target vector. */ @@ -2521,6 +2529,7 @@ init_dummy_target (void) dummy_target.to_stratum = dummy_stratum; dummy_target.to_find_memory_regions = dummy_find_memory_regions; dummy_target.to_make_corefile_notes = dummy_make_corefile_notes; + dummy_target.to_print_proc_map = dummy_print_proc_map; dummy_target.to_xfer_partial = default_xfer_partial; dummy_target.to_magic = OPS_MAGIC; } diff --git a/gdb/target.h b/gdb/target.h index 2722945..c763da5 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -428,6 +428,7 @@ struct target_ops void *), void *); char * (*to_make_corefile_notes) (bfd *, int *); + void (*to_print_proc_map) (long long); /* Return the thread-local address at OFFSET in the thread-local storage for the thread PTID and the shared library @@ -1057,6 +1058,12 @@ extern char *normal_pid_to_str (ptid_t ptid); #define target_make_corefile_notes(BFD, SIZE_P) \ (current_target.to_make_corefile_notes) (BFD, SIZE_P) +/* Print the memory-mapped information from the inferior + (or the corefile). */ + +#define target_print_proc_map(pid) \ + (current_target.to_print_proc_map) (pid) + /* Thread-local values. */ #define target_get_thread_local_address \ (current_target.to_get_thread_local_address) --=-lGNkQ/XlzS47sa4dzG+H--