winedump: Add partial COFF library support.
[wine] / tools / winedump / dump.c
1 /*
2  *      File dumping utility
3  *
4  *      Copyright 2001,2005 Eric Pouech
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <time.h>
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34 #ifdef HAVE_SYS_STAT_H
35 # include <sys/stat.h>
36 #endif
37 #ifdef HAVE_SYS_MMAN_H
38 #include <sys/mman.h>
39 #endif
40 #include <fcntl.h>
41
42 #define NONAMELESSUNION
43 #define NONAMELESSSTRUCT
44 #include "windef.h"
45 #include "winbase.h"
46 #include "winedump.h"
47 #include "pe.h"
48
49 static void*                    dump_base;
50 static unsigned long            dump_total_len;
51
52 void dump_data( const unsigned char *ptr, unsigned int size, const char *prefix )
53 {
54     unsigned int i, j;
55
56     printf( "%s%08x: ", prefix, 0 );
57     if (!ptr)
58     {
59         printf("NULL\n");
60         return;
61     }
62     for (i = 0; i < size; i++)
63     {
64         printf( "%02x%c", ptr[i], (i % 16 == 7) ? '-' : ' ' );
65         if ((i % 16) == 15)
66         {
67             printf( " " );
68             for (j = 0; j < 16; j++)
69                 printf( "%c", isprint(ptr[i-15+j]) ? ptr[i-15+j] : '.' );
70             if (i < size-1) printf( "\n%s%08x: ", prefix, i + 1 );
71         }
72     }
73     if (i % 16)
74     {
75         printf( "%*s ", 3 * (16-(i%16)), "" );
76         for (j = 0; j < i % 16; j++)
77             printf( "%c", isprint(ptr[i-(i%16)+j]) ? ptr[i-(i%16)+j] : '.' );
78     }
79     printf( "\n" );
80 }
81
82 const char *get_time_str(unsigned long _t)
83 {
84     const time_t    t = (const time_t)_t;
85     const char      *str = ctime(&t);
86     size_t          len;
87     static char     buf[128];
88
89     if (!str) /* not valid time */
90     {
91         strcpy(buf, "not valid time");
92         return buf;
93     }
94
95     len = strlen(str);
96     /* FIXME: I don't get the same values from MS' pedump running under Wine...
97      * I wonder if Wine isn't broken wrt to GMT settings...
98      */
99     if (len && str[len-1] == '\n') len--;
100     if (len >= sizeof(buf)) len = sizeof(buf) - 1;
101     memcpy( buf, str, len );
102     buf[len] = 0;
103     return buf;
104 }
105
106 unsigned int strlenW( const WCHAR *str )
107 {
108     const WCHAR *s = str;
109     while (*s) s++;
110     return s - str;
111 }
112
113 void dump_unicode_str( const WCHAR *str, int len )
114 {
115     if (len == -1) len = strlenW( str );
116     printf( "L\"");
117     while (len-- > 0 && *str)
118     {
119         WCHAR c = *str++;
120         switch (c)
121         {
122         case '\n': printf( "\\n" ); break;
123         case '\r': printf( "\\r" ); break;
124         case '\t': printf( "\\t" ); break;
125         case '"':  printf( "\\\"" ); break;
126         case '\\': printf( "\\\\" ); break;
127         default:
128             if (c >= ' ' && c <= 126) putchar(c);
129             else printf( "\\u%04x",c);
130         }
131     }
132     printf( "\"" );
133 }
134
135 const void*     PRD(unsigned long prd, unsigned long len)
136 {
137     return (prd + len > dump_total_len) ? NULL : (const char*)dump_base + prd;
138 }
139
140 unsigned long Offset(const void* ptr)
141 {
142     if (ptr < dump_base) {printf("<<<<<ptr below\n");return 0;}
143     if ((const char *)ptr >= (const char*)dump_base + dump_total_len) {printf("<<<<<ptr above\n");return 0;}
144     return (const char *)ptr - (const char *)dump_base;
145 }
146
147 static  void    do_dump( enum FileSig sig, const void* pmt )
148 {
149     if (sig == SIG_NE)
150     {
151         ne_dump( dump_base, dump_total_len );
152         return;
153     }
154
155     if (sig == SIG_LE)
156     {
157         le_dump( dump_base, dump_total_len );
158         return;
159     }
160
161     pe_dump(pmt);
162 }
163
164 static enum FileSig check_headers(void)
165 {
166     const char *p;
167     const WORD*         pw;
168     const DWORD*                pdw;
169     const IMAGE_DOS_HEADER*     dh;
170     enum FileSig        sig;
171
172     pw = PRD(0, sizeof(WORD));
173     if (!pw) {printf("Can't get main signature, aborting\n"); return 0;}
174
175     switch (*pw)
176     {
177     case IMAGE_DOS_SIGNATURE:
178         sig = SIG_DOS;
179         dh = PRD(0, sizeof(IMAGE_DOS_HEADER));
180         if (dh)
181         {
182             /* the signature is the first DWORD */
183             pdw = PRD(dh->e_lfanew, sizeof(DWORD));
184             if (pdw)
185             {
186                 if (*pdw == IMAGE_NT_SIGNATURE)
187                 {
188                     sig = SIG_PE;
189                 }
190                 else if (*(const WORD *)pdw == IMAGE_OS2_SIGNATURE)
191                 {
192                     sig = SIG_NE;
193                 }
194                 else if (*(const WORD *)pdw == IMAGE_VXD_SIGNATURE)
195                 {
196                     sig = SIG_LE;
197                 }
198                 else
199                 {
200                     printf("No PE Signature found\n");
201                 }
202             }
203             else
204             {
205                 printf("Can't get the extented signature, aborting\n");
206             }
207         }
208         return sig;
209
210     case 0x4944: /* "DI" */
211         return SIG_DBG;
212
213     case 0x444D: /* "MD" */
214         pdw = PRD(0, sizeof(DWORD));
215         if (pdw && *pdw == 0x504D444D) /* "MDMP" */
216             return SIG_MDMP;
217         return SIG_UNKNOWN;
218
219     default:
220         break;
221     }
222
223     p = PRD(0, IMAGE_ARCHIVE_START_SIZE);
224     if (p && !strncmp(p, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE))
225         return SIG_COFFLIB;
226
227     printf("No known main signature (%.2s/%x), aborting\n", (const char *)pw, *pw);
228     return SIG_UNKNOWN;
229 }
230
231 int dump_analysis(const char *name, file_dumper fn, enum FileSig wanted_sig)
232 {
233     int                 fd;
234     enum FileSig        effective_sig;
235     int                 ret = 1;
236     struct stat         s;
237
238     setbuf(stdout, NULL);
239
240     fd = open(name, O_RDONLY | O_BINARY);
241     if (fd == -1) fatal("Can't open file");
242
243     if (fstat(fd, &s) < 0) fatal("Can't get size");
244     dump_total_len = s.st_size;
245
246 #ifdef HAVE_MMAP
247     if ((dump_base = mmap(NULL, dump_total_len, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *)-1)
248 #endif
249     {
250         if (!(dump_base = malloc( dump_total_len ))) fatal( "Out of memory" );
251         if ((unsigned long)read( fd, dump_base, dump_total_len ) != dump_total_len) fatal( "Cannot read file" );
252     }
253
254     effective_sig = check_headers();
255
256     if (wanted_sig == SIG_UNKNOWN || wanted_sig == effective_sig)
257     {
258         switch (effective_sig)
259         {
260         case SIG_UNKNOWN: /* shouldn't happen... */
261             printf("Can't get a recognized file signature, aborting\n");
262             ret = 0; break;
263         case SIG_PE:
264         case SIG_NE:
265         case SIG_LE:
266             printf("Contents of \"%s\": %ld bytes\n\n", name, dump_total_len);
267             (*fn)(effective_sig, dump_base);
268             break;
269         case SIG_DBG:
270             dump_separate_dbg();
271             break;
272         case SIG_DOS:
273             ret = 0; break;
274         case SIG_MDMP:
275             mdmp_dump();
276             break;
277
278         case SIG_COFFLIB:
279             printf("Contents of \"%s\": %ld bytes\n\n", name, dump_total_len);
280             lib_dump(dump_base, dump_total_len);
281             break;
282         }
283     }
284     else
285     {
286         printf("Can't get a suitable file signature, aborting\n");
287         ret = 0;
288     }
289
290     if (ret) printf("Done dumping %s\n", name);
291 #ifdef HAVE_MMAP
292     if (munmap(dump_base, dump_total_len) == -1)
293 #endif
294     {
295         free( dump_base );
296     }
297     close(fd);
298
299     return ret;
300 }
301
302 void    dump_file(const char* name)
303 {
304     dump_analysis(name, do_dump, SIG_UNKNOWN);
305 }