From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 1756 invoked by alias); 6 Jan 2003 17:10:13 -0000 Mailing-List: contact gdb-patches-help@sources.redhat.com; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sources.redhat.com Received: (qmail 1098 invoked from network); 6 Jan 2003 17:07:16 -0000 Received: from unknown (HELO mx1.redhat.com) (66.187.233.31) by 209.249.29.67 with SMTP; 6 Jan 2003 17:07:15 -0000 Received: from int-mx1.corp.redhat.com (int-mx1.corp.redhat.com [172.16.52.254]) by mx1.redhat.com (8.11.6/8.11.6) with ESMTP id h06GdRB21976 for ; Mon, 6 Jan 2003 11:39:27 -0500 Received: from pobox.corp.redhat.com (pobox.corp.redhat.com [172.16.52.156]) by int-mx1.corp.redhat.com (8.11.6/8.11.6) with ESMTP id h06H6xa06706 for ; Mon, 6 Jan 2003 12:06:59 -0500 Received: from localhost.redhat.com (romulus-int.sfbay.redhat.com [172.16.27.46]) by pobox.corp.redhat.com (8.11.6/8.11.6) with ESMTP id h06H6wn09223 for ; Mon, 6 Jan 2003 12:06:58 -0500 Received: by localhost.redhat.com (Postfix, from userid 469) id C7BE5FF79; Mon, 6 Jan 2003 12:11:20 -0500 (EST) From: Elena Zannoni MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <15897.47288.570835.988631@localhost.redhat.com> Date: Mon, 06 Jan 2003 17:10:00 -0000 To: RaoulGough@yahoo.co.uk Cc: Eli Zaretskii , gdb-patches@sources.redhat.com Subject: Re: coffread.c extension for DLLs without debugging symbols In-Reply-To: <2110-Sat04Jan2003130101+0200-eliz@is.elta.co.il> References: <2110-Sat04Jan2003130101+0200-eliz@is.elta.co.il> X-SW-Source: 2003-01/txt/msg00213.txt.bz2 Eli Zaretskii writes: > > From: "Raoul Gough" > > 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 > > > > * 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 */