From e4486bdf9ffd0c61863eee6ccb2e5ef5621d1417 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 23 Jun 1997 00:08:54 +0000 Subject: [PATCH] Another windres snapshot. Can now read the COFF resources directory, although it doesn't yet parse out the binary format. --- binutils/.Sanitize | 1 + binutils/ChangeLog | 1 + binutils/Makefile.in | 8 +- binutils/rescoff.c | 342 +++++++++++++++++++++++++++++++++++++++++++++++++++ binutils/resrc.c | 6 +- binutils/windres.c | 28 +---- 6 files changed, 356 insertions(+), 30 deletions(-) create mode 100644 binutils/rescoff.c diff --git a/binutils/.Sanitize b/binutils/.Sanitize index 5bae795..e66607a 100644 --- a/binutils/.Sanitize +++ b/binutils/.Sanitize @@ -84,6 +84,7 @@ ranlib.1 ranlib.sh rclex.l rcparse.y +rescoff.c resrc.c rdcoff.c rddbg.c diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 2a685dc..3c8f28b 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -6,6 +6,7 @@ Sun Jun 22 17:29:41 1997 Ian Lance Taylor * resrc.c: New file. * rcparse.y: New file. * rclex.l: New file. + * rescoff.c: New file. * configure.in: Define and substitute BUILD_WINDRES. * configure: Rebuild. * Makefile.in: Rebuild dependencies. diff --git a/binutils/Makefile.in b/binutils/Makefile.in index 65d25f7..3a0eb41 100644 --- a/binutils/Makefile.in +++ b/binutils/Makefile.in @@ -138,7 +138,7 @@ CFILES = addr2line.c ar.c arsup.c bucomm.c coffdump.c coffgrok.c debug.c \ maybe-strip.c nlmconv.c nm.c not-ranlib.c not-strip.c \ objcopy.c objdump.c prdbg.c rdcoff.c rddbg.c size.c srconv.c \ stabs.c strings.c sysdump.c version.c wrstabs.c \ - windres.c resrc.c + windres.c resrc.c rescoff.c GENERATED_CFILES = \ underscore.c arparse.c arlex.c sysroff.c sysinfo.c syslex.c \ @@ -409,7 +409,7 @@ nlmconv.o: nlmconv.c $(INCDIR)/coff/sym.h $(INCDIR)/coff/ecoff.h $(NLMCONV_PROG): nlmconv.o nlmheader.o $(ADDL_DEPS) $(HLDENV) $(CC) $(HLDFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ nlmconv.o nlmheader.o $(ADDL_LIBS) $(EXTRALIBS) -WINDRES_OBJS = windres.o resrc.o rcparse.o rclex.o +WINDRES_OBJS = windres.o resrc.o rescoff.o rcparse.o rclex.o $(WINDRES_PROG): $(WINDRES_OBJS) $(ADDL_DEPS) $(HLDENV) $(CC) $(HLDFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ $(WINDRES_OBJS) $(ADDL_LIBS) $(EXTRALIBS) @@ -766,6 +766,10 @@ windres.o: windres.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \ resrc.o: resrc.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \ bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \ windres.h +rescoff.o: rescoff.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \ + bucomm.h config.h $(INCDIR)/fopen-same.h $(INCDIR)/libiberty.h \ + windres.h $(INCDIR)/coff/internal.h $(BFDDIR)/libcoff.h \ + $(INCDIR)/bfdlink.h underscore.o: underscore.c arparse.o: arparse.c ../bfd/bfd.h $(INCDIR)/ansidecl.h \ bucomm.h config.h $(INCDIR)/fopen-same.h arsup.h diff --git a/binutils/rescoff.c b/binutils/rescoff.c new file mode 100644 index 0000000..65df9bf --- /dev/null +++ b/binutils/rescoff.c @@ -0,0 +1,342 @@ +/* resrc.c -- read and write Windows rc files. + Copyright 1997 Free Software Foundation, Inc. + Written by Ian Lance Taylor, Cygnus Support. + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + +/* This file contains function that read and write Windows resources + in COFF files. */ + +#include "bfd.h" +#include "bucomm.h" +#include "libiberty.h" +#include "windres.h" + +/* In order to use the address of a resource data entry, we need to + get the image base of the file. Right now we extract it from + internal BFD information. FIXME. */ + +#include "coff/internal.h" +#include "libcoff.h" + +/* Information we extract from the file. */ + +struct coff_file_info +{ + /* File name. */ + const char *filename; + /* Data read from the file. */ + const bfd_byte *data; + /* End of data read from file. */ + const bfd_byte *data_end; + /* Address of the resource section minus the image base of the file. */ + bfd_vma secaddr; + /* Non-zero if the file is big endian. */ + int big_endian; +}; + +/* A resource directory table in a COFF file. */ + +struct extern_res_directory +{ + /* Characteristics. */ + bfd_byte characteristics[4]; + /* Time stamp. */ + bfd_byte time[4]; + /* Major version number. */ + bfd_byte major[2]; + /* Minor version number. */ + bfd_byte minor[2]; + /* Number of named directory entries. */ + bfd_byte name_count[2]; + /* Number of directory entries with IDs. */ + bfd_byte id_count[2]; +}; + +/* A resource directory entry in a COFF file. */ + +struct extern_res_entry +{ + /* Name or ID. */ + bfd_byte name[4]; + /* Address of resource entry or subdirectory. */ + bfd_byte rva[4]; +}; + +/* A resource data entry in a COFF file. */ + +struct extern_res_data +{ + /* Address of resource data. This is apparently a file relative + address, rather than a section offset. */ + bfd_byte rva[4]; + /* Size of resource data. */ + bfd_byte size[4]; + /* Code page. */ + bfd_byte codepage[4]; + /* Reserved. */ + bfd_byte reserved[4]; +}; + +/* Macros to swap in values. */ + +#define get_16(fi, s) ((fi)->big_endian ? bfd_getb16 (s) : bfd_getl16 (s)) +#define get_32(fi, s) ((fi)->big_endian ? bfd_getb32 (s) : bfd_getl32 (s)) + +/* Local functions. */ + +static void overrun PARAMS ((const struct coff_file_info *, const char *)); +static struct res_directory *read_coff_res_dir + PARAMS ((const bfd_byte *, const struct coff_file_info *)); +static struct res_resource *read_coff_data_entry + PARAMS ((const bfd_byte *, const struct coff_file_info *)); + +/* Read the resources in a COFF file. */ + +struct res_directory * +read_coff_rsrc (filename, target) + const char *filename; + const char *target; +{ + bfd *abfd; + char **matching; + asection *sec; + bfd_size_type size; + bfd_byte *data; + struct coff_file_info finfo; + + abfd = bfd_openr (filename, target); + if (abfd == NULL) + bfd_fatal (filename); + + if (! bfd_check_format_matches (abfd, bfd_object, &matching)) + { + bfd_nonfatal (bfd_get_filename (abfd)); + if (bfd_get_error () == bfd_error_file_ambiguously_recognized) + list_matching_formats (matching); + xexit (1); + } + + sec = bfd_get_section_by_name (abfd, ".rsrc"); + if (sec == NULL) + { + fprintf (stderr, "%s: %s: no resource section\n", program_name, + filename); + xexit (1); + } + + size = bfd_section_size (abfd, sec); + data = (bfd_byte *) xmalloc (size); + + if (! bfd_get_section_contents (abfd, sec, data, 0, size)) + bfd_fatal ("can't read resource section"); + + finfo.filename = filename; + finfo.data = data; + finfo.data_end = data + size; + finfo.secaddr = (bfd_get_section_vma (abfd, sec) + - pe_data (abfd)->pe_opthdr.ImageBase); + finfo.big_endian = bfd_big_endian (abfd); + + bfd_close (abfd); + + /* Now just read in the top level resource directory. Note that we + don't free data, since we create resource entries that point into + it. If we ever want to free up the resource information we read, + this will have to be cleaned up. */ + + return read_coff_res_dir (data, &finfo); +} + +/* Give an error if we are out of bounds. */ + +static void +overrun (finfo, msg) + const struct coff_file_info *finfo; + const char *msg; +{ + fatal ("%s: %s: address out of bounds", finfo->filename, msg); +} + +/* Read a resource directory. */ + +static struct res_directory * +read_coff_res_dir (data, finfo) + const bfd_byte *data; + const struct coff_file_info *finfo; +{ + const struct extern_res_directory *erd; + struct res_directory *rd; + int name_count, id_count, i; + struct res_entry **pp; + const struct extern_res_entry *ere; + + if (finfo->data_end - data < sizeof (struct extern_res_directory)) + overrun (finfo, "directory"); + + erd = (const struct extern_res_directory *) data; + + rd = (struct res_directory *) xmalloc (sizeof *rd); + rd->characteristics = get_32 (finfo, erd->characteristics); + rd->time = get_32 (finfo, erd->time); + rd->major = get_16 (finfo, erd->major); + rd->minor = get_16 (finfo, erd->minor); + rd->entries = NULL; + + name_count = get_16 (finfo, erd->name_count); + id_count = get_16 (finfo, erd->id_count); + + pp = &rd->entries; + + /* The resource directory entries immediately follow the directory + table. */ + ere = (const struct extern_res_entry *) (erd + 1); + + for (i = 0; i < name_count; i++, ere++) + { + unsigned long name, rva; + struct res_entry *re; + const bfd_byte *ers; + int length, j; + + if ((const bfd_byte *) ere >= finfo->data_end) + overrun (finfo, "named directory entry"); + + name = get_32 (finfo, ere->name); + rva = get_32 (finfo, ere->rva); + + /* For some reason the high bit in NAME is set. */ + name &=~ 0x80000000; + + if (name > finfo->data_end - finfo->data) + overrun (finfo, "directory entry name"); + + ers = finfo->data + name; + + re = (struct res_entry *) xmalloc (sizeof *re); + re->next = NULL; + re->id.named = 1; + length = get_16 (finfo, ers); + re->id.u.n.length = length; + re->id.u.n.name = ((unsigned short *) + xmalloc (length * sizeof (unsigned short))); + for (j = 0; j < length; j++) + re->id.u.n.name[j] = get_16 (finfo, ers + j * 2 + 2); + + if ((rva & 0x80000000) != 0) + { + rva &=~ 0x80000000; + if (rva >= finfo->data_end - finfo->data) + overrun (finfo, "named subdirectory"); + re->subdir = 1; + re->u.dir = read_coff_res_dir (finfo->data + rva, finfo); + } + else + { + if (rva >= finfo->data_end - finfo->data) + overrun (finfo, "named resource"); + re->subdir = 0; + re->u.res = read_coff_data_entry (finfo->data + rva, finfo); + } + + *pp = re; + pp = &re->next; + } + + for (i = 0; i < id_count; i++, ere++) + { + unsigned long name, rva; + struct res_entry *re; + + if ((const bfd_byte *) ere >= finfo->data_end) + overrun (finfo, "ID directory entry"); + + name = get_32 (finfo, ere->name); + rva = get_32 (finfo, ere->rva); + + re = (struct res_entry *) xmalloc (sizeof *re); + re->next = NULL; + re->id.named = 0; + re->id.u.id = name; + + if ((rva & 0x80000000) != 0) + { + rva &=~ 0x80000000; + if (rva >= finfo->data_end - finfo->data) + overrun (finfo, "ID subdirectory"); + re->subdir = 1; + re->u.dir = read_coff_res_dir (finfo->data + rva, finfo); + } + else + { + if (rva >= finfo->data_end - finfo->data) + overrun (finfo, "ID resource"); + re->subdir = 0; + re->u.res = read_coff_data_entry (finfo->data + rva, finfo); + } + + *pp = re; + pp = &re->next; + } + + return rd; +} + +/* Read a resource data entry. */ + +static struct res_resource * +read_coff_data_entry (data, finfo) + const bfd_byte *data; + const struct coff_file_info *finfo; +{ + const struct extern_res_data *erd; + struct res_resource *r; + unsigned long size, rva; + const bfd_byte *resdata; + + if (finfo->data_end - data < sizeof (struct extern_res_data)) + overrun (finfo, "data entry"); + + erd = (const struct extern_res_data *) data; + + r = (struct res_resource *) xmalloc (sizeof *r); + memset (&r->res_info, 0, sizeof (struct res_res_info)); + r->coff_info.codepage = get_32 (finfo, erd->codepage); + r->coff_info.reserved = get_32 (finfo, erd->reserved); + + size = get_32 (finfo, erd->size); + rva = get_32 (finfo, erd->rva); + if (rva < finfo->secaddr + || rva - finfo->secaddr >= finfo->data_end - finfo->data) + overrun (finfo, "resource data"); + + resdata = finfo->data + (rva - finfo->secaddr); + + r->type = RES_TYPE_USERDATA; + r->u.userdata = ((struct rcdata_data *) + xmalloc (sizeof (struct rcdata_data))); + r->u.userdata->first = ((struct rcdata_item *) + xmalloc (sizeof (struct rcdata_item))); + r->u.userdata->last = r->u.userdata->first; + r->u.userdata->first->next = NULL; + r->u.userdata->first->type = RCDATA_BUFFER; + r->u.userdata->first->u.buffer.length = size; + r->u.userdata->first->u.buffer.data = (unsigned char *) resdata; + + return r; +} diff --git a/binutils/resrc.c b/binutils/resrc.c index 64c6c78..fb340fa 100644 --- a/binutils/resrc.c +++ b/binutils/resrc.c @@ -2009,7 +2009,7 @@ write_rc_rcdata (e, rcdata, ind) else { fprintf (e, ",\n"); - indent (e, ind); + indent (e, ind + 2); } fprintf (e, "%luL", l); } @@ -2024,7 +2024,7 @@ write_rc_rcdata (e, rcdata, ind) else { fprintf (e, ",\n"); - indent (e, ind); + indent (e, ind + 2); } fprintf (e, "%d", i); i += 2; @@ -2037,7 +2037,7 @@ write_rc_rcdata (e, rcdata, ind) else { fprintf (e, ",\n"); - indent (e, ind); + indent (e, ind + 2); } if ((ri->u.buffer.data[i] & 0x7f) == ri->u.buffer.data[i] && isprint (ri->u.buffer.data[i])) diff --git a/binutils/windres.c b/binutils/windres.c index d08fb97..bd17aaf 100644 --- a/binutils/windres.c +++ b/binutils/windres.c @@ -306,22 +306,9 @@ res_id_print (stream, id, quote) fprintf (stream, "%lu", id.u.id); else { - unsigned short *s, *se; - if (quote) putc ('"', stream); - s = id.u.n.name; - se = s + id.u.n.length; - while (s < se) - { - if (*s == '"') - fprintf (stream, "\\\""); - else if ((*s & 0xff) == *s && isprint (*s)) - putc (*s, stream); - else - fprintf (stream, "\\%03o", *s); - ++s; - } + unicode_print (stream, id.u.n.name, id.u.n.length); if (quote) putc ('"', stream); } @@ -600,8 +587,8 @@ format_from_filename (filename, input) fclose (e); - /* A PE executable starts with 0x4d 0x5a 0x90 0x00. */ - if (b1 == 0x4d && b2 == 0x5a && b3 == 0x90 && b4 == 0) + /* A PE executable starts with 0x4d 0x5a. */ + if (b1 == 0x4d && b2 == 0x5a) return RES_FORMAT_COFF; /* A COFF .o file starts with a COFF magic number. */ @@ -885,15 +872,6 @@ read_res_file (filename) return NULL; } -struct res_directory * -read_coff_rsrc (filename, target) - const char *filename; - const char *target; -{ - fatal ("read_coff_rsrc unimplemented"); - return NULL; -} - void write_res_file (filename, resources) const char *filename; -- 2.7.4