dump.c 8.49 KB
Newer Older
1 2 3
/*
 *	File dumping utility
 *
4
 * 	Copyright 2001,2007 Eric Pouech
5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
 */

#include "config.h"
#include "wine/port.h"

#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <time.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
#endif
#include <fcntl.h>

#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "windef.h"
#include "winbase.h"
#include "winedump.h"

static void*			dump_base;
static unsigned long		dump_total_len;

void dump_data( const unsigned char *ptr, unsigned int size, const char *prefix )
{
    unsigned int i, j;

55
    printf( "%s%08x: ", prefix, 0 );
56 57 58 59 60 61 62 63 64 65 66 67 68
    if (!ptr)
    {
        printf("NULL\n");
        return;
    }
    for (i = 0; i < size; i++)
    {
        printf( "%02x%c", ptr[i], (i % 16 == 7) ? '-' : ' ' );
        if ((i % 16) == 15)
        {
            printf( " " );
            for (j = 0; j < 16; j++)
                printf( "%c", isprint(ptr[i-15+j]) ? ptr[i-15+j] : '.' );
69
            if (i < size-1) printf( "\n%s%08x: ", prefix, i + 1 );
70 71 72 73 74 75 76 77 78 79 80
        }
    }
    if (i % 16)
    {
        printf( "%*s ", 3 * (16-(i%16)), "" );
        for (j = 0; j < i % 16; j++)
            printf( "%c", isprint(ptr[i-(i%16)+j]) ? ptr[i-(i%16)+j] : '.' );
    }
    printf( "\n" );
}

81 82 83 84 85 86 87 88 89 90 91 92 93
static char* dump_want_n(unsigned sz)
{
    static char         buffer[4 * 1024];
    static unsigned     idx;
    char*               ret;

    assert(sz < sizeof(buffer));
    if (idx + sz >= sizeof(buffer)) idx = 0;
    ret = &buffer[idx];
    idx += sz;
    return ret;
}

94
const char *get_time_str(unsigned long _t)
95
{
96 97 98
    const time_t    t = (const time_t)_t;
    const char      *str = ctime(&t);
    size_t          len;
99
    char*           buf;
100

101
    if (!str) return "not valid time";
102 103

    len = strlen(str);
104 105 106
    /* FIXME: I don't get the same values from MS' pedump running under Wine...
     * I wonder if Wine isn't broken wrt to GMT settings...
     */
107
    if (len && str[len-1] == '\n') len--;
108 109 110 111 112 113
    buf = dump_want_n(len + 1);
    if (buf)
    {
        memcpy( buf, str, len );
        buf[len] = 0;
    }
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
    return buf;
}

unsigned int strlenW( const WCHAR *str )
{
    const WCHAR *s = str;
    while (*s) s++;
    return s - str;
}

void dump_unicode_str( const WCHAR *str, int len )
{
    if (len == -1) len = strlenW( str );
    printf( "L\"");
    while (len-- > 0 && *str)
    {
        WCHAR c = *str++;
        switch (c)
        {
        case '\n': printf( "\\n" ); break;
        case '\r': printf( "\\r" ); break;
        case '\t': printf( "\\t" ); break;
        case '"':  printf( "\\\"" ); break;
        case '\\': printf( "\\\\" ); break;
        default:
            if (c >= ' ' && c <= 126) putchar(c);
            else printf( "\\u%04x",c);
        }
    }
    printf( "\"" );
}

146 147 148 149 150 151 152 153 154 155 156
const char* get_symbol_str(const char* symname)
{
    char*       tmp;
    const char* ret;

    if (!symname) return "(nil)";
    if (globals.do_demangle)
    {
        parsed_symbol   symbol;

        symbol_init(&symbol, symname);
157
        if (!symbol_demangle(&symbol))
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
            ret = symname;
        else if (symbol.flags & SYM_DATA)
        {
            ret = tmp = dump_want_n(strlen(symbol.arg_text[0]) + 1);
            if (tmp) strcpy(tmp, symbol.arg_text[0]);
        }
        else
        {
            unsigned int i, len, start = symbol.flags & SYM_THISCALL ? 1 : 0;

            len = strlen(symbol.return_text) + 3 /* ' __' */ +
                strlen(symbol_get_call_convention(&symbol)) + 1 /* ' ' */+
                strlen(symbol.function_name) + 1 /* ')' */;
            if (!symbol.argc || (symbol.argc == 1 && symbol.flags & SYM_THISCALL))
                len += 4 /* "void" */;
            else for (i = start; i < symbol.argc; i++)
                len += (i > start ? 2 /* ", " */ : 0 /* "" */) + strlen(symbol.arg_text[i]);
            if (symbol.varargs) len += 5 /* ", ..." */;
            len += 2; /* ")\0" */

            ret = tmp = dump_want_n(len);
            if (tmp)
            {
                sprintf(tmp, "%s __%s %s(",
                        symbol.return_text,
                        symbol_get_call_convention(&symbol),
                        symbol.function_name);
                if (!symbol.argc || (symbol.argc == 1 && symbol.flags & SYM_THISCALL))
                    strcat(tmp, "void");
                else for (i = start; i < symbol.argc; i++)
                {
                    if (i > start) strcat(tmp, ", ");
                    strcat(tmp, symbol.arg_text[i]);
                }
                if (symbol.varargs) strcat(tmp, ", ...");
                strcat(tmp, ")");
            }
        }
        symbol_clear(&symbol);
    }
    else ret = symname;
    return ret;
}

