This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: coffread.c extension for DLLs without debugging symbols


Eli Zaretskii writes:
 > > From: "Raoul Gough" <RaoulGough@yahoo.co.uk>
 > > Date: Fri, 3 Jan 2003 19:39:31 -0000
 > > 
 > > This is my *first* gdb patch submission,
 > > so someone with more experience should probably take a good look at
 > > (e.g. is coffread.c the right place for this kind of code?).
 > 
 > Lesson number 1: post the diffs as plain text, not uuencoded or
 > otherwise encoded.  Some people, such as myself, don't have time to
 > open binary attachments, but do have time to read a patch that's in
 > plain text.
 > 
 > Also, please include "[RFA]" in the subject, so that we know you are
 > seeking an approval for your patch.
 > 
 > > Proposed ChangeLog entry, assuming the code is accepted:
 > > 
 > > 2003-01-03  Raoul Gough  <RaoulGough@yahoo.co.uk>
 > > 
 > >  * coffread.c: Support non-debug export symbols for win32 DLLs
 > 
 > This should mention every function where changes are made, preferably
 > with a description of a change in each one of them.
 > 
 > And thanks for working on this.


I am including the plain text of the last version of the patch.
I have noticed a few functions are using K&R style, please use ISO C.
Also the formatting for functions should be

int
foo (int par1, int par2)

so that grep ^foo will work.

(sorry, I have to ask) Do you have a copyright assignment with the FSF?

As far as the new code being triggered, could you do it based on the
existance of some particular section/data in the objfile?  I see that
you bail out of read_pe_exported_syms if there are no exports, could
something on the same flavour be done? (like using bfd_get_flavour, 
or bfd_get_section_by_name, etc)

About location of the code, add maybe a coff-pe-read.c? (ulgh) But
since it deals with reading symbols, I would think it more logical to
stay in some object/debug format related file rather than in a target
related file.

Elena


Index: coffread.c
===================================================================
RCS file: /cvs/src/src/gdb/coffread.c,v
retrieving revision 1.32
diff -c -p -r1.32 coffread.c
*** coffread.c	17 Dec 2002 00:39:07 -0000	1.32
--- coffread.c	3 Jan 2003 18:24:39 -0000
*************** static void read_one_sym (struct coff_sy
*** 179,184 ****
--- 179,186 ----
  			  struct internal_syment *, union internal_auxent *);
  
  static void coff_symtab_read (long, unsigned int, struct objfile *);
+ 
+ static void read_pe_exported_syms (struct objfile *objfile);
  
  /* We are called once per section from coff_symfile_read.  We
     need to examine each section we are passed, check to see
*************** coff_symtab_read (long symtab_offset, un
*** 1086,1091 ****
--- 1088,1109 ----
  	}
      }
  
+   if ((nsyms == 0) && (pe_file))
+     {
+       /* We've got no debugging symbols, but know how to read the list
+ 	 of exported symbols (on i386 at least). The code _might_ work
+ 	 on other architectures, but hasn't been tested. Check the
+ 	 target name to be on the safe side */
+ 
+       char const *target = bfd_get_target (objfile->obfd);
+ 
+       if ((strncmp (target, "pe-i386", 3) == 0)
+ 	  || (strncmp (target, "pei-i386", 4) == 0))
+ 	{
+ 	  read_pe_exported_syms (objfile);
+ 	}
+     }
+ 
    if (last_source_file)
      coff_end_symtab (objfile);
  
*************** read_one_sym (register struct coff_symbo
*** 1166,1171 ****
--- 1184,1488 ----
  	  break;
  	}
      }
