2 * Dumping of NE binaries
4 * Copyright 2002 Alexandre Julliard
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.
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.
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
22 #include "wine/port.h"
33 #include "wine/winbase16.h"
36 struct ne_segtable_entry
38 WORD seg_data_offset
; /* Sector offset of segment data */
39 WORD seg_data_length
; /* Length of segment data */
40 WORD seg_flags
; /* Flags associated with this segment */
41 WORD min_alloc
; /* Minimum allocation size for this */
44 struct relocation_entry
46 BYTE address_type
; /* Relocation address type */
47 BYTE relocation_type
; /* Relocation type */
48 WORD offset
; /* Offset in segment to fixup */
49 WORD target1
; /* Target specification */
50 WORD target2
; /* Target specification */
53 #define NE_RADDR_LOWBYTE 0
54 #define NE_RADDR_SELECTOR 2
55 #define NE_RADDR_POINTER32 3
56 #define NE_RADDR_OFFSET16 5
57 #define NE_RADDR_POINTER48 11
58 #define NE_RADDR_OFFSET32 13
60 #define NE_RELTYPE_INTERNAL 0
61 #define NE_RELTYPE_ORDINAL 1
62 #define NE_RELTYPE_NAME 2
63 #define NE_RELTYPE_OSFIXUP 3
64 #define NE_RELFLAG_ADDITIVE 4
66 static inline WORD
get_word( const BYTE
*ptr
)
68 return ptr
[0] | (ptr
[1] << 8);
71 static void dump_ne_header( const IMAGE_OS2_HEADER
*ne
)
73 printf( "File header:\n" );
74 printf( "Linker version: %d.%d\n", ne
->ne_ver
, ne
->ne_rev
);
75 printf( "Entry table: %x len %d\n", ne
->ne_enttab
, ne
->ne_cbenttab
);
76 printf( "Checksum: %08x\n", ne
->ne_crc
);
77 printf( "Flags: %04x\n", ne
->ne_flags
);
78 printf( "Auto data segment: %x\n", ne
->ne_autodata
);
79 printf( "Heap size: %d bytes\n", ne
->ne_heap
);
80 printf( "Stack size: %d bytes\n", ne
->ne_stack
);
81 printf( "Stack pointer: %x:%04x\n", SELECTOROF(ne
->ne_sssp
), OFFSETOF(ne
->ne_sssp
) );
82 printf( "Entry point: %x:%04x\n", SELECTOROF(ne
->ne_csip
), OFFSETOF(ne
->ne_csip
) );
83 printf( "Number of segments: %d\n", ne
->ne_cseg
);
84 printf( "Number of modrefs: %d\n", ne
->ne_cmod
);
85 printf( "Segment table: %x\n", ne
->ne_segtab
);
86 printf( "Resource table: %x\n", ne
->ne_rsrctab
);
87 printf( "Resident name table: %x\n", ne
->ne_restab
);
88 printf( "Module table: %x\n", ne
->ne_modtab
);
89 printf( "Import table: %x\n", ne
->ne_imptab
);
90 printf( "Non-resident table: %x\n", ne
->ne_nrestab
);
91 printf( "Exe type: %x\n", ne
->ne_exetyp
);
92 printf( "Other flags: %x\n", ne
->ne_flagsothers
);
93 printf( "Fast load area: %x-%x\n", ne
->ne_pretthunks
<< ne
->ne_align
,
94 (ne
->ne_pretthunks
+ne
->ne_psegrefbytes
) << ne
->ne_align
);
95 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
)
100 const unsigned char *pstr
= (const unsigned char *)ne
+ ne
->ne_restab
;
102 printf( "\nResident name table:\n" );
105 printf( " %4d: %*.*s\n", get_word(pstr
+ *pstr
+ 1), *pstr
, *pstr
, pstr
+ 1 );
106 pstr
+= *pstr
+ 1 + sizeof(WORD
);
108 if (ne
->ne_cbnrestab
)
110 printf( "\nNon-resident name table:\n" );
111 pstr
= PRD(ne
->ne_nrestab
, 0);
114 printf( " %4d: %*.*s\n", get_word(pstr
+ *pstr
+ 1), *pstr
, *pstr
, pstr
+ 1 );
115 pstr
+= *pstr
+ 1 + sizeof(WORD
);
120 static const char *get_resource_type( WORD id
)
122 static char buffer
[5];
125 case NE_RSCTYPE_CURSOR
: return "CURSOR";
126 case NE_RSCTYPE_BITMAP
: return "BITMAP";
127 case NE_RSCTYPE_ICON
: return "ICON";
128 case NE_RSCTYPE_MENU
: return "MENU";
129 case NE_RSCTYPE_DIALOG
: return "DIALOG";
130 case NE_RSCTYPE_STRING
: return "STRING";
131 case NE_RSCTYPE_FONTDIR
: return "FONTDIR";
132 case NE_RSCTYPE_FONT
: return "FONT";
133 case NE_RSCTYPE_ACCELERATOR
: return "ACCELERATOR";
134 case NE_RSCTYPE_RCDATA
: return "RCDATA";
135 case NE_RSCTYPE_GROUP_CURSOR
: return "CURSOR_GROUP";
136 case NE_RSCTYPE_GROUP_ICON
: return "ICON_GROUP";
138 sprintf( buffer
, "%04x", id
);
143 static void dump_ne_resources( const IMAGE_OS2_HEADER
*ne
)
145 const NE_NAMEINFO
*name
;
146 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);
151 printf( "\nResources:\n" );
152 while (info
->type_id
!= 0 && (const char *)info
< (const char *)ne
+ ne
->ne_restab
)
154 name
= (const NE_NAMEINFO
*)(info
+ 1);
155 for (count
= info
->count
; count
> 0; count
--, name
++)
157 if (name
->id
& 0x8000) printf( " %d", (name
->id
& ~0x8000) );
158 else printf( " %.*s", *((const unsigned char *)res_ptr
+ name
->id
),
159 (const char *)res_ptr
+ name
->id
+ 1 );
160 if (info
->type_id
& 0x8000) printf( " %s", get_resource_type(info
->type_id
) );
161 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 name
->length
<< size_shift
, " " );
167 info
= (const NE_TYPEINFO
*)name
;
171 static const char *get_export_name( const IMAGE_OS2_HEADER
*ne
, int ordinal
)
173 static char name
[256];
177 /* search the resident names */
181 if (pass
== 0) /* resident names */
183 pstr
= (const BYTE
*)ne
+ ne
->ne_restab
;
184 if (*pstr
) pstr
+= *pstr
+ 1 + sizeof(WORD
); /* skip first entry (module name) */
186 else /* non-resident names */
188 if (!ne
->ne_cbnrestab
) break;
189 pstr
= PRD(ne
->ne_nrestab
, 0);
193 WORD ord
= get_word(pstr
+ *pstr
+ 1);
196 memcpy( name
, pstr
+ 1, *pstr
);
200 pstr
+= *pstr
+ 1 + sizeof(WORD
);
208 static void dump_ne_exports( const IMAGE_OS2_HEADER
*ne
)
210 const BYTE
*ptr
= (const BYTE
*)ne
+ ne
->ne_enttab
;
211 const BYTE
*end
= ptr
+ ne
->ne_cbenttab
;
214 if (!ne
->ne_cbenttab
|| !*ptr
) return;
216 printf( "\nExported entry points:\n" );
218 while (ptr
< end
&& *ptr
)
224 case 0: /* next bundle */
227 case 0xff: /* movable */
228 for (i
= 0; i
< count
; i
++)
230 printf( " %4d MOVABLE %d:%04x %s\n",
231 ordinal
+ i
, ptr
[3], get_word(ptr
+ 4),
232 get_export_name( ne
, ordinal
+ i
) );
237 case 0xfe: /* constant */
238 for (i
= 0; i
< count
; i
++)
240 printf( " %4d CONST %04x %s\n",
241 ordinal
+ i
, get_word(ptr
+ 1),
242 get_export_name( ne
, ordinal
+ i
) );
248 for (i
= 0; i
< count
; i
++)
250 printf( " %4d FIXED %d:%04x %s\n",
251 ordinal
+ i
, type
, get_word(ptr
+ 1),
252 get_export_name( ne
, ordinal
+ i
) );
261 static const char *get_reloc_name( BYTE addr_type
, int additive
)
263 switch(addr_type
& 0x7f)
265 case NE_RADDR_LOWBYTE
: return additive
? "byte add" : "byte";
266 case NE_RADDR_OFFSET16
: return additive
? "off16 add" : "off16";
267 case NE_RADDR_POINTER32
: return additive
? "ptr32 add" : "ptr32";
268 case NE_RADDR_SELECTOR
: return additive
? "sel add" : "sel";
269 case NE_RADDR_POINTER48
: return additive
? "ptr48 add" : "ptr48";
270 case NE_RADDR_OFFSET32
: return additive
? "off32 add" : "off32";
275 static const char *get_seg_flags( WORD flags
)
277 static char buffer
[256];
280 #define ADD_FLAG(x) if (flags & NE_SEGFLAGS_##x) strcat( buffer, " " #x );
288 ADD_FLAG(EXECUTEONLY
);
290 ADD_FLAG(RELOC_DATA
);
292 ADD_FLAG(DISCARDABLE
);
298 strcat( buffer
, ")" );
303 static void dump_relocations( const IMAGE_OS2_HEADER
*ne
, WORD count
,
304 const struct relocation_entry
*rep
)
306 const WORD
*modref
= (const WORD
*)((const BYTE
*)ne
+ ne
->ne_modtab
);
307 const BYTE
*mod_name
, *func_name
;
310 for (i
= 0; i
< count
; i
++, rep
++)
312 int additive
= rep
->relocation_type
& NE_RELFLAG_ADDITIVE
;
313 switch (rep
->relocation_type
& 3)
315 case NE_RELTYPE_ORDINAL
:
316 mod_name
= (const BYTE
*)ne
+ ne
->ne_imptab
+ modref
[rep
->target1
- 1];
317 printf( "%6d: %s = %*.*s.%d\n", i
+ 1, get_reloc_name( rep
->address_type
, additive
),
318 *mod_name
, *mod_name
, mod_name
+ 1, rep
->target2
);
320 case NE_RELTYPE_NAME
:
321 mod_name
= (const BYTE
*)ne
+ ne
->ne_imptab
+ modref
[rep
->target1
- 1];
322 func_name
= (const BYTE
*)ne
+ ne
->ne_imptab
+ rep
->target2
;
323 printf( "%6d: %s = %*.*s.%*.*s\n", i
+ 1, get_reloc_name( rep
->address_type
, additive
),
324 *mod_name
, *mod_name
, mod_name
+ 1,
325 *func_name
, *func_name
, func_name
+ 1 );
327 case NE_RELTYPE_INTERNAL
:
328 if ((rep
->target1
& 0xff) == 0xff)
330 /* the module itself */
331 mod_name
= (const BYTE
*)ne
+ ne
->ne_restab
;
332 printf( "%6d: %s = %*.*s.%d\n", i
+ 1, get_reloc_name( rep
->address_type
, additive
),
333 *mod_name
, *mod_name
, mod_name
+ 1, rep
->target2
);
336 printf( "%6d: %s = %d:%04x\n", i
+ 1, get_reloc_name( rep
->address_type
, additive
),
337 rep
->target1
, rep
->target2
);
339 case NE_RELTYPE_OSFIXUP
:
340 /* Relocation type 7:
342 * These appear to be used as fixups for the Windows
343 * floating point emulator. Let's just ignore them and
344 * try to use the hardware floating point. Linux should
345 * successfully emulate the coprocessor if it doesn't
348 printf( "%6d: %s = TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
349 i
+ 1, get_reloc_name( rep
->address_type
, additive
),
350 rep
->relocation_type
, rep
->offset
,
351 rep
->target1
, rep
->target2
);
357 static void dump_ne_segment( const IMAGE_OS2_HEADER
*ne
, int segnum
)
359 const struct ne_segtable_entry
*table
= (const struct ne_segtable_entry
*)((const BYTE
*)ne
+ ne
->ne_segtab
);
360 const struct ne_segtable_entry
*seg
= table
+ segnum
- 1;
362 printf( "\nSegment %d:\n", segnum
);
363 printf( " File offset: %08x\n", seg
->seg_data_offset
<< ne
->ne_align
);
364 printf( " Length: %08x\n", seg
->seg_data_length
);
365 printf( " Flags: %08x %s\n", seg
->seg_flags
, get_seg_flags(seg
->seg_flags
) );
366 printf( " Alloc size: %08x\n", seg
->min_alloc
);
367 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 WORD count
= get_word(ptr
);
372 printf( " Relocations:\n" );
373 dump_relocations( ne
, count
, (const struct relocation_entry
*)ptr
);
380 const IMAGE_DOS_HEADER
*dos
;
381 const IMAGE_OS2_HEADER
*ne
;
383 dos
= PRD(0, sizeof(*dos
));
385 ne
= PRD(dos
->e_lfanew
, sizeof(*ne
));
387 if (globals
.do_dumpheader
|| !globals
.dumpsect
)
388 dump_ne_header( ne
);
389 if (globals
.do_dumpheader
)
391 if (globals
.dumpsect
)
393 BOOL all
= strcmp(globals
.dumpsect
, "ALL") == 0;
395 if (all
|| !strcmp(globals
.dumpsect
, "resource"))
396 dump_ne_resources( ne
);
397 if (all
|| !strcmp(globals
.dumpsect
, "export"))
398 dump_ne_exports( ne
);
400 if (globals
.do_dumpheader
)
401 for (i
= 1; i
<= ne
->ne_cseg
; i
++) dump_ne_segment( ne
, i
);