ne.c 13.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/*
 * Dumping of NE binaries
 *
 * Copyright 2002 Alexandre Julliard
 *
 * 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
 */

Jon Griffiths's avatar
Jon Griffiths committed
21 22 23
#include "config.h"
#include "wine/port.h"

24
#include <fcntl.h>
25
#include <stdarg.h>
26
#include <stdio.h>
Jon Griffiths's avatar
Jon Griffiths committed
27
#ifdef HAVE_UNISTD_H
28
#include <unistd.h>
Jon Griffiths's avatar
Jon Griffiths committed
29
#endif
30

31
#include "windef.h"
32 33 34 35
#include "winbase.h"
#include "wine/winbase16.h"
#include "winedump.h"

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
struct ne_segtable_entry
{
    WORD seg_data_offset;   /* Sector offset of segment data	*/
    WORD seg_data_length;   /* Length of segment data		*/
    WORD seg_flags;         /* Flags associated with this segment	*/
    WORD min_alloc;         /* Minimum allocation size for this	*/
};

struct relocation_entry
{
    BYTE address_type;    /* Relocation address type */
    BYTE relocation_type; /* Relocation type */
    WORD offset;          /* Offset in segment to fixup */
    WORD target1;         /* Target specification */
    WORD target2;         /* Target specification */
};

#define NE_RADDR_LOWBYTE      0
#define NE_RADDR_SELECTOR     2
#define NE_RADDR_POINTER32    3
#define NE_RADDR_OFFSET16     5
#define NE_RADDR_POINTER48    11
#define NE_RADDR_OFFSET32     13

#define NE_RELTYPE_INTERNAL  0
#define NE_RELTYPE_ORDINAL   1
#define NE_RELTYPE_NAME      2
#define NE_RELTYPE_OSFIXUP   3
#define NE_RELFLAG_ADDITIVE  4

66 67 68 69 70
static inline WORD get_word( const BYTE *ptr )
{
    return ptr[0] | (ptr[1] << 8);
}

71 72 73 74 75
static void dump_ne_header( const IMAGE_OS2_HEADER *ne )
{
    printf( "File header:\n" );
    printf( "Linker version:      %d.%d\n", ne->ne_ver, ne->ne_rev );
    printf( "Entry table:         %x len %d\n", ne->ne_enttab, ne->ne_cbenttab );
76
    printf( "Checksum:            %08x\n", ne->ne_crc );
77 78 79 80 81 82 83 84 85 86 87 88 89
    printf( "Flags:               %04x\n", ne->ne_flags );
    printf( "Auto data segment:   %x\n", ne->ne_autodata );
    printf( "Heap size:           %d bytes\n", ne->ne_heap );
    printf( "Stack size:          %d bytes\n", ne->ne_stack );
    printf( "Stack pointer:       %x:%04x\n", SELECTOROF(ne->ne_sssp), OFFSETOF(ne->ne_sssp) );
    printf( "Entry point:         %x:%04x\n", SELECTOROF(ne->ne_csip), OFFSETOF(ne->ne_csip) );
    printf( "Number of segments:  %d\n", ne->ne_cseg );
    printf( "Number of modrefs:   %d\n", ne->ne_cmod );
    printf( "Segment table:       %x\n", ne->ne_segtab );
    printf( "Resource table:      %x\n", ne->ne_rsrctab );
    printf( "Resident name table: %x\n", ne->ne_restab );
    printf( "Module table:        %x\n", ne->ne_modtab );
    printf( "Import table:        %x\n", ne->ne_imptab );
90
    printf( "Non-resident table:  %x\n", ne->ne_nrestab );
91 92
    printf( "Exe type:            %x\n", ne->ne_exetyp );
    printf( "Other flags:         %x\n", ne->ne_flagsothers );
93 94
    printf( "Fast load area:      %x-%x\n", ne->ne_pretthunks << ne->ne_align,
            (ne->ne_pretthunks+ne->ne_psegrefbytes) << ne->ne_align );
95 96 97
    printf( "Expected version:    %d.%d\n", HIBYTE(ne->ne_expver), LOBYTE(ne->ne_expver) );
}