+ }
+ 
+ /* Additional section information recorded just for the purposes of
+  * read_pe_exported_syms */
+ 
+ struct read_pe_section_data
+ {
+   CORE_ADDR vma_offset;               /* Offset to loaded address of section */
+   unsigned long rva_start;            /* Start offset within the pe */
+   unsigned long rva_end;              /* End offset within the pe */
+   enum minimal_symbol_type ms_type;   /* Type to assign symbols in section */
+ };
+ 
+ #define PE_SECTION_INDEX_TEXT     0
+ #define PE_SECTION_INDEX_DATA     1
+ #define PE_SECTION_INDEX_BSS      2
+ #define PE_SECTION_TABLE_SIZE     3
+ #define PE_SECTION_INDEX_INVALID -1
+ 
+ /* Get the index of the named section in our own array, which contains
+  * text, data and bss in that order. Return PE_SECTION_INDEX_INVALID
+  * if passed an unrecognised section name */
+ static int read_pe_section_index (const char *section_name)
+ {
+   if (strcmp (section_name, ".text") == 0)
+     {
+       return PE_SECTION_INDEX_TEXT;
+     }
+ 
+   else if (strcmp (section_name, ".data") == 0)
+     {
+       return PE_SECTION_INDEX_DATA;
+     }
+ 
+   else if (strcmp (section_name, ".bss") == 0)
+     {
+       return PE_SECTION_INDEX_BSS;
+     }
+ 
+   else
+     {
+       return PE_SECTION_INDEX_INVALID;
+     }
+ }
+ 
+ /* Record the virtual memory address of a section */
+ static void get_section_vmas (bfd *abfd, asection *sectp, void *context)
+ {
+   struct read_pe_section_data *sections = context;
+   int sectix = read_pe_section_index (sectp->name);
+ 
+   if (sectix != PE_SECTION_INDEX_INVALID)
+     {
+       /* Data within the section start at rva_start in the pe and at
+        * bfd_get_section_vma() within memory. Store the offset */
+ 
+       sections[sectix].vma_offset
+ 	= bfd_get_section_vma (abfd, sectp) - sections[sectix].rva_start;
+     }
+ }
+ 
+ /* Create a minimal symbol entry for an exported symbol */
+ static void
+ add_pe_exported_sym (char *sym_name,
+ 		     unsigned long func_rva,
+ 		     const struct read_pe_section_data *section_data,
+ 		     const char *dll_name,
+ 		     struct objfile *objfile)
+ {
+   /* Add the stored offset to get the loaded address of the symbol */
+   CORE_ADDR vma = func_rva + section_data->vma_offset;
+   char *qualified_name = 0;
+   int dll_name_len = strlen (dll_name);
+   int count;
+ 
+   /* Generate a (hopefully unique) qualified name using the first part
+    * of the dll name, e.g. KERNEL32!AddAtomA. This matches the style
+    * used by windbg from the "Microsoft Debugging Tools for Windows" */
+ 
+   qualified_name = xmalloc (dll_name_len + strlen (sym_name) + 2);
+ 
+   strncpy (qualified_name, dll_name, dll_name_len);
+   qualified_name[dll_name_len] = '!';
+   strcpy (qualified_name + dll_name_len + 1, sym_name);
+ 
+   record_minimal_symbol (qualified_name,
+ 			 vma,
+ 			 section_data->ms_type,
+ 			 objfile);
+ 
+   xfree (qualified_name);
+ 
+   /* Enter the plain name as well, which might not be unique */
+   record_minimal_symbol (sym_name,
+ 			 vma,
+ 			 section_data->ms_type,
+ 			 objfile);
+ }
+ 
+ /* Truncate a dll_name at the first dot character */
+ static void read_pe_truncate_name (char *dll_name)
+ {
+   while (*dll_name)
+     {
+       if ((*dll_name) == '.')
+ 	{
+ 	  *dll_name = '\0'; /* truncates and causes loop exit */
+ 	}
+ 
+       else
+ 	{
+ 	  ++dll_name;
+ 	}
+     }
+ }
+ 
+ /* Last-resort support for (non-debug) symbols exported from portable
+  * executables, used when there are no other recognized symbols. Code
+  * lifted (with modifications) from pe-dll.c from ld */
+ 
+ static unsigned int
+ pe_get16 (abfd, where)
+      bfd *abfd;
+      int where;
+ {
+   unsigned char b[2];
+ 
+   bfd_seek (abfd, (file_ptr) where, SEEK_SET);
+   bfd_bread (b, (bfd_size_type) 2, abfd);
+   return b[0] + (b[1] << 8);
+ }
+ 
+ static unsigned int
+ pe_get32 (abfd, where)
+      bfd *abfd;
+      int where;
+ {
+   unsigned char b[4];
+ 
+   bfd_seek (abfd, (file_ptr) where, SEEK_SET);
+   bfd_bread (b, (bfd_size_type) 4, abfd);
+   return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
+ }
+ 
+ static unsigned int
+ pe_as32 (ptr)
+      void *ptr;
+ {
+   unsigned char *b = ptr;
+ 
+   return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24);
+ }
+ 
+ /* Read the (non-debug) export symbol table from a portable
+  * executable.  originally from the ld function pe_implied_import_dll
+  * from pe-dll.c */
+ 
+ static void read_pe_exported_syms (struct objfile *objfile)
+ {
+   bfd *dll = objfile->obfd;
+   unsigned long pe_header_offset, opthdr_ofs, num_entries, i;
+   unsigned long export_rva, export_size, nsections, secptr, expptr;
+   unsigned long exp_funcbase;
+   unsigned char *expdata, *erva;
+   unsigned long name_rvas, ordinals, nexp, ordbase;
+   char *dll_name;
+ 
+   /* Array elements are for text, data and bss in that order
+      Initialization with start_rva > end_rva guarantees that
+      unused sections won't be matched */
+   struct read_pe_section_data section_data[PE_SECTION_TABLE_SIZE]
+     = { {0, 1, 0, mst_text},
+ 	{0, 1, 0, mst_data},
+ 	{0, 1, 0, mst_bss} };
+ 
+   struct cleanup *back_to = 0;
+ 
+   /* Get pe_header, optional header and numbers of export entries.  */
+   pe_header_offset = pe_get32 (dll, 0x3c);
+   opthdr_ofs = pe_header_offset + 4 + 20;
+   num_entries = pe_get32 (dll, opthdr_ofs + 92);
+ 
+   if (num_entries < 1) /* No exports.  */
+     {
+       return;
+     }
+ 
+   export_rva = pe_get32 (dll, opthdr_ofs + 96);
+   export_size = pe_get32 (dll, opthdr_ofs + 100);
+   nsections = pe_get16 (dll, pe_header_offset + 4 + 2);
+   secptr = (pe_header_offset + 4 + 20 +
+ 	    pe_get16 (dll, pe_header_offset + 4 + 16));
+   expptr = 0;
+ 
+   /* Get the rva and size of the export section.  */ 
+   for (i = 0; i < nsections; i++)
+     {
+       char sname[8];
+       unsigned long secptr1 = secptr + 40 * i;
+       unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
+       unsigned long vsize = pe_get32 (dll, secptr1 + 16);
+       unsigned long fptr = pe_get32 (dll, secptr1 + 20);
+ 
+       bfd_seek (dll, (file_ptr) secptr1, SEEK_SET);
+       bfd_bread (sname, (bfd_size_type) 8, dll);
+ 
+       if (vaddr <= export_rva && vaddr + vsize > export_rva)
+ 	{
+ 	  expptr = fptr + (export_rva - vaddr);
+ 	  if (export_rva + export_size > vaddr + vsize)
+ 	    export_size = vsize - (export_rva - vaddr);
+ 	  break;
+ 	}
+     }
+ 
+   if (export_size == 0)
+     {
+       /* Empty export table */
+       return;
+     }
+ 
+   /* Scan sections and store the base and size of the relevant sections */
+   for (i = 0; i < nsections; i++)
+     {
+       unsigned long secptr1 = secptr + 40 * i;
+       unsigned long vsize = pe_get32 (dll, secptr1 + 8);
+       unsigned long vaddr = pe_get32 (dll, secptr1 + 12);
+       unsigned long flags = pe_get32 (dll, secptr1 + 36);
+       char sec_name[9];
+       int sectix;
+ 
+       sec_name[8] = '\0';
+       bfd_seek (dll, (file_ptr) secptr1 + 0, SEEK_SET);
+       bfd_bread (sec_name, (bfd_size_type) 8, dll);
+ 
+       sectix = read_pe_section_index (sec_name);
+ 
+       if (sectix != PE_SECTION_INDEX_INVALID)
+ 	{
+ 	  section_data[sectix].rva_start = vaddr;
+ 	  section_data[sectix].rva_end = vaddr + vsize;
+ 	}
+     }
+ 
+   expdata = (unsigned char *) xmalloc (export_size);
+   back_to = make_cleanup (xfree, expdata);
+ 
+   bfd_seek (dll, (file_ptr) expptr, SEEK_SET);
+   bfd_bread (expdata, (bfd_size_type) export_size, dll);
+   erva = expdata - export_rva;
+ 
+   nexp = pe_as32 (expdata + 24);
+   name_rvas = pe_as32 (expdata + 32);
+   ordinals = pe_as32 (expdata + 36);
+   ordbase = pe_as32 (expdata + 16);
+   exp_funcbase = pe_as32 (expdata + 28);
+ 
+   /* Use internal dll name instead of full pathname */
+   dll_name = pe_as32 (expdata + 12) + erva;
+ 
+   bfd_map_over_sections (dll, get_section_vmas, section_data);
+ 
+   printf_filtered ("Minimal symbols from %s...", dll_name);
+   wrap_here ("");
+ 
+   /* Truncate name at first dot to avoid problems with the qualified
+      names we generate. Should maybe also convert to all lower case
+      for convenience on Windows */
+   read_pe_truncate_name (dll_name);
+ 
+   /* Iterate through the list of symbols.  */
+   for (i = 0; i < nexp; i++)
+     {
+       /* Pointer to the names vector.  */
+       unsigned long name_rva = pe_as32 (erva + name_rvas + i * 4);
+ 
+       /* Pointer to the function address vector.  */ 
+       unsigned long func_rva = pe_as32 (erva + exp_funcbase + i * 4);
+ 
+       /* Find this symbol's section in our own array */
+       int sectix = 0;
+ 
+       for (sectix = 0; sectix < PE_SECTION_TABLE_SIZE; ++sectix)
+ 	{
+ 	  if ((func_rva >= section_data[sectix].rva_start)
+ 	      && (func_rva < section_data[sectix].rva_end))
+ 	    {
+ 	      add_pe_exported_sym (erva + name_rva,
+ 				   func_rva,
+ 				   section_data + sectix,
+ 				   dll_name,
+ 				   objfile);
+ 	      break;
+ 	    }
+ 	}
+     }
+ 
+   /* discard expdata */
+   do_cleanups (back_to);
  }
  
  /* Support for string table handling */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]