202
const char* get_guid_str(const GUID* guid)
203
{
204 205 206 207 208 209 210 211
    char* str;

    str = dump_want_n(39);
    if (str)
        sprintf(str, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
                guid->Data1, guid->Data2, guid->Data3,
                guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
                guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
212 213 214
    return str;
}

215
const void*	PRD(unsigned long prd, unsigned long len)
216
{
217
    return (prd + len > dump_total_len) ? NULL : (const char*)dump_base + prd;
218 219
}

220
unsigned long Offset(const void* ptr)
221 222
{
    if (ptr < dump_base) {printf("<<<<<ptr below\n");return 0;}
223
    if ((const char *)ptr >= (const char*)dump_base + dump_total_len) {printf("<<<<<ptr above\n");return 0;}
224
    return (const char *)ptr - (const char *)dump_base;
225 226
}

227
static const struct dumper
228
{
229 230 231
    enum FileSig        kind;
    enum FileSig        (*get_kind)(void);
    file_dumper         dumper; /* default dump tool */
232
}
233
dumpers[] =
234
{
235
    {SIG_DOS,           get_kind_exec,  dos_dump},
236 237
    {SIG_PE,            get_kind_exec,  pe_dump},
    {SIG_DBG,           get_kind_dbg,   dbg_dump},
238
    {SIG_PDB,           get_kind_pdb,   pdb_dump},
239 240 241 242
    {SIG_NE,            get_kind_exec,  ne_dump},
    {SIG_LE,            get_kind_exec,  le_dump},
    {SIG_COFFLIB,       get_kind_lib,   lib_dump},
    {SIG_MDMP,          get_kind_mdmp,  mdmp_dump},
243
    {SIG_LNK,           get_kind_lnk,   lnk_dump},
244
    {SIG_EMF,           get_kind_emf,   emf_dump},
245
    {SIG_FNT,           get_kind_fnt,   fnt_dump},
246
    {SIG_MSFT,          get_kind_msft,  msft_dump},
247 248
    {SIG_UNKNOWN,       NULL,           NULL} /* sentinel */
};
249

250
BOOL dump_analysis(const char *name, file_dumper fn, enum FileSig wanted_sig)
251 252
{
    int			fd;
253
    BOOL                ret = TRUE;
254
    struct stat		s;
255
    const struct dumper *dpr;
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272

    setbuf(stdout, NULL);

    fd = open(name, O_RDONLY | O_BINARY);
    if (fd == -1) fatal("Can't open file");

    if (fstat(fd, &s) < 0) fatal("Can't get size");
    dump_total_len = s.st_size;

#ifdef HAVE_MMAP
    if ((dump_base = mmap(NULL, dump_total_len, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *)-1)
#endif
    {
        if (!(dump_base = malloc( dump_total_len ))) fatal( "Out of memory" );
        if ((unsigned long)read( fd, dump_base, dump_total_len ) != dump_total_len) fatal( "Cannot read file" );
    }

273 274
    printf("Contents of %s: %ld bytes\n\n", name, dump_total_len);

275
    for (dpr = dumpers; dpr->kind != SIG_UNKNOWN; dpr++)
276
    {
277 278 279 280
        if (dpr->get_kind() == dpr->kind &&
            (wanted_sig == SIG_UNKNOWN || wanted_sig == dpr->kind))
        {
            if (fn) fn(); else dpr->dumper();
281
            break;
282
        }
283
    }
284
    if (dpr->kind == SIG_UNKNOWN)
285 286
    {
	printf("Can't get a suitable file signature, aborting\n");
287
        ret = FALSE;
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
    }

    if (ret) printf("Done dumping %s\n", name);
#ifdef HAVE_MMAP
    if (munmap(dump_base, dump_total_len) == -1)
#endif
    {
        free( dump_base );
    }
    close(fd);

    return ret;
}

void	dump_file(const char* name)
{
304
    dump_analysis(name, NULL, SIG_UNKNOWN);
305
}