98
static void dump_ne_names( const IMAGE_OS2_HEADER *ne )
99
{
100
    const unsigned char *pstr = (const unsigned char *)ne + ne->ne_restab;
101

102
    printf( "\nResident name table:\n" );
103 104
    while (*pstr)
    {
105
        printf( " %4d: %*.*s\n", get_word(pstr + *pstr + 1), *pstr, *pstr, pstr + 1 );
106 107
        pstr += *pstr + 1 + sizeof(WORD);
    }
108 109 110
    if (ne->ne_cbnrestab)
    {
        printf( "\nNon-resident name table:\n" );
111
        pstr = PRD(ne->ne_nrestab, 0);
112 113 114 115 116 117
        while (*pstr)
        {
            printf( " %4d: %*.*s\n", get_word(pstr + *pstr + 1), *pstr, *pstr, pstr + 1 );
            pstr += *pstr + 1 + sizeof(WORD);
        }
    }
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
static const char *get_resource_type( WORD id )
{
    static char buffer[5];
    switch(id)
    {
    case NE_RSCTYPE_CURSOR: return "CURSOR";
    case NE_RSCTYPE_BITMAP: return "BITMAP";
    case NE_RSCTYPE_ICON: return "ICON";
    case NE_RSCTYPE_MENU: return "MENU";
    case NE_RSCTYPE_DIALOG: return "DIALOG";
    case NE_RSCTYPE_STRING: return "STRING";
    case NE_RSCTYPE_FONTDIR: return "FONTDIR";
    case NE_RSCTYPE_FONT: return "FONT";
    case NE_RSCTYPE_ACCELERATOR: return "ACCELERATOR";
    case NE_RSCTYPE_RCDATA: return "RCDATA";
    case NE_RSCTYPE_GROUP_CURSOR: return "CURSOR_GROUP";
    case NE_RSCTYPE_GROUP_ICON: return "ICON_GROUP";
    default:
        sprintf( buffer, "%04x", id );
        return buffer;
    }
}

143
static void dump_ne_resources( const IMAGE_OS2_HEADER *ne )
144
{
145 146
    const NE_NAMEINFO *name;
    const void *res_ptr = (const char *)ne + ne->ne_rsrctab;
147
    WORD size_shift = get_word(res_ptr);
148
    const NE_TYPEINFO *info = (const NE_TYPEINFO *)((const WORD *)res_ptr + 1);
149 150 151
    int count;

    printf( "\nResources:\n" );
152
    while (info->type_id != 0 && (const char *)info < (const char *)ne + ne->ne_restab)
153
    {
154
        name = (const NE_NAMEINFO *)(info + 1);
155 156 157
        for (count = info->count; count > 0; count--, name++)
        {
            if (name->id & 0x8000) printf( "  %d", (name->id & ~0x8000) );
158 159
            else printf( "  %.*s", *((const unsigned char *)res_ptr + name->id),
                         (const char *)res_ptr + name->id + 1 );
160 161
            if (info->type_id & 0x8000) printf( " %s", get_resource_type(info->type_id) );
            else printf( " %.*s", *((const unsigned char *)res_ptr + info->type_id),
162
                         (const char *)res_ptr + info->type_id + 1 );
163
            printf(" flags %04x length %04x\n", name->flags, name->length << size_shift);
164
            dump_data( PRD(name->offset << size_shift, name->length << size_shift),
165 166
                       name->length << size_shift, "    " );
        }
167
        info = (const NE_TYPEINFO *)name;
168 169 170
    }
}

171
static const char *get_export_name( const IMAGE_OS2_HEADER *ne, int ordinal )
172 173
{
    static char name[256];
174
    const BYTE *pstr;
175 176 177 178 179 180 181 182
    int pass = 0;

    /* search the resident names */

    while (pass < 2)
    {
        if (pass == 0)  /* resident names */
        {
183
            pstr = (const BYTE *)ne + ne->ne_restab;
184 185 186 187 188
            if (*pstr) pstr += *pstr + 1 + sizeof(WORD);  /* skip first entry (module name) */
        }
        else  /* non-resident names */
        {
            if (!ne->ne_cbnrestab) break;
189
            pstr = PRD(ne->ne_nrestab, 0);
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
        }
        while (*pstr)
        {
            WORD ord = get_word(pstr + *pstr + 1);
            if (ord == ordinal)
            {
                memcpy( name, pstr + 1, *pstr );
                name[*pstr] = 0;
                return name;
            }
            pstr += *pstr + 1 + sizeof(WORD);
        }
        pass++;
    }
    name[0] = 0;
    return name;
}

208
static void dump_ne_exports( const IMAGE_OS2_HEADER *ne )
209
{
210 211
    const BYTE *ptr = (const BYTE *)ne + ne->ne_enttab;
    const BYTE *end = ptr + ne->ne_cbenttab;
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
    int i, ordinal = 1;

    if (!ne->ne_cbenttab || !*ptr) return;

    printf( "\nExported entry points:\n" );

    while (ptr < end && *ptr)
    {
        BYTE count = *ptr++;
        BYTE type = *ptr++;
        switch(type)
        {
        case 0:  /* next bundle */
            ordinal += count;
            break;
        case 0xff:  /* movable */
            for (i = 0; i < count; i++)
            {
                printf( " %4d MOVABLE %d:%04x %s\n",
                        ordinal + i, ptr[3], get_word(ptr + 4),
232
                        get_export_name( ne, ordinal + i ) );
233 234 235 236 237 238 239 240 241
                ptr += 6;
            }
            ordinal += count;
            break;
        case 0xfe:  /* constant */
            for (i = 0; i < count; i++)
            {
                printf( " %4d CONST     %04x %s\n",
                        ordinal + i, get_word(ptr + 1),
242
                        get_export_name( ne, ordinal + i ) );
243 244 245 246 247 248 249 250 251
                ptr += 3;
            }
            ordinal += count;
            break;
        default:  /* fixed */
            for (i = 0; i < count; i++)
            {
                printf( " %4d FIXED   %d:%04x %s\n",
                        ordinal + i, type, get_word(ptr + 1),
252
                        get_export_name( ne, ordinal + i ) );
253 254 255 256 257 258 259 260
                ptr += 3;
            }
            ordinal += count;
            break;
        }
    }
}

261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
static const char *get_reloc_name( BYTE addr_type, int additive )
{
    switch(addr_type & 0x7f)
    {
    case NE_RADDR_LOWBYTE:   return additive ? "byte add" : "byte";
    case NE_RADDR_OFFSET16:  return additive ? "off16 add" : "off16";
    case NE_RADDR_POINTER32: return additive ? "ptr32 add" : "ptr32";
    case NE_RADDR_SELECTOR:  return additive ? "sel add" : "sel";
    case NE_RADDR_POINTER48: return additive ? "ptr48 add" : "ptr48";
    case NE_RADDR_OFFSET32:  return additive ? "off32 add" : "off32";
    }
    return "???";
}

static const char *get_seg_flags( WORD flags )
{
    static char buffer[256];

    buffer[0] = 0;
#define ADD_FLAG(x) if (flags & NE_SEGFLAGS_##x) strcat( buffer, " " #x );
    ADD_FLAG(DATA);
    ADD_FLAG(ALLOCATED);
    ADD_FLAG(LOADED);
    ADD_FLAG(ITERATED);
    ADD_FLAG(MOVEABLE);
    ADD_FLAG(SHAREABLE);
    ADD_FLAG(PRELOAD);
    ADD_FLAG(EXECUTEONLY);
    ADD_FLAG(READONLY);
    ADD_FLAG(RELOC_DATA);
    ADD_FLAG(SELFLOAD);
    ADD_FLAG(DISCARDABLE);
    ADD_FLAG(32BIT);
#undef ADD_FLAG
    if (buffer[0])
    {
        buffer[0] = '(';
        strcat( buffer, ")" );
    }
    return buffer;
}

303
static void dump_relocations( const IMAGE_OS2_HEADER *ne, WORD count,
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
                              const struct relocation_entry *rep )
{
    const WORD *modref = (const WORD *)((const BYTE *)ne + ne->ne_modtab);
    const BYTE *mod_name, *func_name;
    WORD i;

    for (i = 0; i < count; i++, rep++)
    {
        int additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
        switch (rep->relocation_type & 3)
        {
        case NE_RELTYPE_ORDINAL:
            mod_name = (const BYTE *)ne + ne->ne_imptab + modref[rep->target1 - 1];
            printf( "%6d: %s = %*.*s.%d\n", i + 1, get_reloc_name( rep->address_type, additive ),
                    *mod_name, *mod_name, mod_name + 1, rep->target2 );
            break;
        case NE_RELTYPE_NAME:
            mod_name = (const BYTE *)ne + ne->ne_imptab + modref[rep->target1 - 1];
            func_name = (const BYTE *)ne + ne->ne_imptab + rep->target2;
            printf( "%6d: %s = %*.*s.%*.*s\n", i + 1, get_reloc_name( rep->address_type, additive ),
                    *mod_name, *mod_name, mod_name + 1,
                    *func_name, *func_name, func_name + 1 );
            break;
        case NE_RELTYPE_INTERNAL:
            if ((rep->target1 & 0xff) == 0xff)
            {
                /* the module itself */
                mod_name = (const BYTE *)ne + ne->ne_restab;
                printf( "%6d: %s = %*.*s.%d\n", i + 1, get_reloc_name( rep->address_type, additive ),
                        *mod_name, *mod_name, mod_name + 1, rep->target2 );
            }
            else
                printf( "%6d: %s = %d:%04x\n", i + 1, get_reloc_name( rep->address_type, additive ),
                        rep->target1, rep->target2 );
            break;
        case NE_RELTYPE_OSFIXUP:
            /* Relocation type 7:
             *
             *    These appear to be used as fixups for the Windows
             * floating point emulator.  Let's just ignore them and
             * try to use the hardware floating point.  Linux should
             * successfully emulate the coprocessor if it doesn't
             * exist.
             */
            printf( "%6d: %s = TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
                    i + 1, get_reloc_name( rep->address_type, additive ),
                    rep->relocation_type, rep->offset,
                    rep->target1, rep->target2 );
            break;
        }
    }
}

357
static void dump_ne_segment( const IMAGE_OS2_HEADER *ne, int segnum )
358 359 360 361 362 363 364 365 366 367 368
{
    const struct ne_segtable_entry *table = (const struct ne_segtable_entry *)((const BYTE *)ne + ne->ne_segtab);
    const struct ne_segtable_entry *seg = table + segnum - 1;

    printf( "\nSegment %d:\n", segnum );
    printf( "  File offset: %08x\n", seg->seg_data_offset << ne->ne_align );
    printf( "  Length:      %08x\n", seg->seg_data_length );
    printf( "  Flags:       %08x %s\n", seg->seg_flags, get_seg_flags(seg->seg_flags) );
    printf( "  Alloc size:  %08x\n", seg->min_alloc );
    if (seg->seg_flags & NE_SEGFLAGS_RELOC_DATA)
    {
369
        const BYTE *ptr = PRD((seg->seg_data_offset << ne->ne_align) + seg->seg_data_length, 0);
370 371 372
        WORD count = get_word(ptr);
        ptr += sizeof(WORD);
        printf( "  Relocations:\n" );
373
        dump_relocations( ne, count, (const struct relocation_entry *)ptr );
374 375 376
    }
}

377
void ne_dump( void )
378
{
379
    unsigned int i;
380 381 382 383 384 385
    const IMAGE_DOS_HEADER *dos;
    const IMAGE_OS2_HEADER *ne;

    dos = PRD(0, sizeof(*dos));
    if (!dos) return;
    ne = PRD(dos->e_lfanew, sizeof(*ne));
386

387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
    if (globals.do_dumpheader || !globals.dumpsect)
        dump_ne_header( ne );
    if (globals.do_dumpheader)
        dump_ne_names( ne );
    if (globals.dumpsect)
    {
        BOOL	all = strcmp(globals.dumpsect, "ALL") == 0;

        if (all || !strcmp(globals.dumpsect, "resource"))
            dump_ne_resources( ne );
        if (all || !strcmp(globals.dumpsect, "export"))
            dump_ne_exports( ne );
    }
    if (globals.do_dumpheader)
        for (i = 1; i <= ne->ne_cseg; i++) dump_ne_segment( ne, i );
402
}