Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/tools/winedump/dump.c
8669 views
1
/*
2
* File dumping utility
3
*
4
* Copyright 2001,2007 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
23
#include <stdlib.h>
24
#include <stdarg.h>
25
#include <stdio.h>
26
#include <time.h>
27
28
#include "../tools.h"
29
#include "windef.h"
30
#include "winbase.h"
31
#include "winedump.h"
32
33
void *dump_base = NULL;
34
size_t dump_total_len = 0;
35
36
void dump_data_offset( const unsigned char *ptr, unsigned int size, unsigned int offset, const char *prefix )
37
{
38
unsigned int i, j;
39
40
printf( "%s%08x: ", prefix, offset );
41
if (!ptr)
42
{
43
printf("NULL\n");
44
return;
45
}
46
for (i = 0; i < size; i++)
47
{
48
printf( "%02x%c", ptr[i], (i % 16 == 7) ? '-' : ' ' );
49
if ((i % 16) == 15)
50
{
51
printf( " " );
52
for (j = 0; j < 16; j++)
53
printf( "%c", isprint(ptr[i-15+j]) ? ptr[i-15+j] : '.' );
54
if (i < size-1) printf( "\n%s%08x: ", prefix, offset + i + 1 );
55
}
56
}
57
if (i % 16)
58
{
59
printf( "%*s ", 3 * (16-(i%16)), "" );
60
for (j = 0; j < i % 16; j++)
61
printf( "%c", isprint(ptr[i-(i%16)+j]) ? ptr[i-(i%16)+j] : '.' );
62
}
63
printf( "\n" );
64
}
65
66
void dump_data( const unsigned char *ptr, unsigned int size, const char *prefix )
67
{
68
dump_data_offset( ptr, size, 0, prefix );
69
}
70
71
static char* dump_want_n(unsigned sz)
72
{
73
static char buffer[64 * 1024];
74
static unsigned idx;
75
char* ret;
76
77
assert(sz < sizeof(buffer));
78
if (idx + sz >= sizeof(buffer)) idx = 0;
79
ret = &buffer[idx];
80
idx += sz;
81
return ret;
82
}
83
84
const char *get_time_str(unsigned long _t)
85
{
86
const time_t t = (const time_t)_t;
87
const char *str = ctime(&t);
88
size_t len;
89
char* buf;
90
91
if (!str) return "not valid time";
92
93
len = strlen(str);
94
/* FIXME: I don't get the same values from MS' pedump running under Wine...
95
* I wonder if Wine isn't broken wrt to GMT settings...
96
*/
97
if (len && str[len-1] == '\n') len--;
98
buf = dump_want_n(len + 1);
99
if (buf)
100
{
101
memcpy( buf, str, len );
102
buf[len] = 0;
103
}
104
return buf;
105
}
106
107
unsigned int strlenW( const WCHAR *str )
108
{
109
const WCHAR *s = str;
110
while (*s) s++;
111
return s - str;
112
}
113
114
/* dump an ASCII string with proper escaping */
115
int dump_strA( const char *str, size_t len )
116
{
117
static const char escapes[32] = ".......abtnvfr.............e....";
118
char buffer[256];
119
char *pos = buffer;
120
int count = 0;
121
122
for (; len; str++, len--)
123
{
124
if (pos > buffer + sizeof(buffer) - 8)
125
{
126
fwrite( buffer, pos - buffer, 1, stdout );
127
count += pos - buffer;
128
pos = buffer;
129
}
130
if ((unsigned char)*str > 127) /* hex escape */
131
{
132
pos += sprintf( pos, "\\x%02x", (unsigned char)*str );
133
continue;
134
}
135
if (*str < 32) /* octal or C escape */
136
{
137
if (!*str && len == 1) continue; /* do not output terminating NULL */
138
if (escapes[(unsigned char)*str] != '.')
139
pos += sprintf( pos, "\\%c", escapes[(unsigned char)*str] );
140
else if (len > 1 && str[1] >= '0' && str[1] <= '7')
141
pos += sprintf( pos, "\\%03o", *str );
142
else
143
pos += sprintf( pos, "\\%o", *str );
144
continue;
145
}
146
if (*str == '\\') *pos++ = '\\';
147
*pos++ = *str;
148
}
149
fwrite( buffer, pos - buffer, 1, stdout );
150
count += pos - buffer;
151
return count;
152
}
153
154
/* dump a Unicode string with proper escaping */
155
int dump_strW( const WCHAR *str, size_t len )
156
{
157
static const char escapes[32] = ".......abtnvfr.............e....";
158
char buffer[256];
159
char *pos = buffer;
160
int count = 0;
161
162
for (; len; str++, len--)
163
{
164
if (pos > buffer + sizeof(buffer) - 8)
165
{
166
fwrite( buffer, pos - buffer, 1, stdout );
167
count += pos - buffer;
168
pos = buffer;
169
}
170
if (*str > 127) /* hex escape */
171
{
172
if (len > 1 && str[1] < 128 && isxdigit((char)str[1]))
173
pos += sprintf( pos, "\\x%04x", *str );
174
else
175
pos += sprintf( pos, "\\x%x", *str );
176
continue;
177
}
178
if (*str < 32) /* octal or C escape */
179
{
180
if (!*str && len == 1) continue; /* do not output terminating NULL */
181
if (escapes[*str] != '.')
182
pos += sprintf( pos, "\\%c", escapes[*str] );
183
else if (len > 1 && str[1] >= '0' && str[1] <= '7')
184
pos += sprintf( pos, "\\%03o", *str );
185
else
186
pos += sprintf( pos, "\\%o", *str );
187
continue;
188
}
189
if (*str == '\\') *pos++ = '\\';
190
*pos++ = *str;
191
}
192
fwrite( buffer, pos - buffer, 1, stdout );
193
count += pos - buffer;
194
return count;
195
}
196
197
const char *get_hexint64_str( DWORD64 l )
198
{
199
char *buf = dump_want_n(2 + 16 + 1);
200
if (sizeof(l) > sizeof(unsigned long) && l >> 32)
201
sprintf(buf, "%#lx%08lx", (unsigned long)(l >> 32), (unsigned long)l);
202
else
203
sprintf(buf, "%#lx", (unsigned long)l);
204
assert(strlen(buf) <= 18);
205
return buf;
206
}
207
208
const char *get_uint64_str( DWORD64 l )
209
{
210
char *buf = dump_want_n( 32 );
211
char *ptr = buf + 31;
212
*ptr = '\0';
213
for ( ; l; l /= 10)
214
*--ptr = '0' + (l % 10);
215
if (ptr == buf + 31) *--ptr = '0';
216
assert(ptr >= buf);
217
return ptr;
218
}
219
220
const char* get_symbol_str(const char* symname)
221
{
222
const char* ret = NULL;
223
224
if (!symname) return "(nil)";
225
if (globals.do_demangle) ret = demangle( symname );
226
return ret ? ret : symname;
227
}
228
229
const char* get_guid_str(const GUID* guid)
230
{
231
char* str;
232
233
str = dump_want_n(39);
234
if (str)
235
sprintf(str, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
236
(unsigned int)guid->Data1, guid->Data2, guid->Data3,
237
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
238
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
239
return str;
240
}
241
242
const char *get_unicode_str( const WCHAR *str, int len )
243
{
244
char *buffer;
245
int i = 0;
246
247
if (!str) return "(null)";
248
if (len == -1) len = strlenW( str );
249
buffer = dump_want_n( len * 6 + 3);
250
buffer[i++] = '"';
251
while (len-- > 0 && *str)
252
{
253
WCHAR c = *str++;
254
switch (c)
255
{
256
case '\n': strcpy( buffer + i, "\\n" ); i += 2; break;
257
case '\r': strcpy( buffer + i, "\\r" ); i += 2; break;
258
case '\t': strcpy( buffer + i, "\\t" ); i += 2; break;
259
case '"': strcpy( buffer + i, "\\\"" ); i += 2; break;
260
case '\\': strcpy( buffer + i, "\\\\" ); i += 2; break;
261
default:
262
if (c >= ' ' && c <= 126) buffer[i++] = c;
263
else i += sprintf( buffer + i, "\\u%04x",c);
264
}
265
}
266
buffer[i++] = '"';
267
buffer[i] = 0;
268
return buffer;
269
}
270
271
const void* PRD(unsigned long prd, unsigned long len)
272
{
273
return (prd + len > dump_total_len) ? NULL : (const char*)dump_base + prd;
274
}
275
276
unsigned long Offset(const void* ptr)
277
{
278
if (ptr < dump_base) {printf("<<<<<ptr below\n");return 0;}
279
if ((const char *)ptr >= (const char*)dump_base + dump_total_len) {printf("<<<<<ptr above\n");return 0;}
280
return (const char *)ptr - (const char *)dump_base;
281
}
282
283
static const struct dumper
284
{
285
enum FileSig kind;
286
enum FileSig (*get_kind)(void);
287
file_dumper dumper; /* default dump tool */
288
enum FileSig (*alt_get_kind)( int fd );
289
void (*alt_dumper)( int fd );
290
}
291
dumpers[] =
292
{
293
{SIG_DOS, get_kind_exec, dos_dump},
294
{SIG_PE, get_kind_exec, pe_dump},
295
{SIG_DBG, get_kind_dbg, dbg_dump},
296
{SIG_PDB, .alt_get_kind = get_kind_pdb, .alt_dumper = pdb_dump},
297
{SIG_NE, get_kind_exec, ne_dump},
298
{SIG_LE, get_kind_exec, le_dump},
299
{SIG_COFFLIB, get_kind_lib, lib_dump},
300
{SIG_MDMP, get_kind_mdmp, mdmp_dump},
301
{SIG_LNK, get_kind_lnk, lnk_dump},
302
{SIG_EMF, get_kind_emf, emf_dump},
303
{SIG_EMFSPOOL, get_kind_emfspool, emfspool_dump},
304
{SIG_MF, get_kind_mf, mf_dump},
305
{SIG_FNT, get_kind_fnt, fnt_dump},
306
{SIG_TLB, get_kind_tlb, tlb_dump},
307
{SIG_NLS, get_kind_nls, nls_dump},
308
{SIG_REG, get_kind_reg, reg_dump},
309
{SIG_UNKNOWN, NULL, NULL} /* sentinel */
310
};
311
312
BOOL dump_analysis(const char *name, file_dumper fn, enum FileSig wanted_sig)
313
{
314
BOOL ret = TRUE;
315
const struct dumper*dpr;
316
int fd;
317
struct stat st;
318
319
setbuf(stdout, NULL);
320
321
if ((fd = open( name, O_RDONLY | O_BINARY )) == -1) fatal( "Cannot read file" );
322
fstat( fd, &st );
323
printf("Contents of %s: %llu bytes\n\n", name, (unsigned long long)st.st_size);
324
325
for (dpr = dumpers; dpr->kind != SIG_UNKNOWN; dpr++)
326
{
327
if (!dpr->alt_get_kind) continue;
328
/* alt interface isn't compatible with incoming file_dumper */
329
if (wanted_sig == dpr->kind)
330
assert( !fn );
331
332
lseek( fd, 0, SEEK_SET );
333
if (dpr->alt_get_kind( fd ) == dpr->kind &&
334
(wanted_sig == SIG_UNKNOWN || wanted_sig == dpr->kind))
335
{
336
lseek( fd, 0, SEEK_SET );
337
dpr->alt_dumper( fd );
338
break;
339
}
340
}
341
close(fd);
342
343
if (dpr->kind == SIG_UNKNOWN)
344
{
345
if (!(dump_base = read_file( name, &dump_total_len ))) fatal( "Cannot read file" );
346
347
for (dpr = dumpers; dpr->kind != SIG_UNKNOWN; dpr++)
348
{
349
if (!dpr->get_kind) continue;
350
if (dpr->get_kind() == dpr->kind &&
351
(wanted_sig == SIG_UNKNOWN || wanted_sig == dpr->kind))
352
{
353
if (fn) fn(); else dpr->dumper();
354
break;
355
}
356
}
357
if (dpr->kind == SIG_UNKNOWN)
358
{
359
printf("Can't get a suitable file signature, aborting\n");
360
ret = FALSE;
361
}
362
363
free( dump_base );
364
}
365
if (ret) printf("Done dumping %s\n", name);
366
367
return ret;
368
}
369
370
void dump_file(const char* name)
371
{
372
dump_analysis(name, NULL, SIG_UNKNOWN);
373
}
374
375