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"
35 struct ne_segtable_entry
37 WORD seg_data_offset
; /* Sector offset of segment data */
38 WORD seg_data_length
; /* Length of segment data */
39 WORD seg_flags
; /* Flags associated with this segment */
40 WORD min_alloc
; /* Minimum allocation size for this */
43 struct relocation_entry
45 BYTE address_type
; /* Relocation address type */
46 BYTE relocation_type
; /* Relocation type */
47 WORD offset
; /* Offset in segment to fixup */
48 WORD target1
; /* Target specification */
49 WORD target2
; /* Target specification */
69 #define NE_RADDR_LOWBYTE 0
70 #define NE_RADDR_SELECTOR 2
71 #define NE_RADDR_POINTER32 3
72 #define NE_RADDR_OFFSET16 5
73 #define NE_RADDR_POINTER48 11
74 #define NE_RADDR_OFFSET32 13
76 #define NE_RELTYPE_INTERNAL 0
77 #define NE_RELTYPE_ORDINAL 1
78 #define NE_RELTYPE_NAME 2
79 #define NE_RELTYPE_OSFIXUP 3
80 #define NE_RELFLAG_ADDITIVE 4
82 #define NE_SEGFLAGS_DATA 0x0001
83 #define NE_SEGFLAGS_ALLOCATED 0x0002
84 #define NE_SEGFLAGS_LOADED 0x0004
85 #define NE_SEGFLAGS_ITERATED 0x0008
86 #define NE_SEGFLAGS_MOVEABLE 0x0010
87 #define NE_SEGFLAGS_SHAREABLE 0x0020
88 #define NE_SEGFLAGS_PRELOAD 0x0040
89 #define NE_SEGFLAGS_EXECUTEONLY 0x0080
90 #define NE_SEGFLAGS_READONLY 0x0080
91 #define NE_SEGFLAGS_RELOC_DATA 0x0100
92 #define NE_SEGFLAGS_SELFLOAD 0x0800
93 #define NE_SEGFLAGS_DISCARDABLE 0x1000
94 #define NE_SEGFLAGS_32BIT 0x2000
96 #define NE_RSCTYPE_CURSOR 0x8001
97 #define NE_RSCTYPE_BITMAP 0x8002
98 #define NE_RSCTYPE_ICON 0x8003
99 #define NE_RSCTYPE_MENU 0x8004
100 #define NE_RSCTYPE_DIALOG 0x8005
101 #define NE_RSCTYPE_STRING 0x8006
102 #define NE_RSCTYPE_FONTDIR 0x8007
103 #define NE_RSCTYPE_FONT 0x8008
104 #define NE_RSCTYPE_ACCELERATOR 0x8009
105 #define NE_RSCTYPE_RCDATA 0x800a
106 #define NE_RSCTYPE_GROUP_CURSOR 0x800c
107 #define NE_RSCTYPE_GROUP_ICON 0x800e
108 #define NE_RSCTYPE_SCALABLE_FONTPATH 0x80cc
110 static inline WORD
get_word( const BYTE
*ptr
)
112 return ptr
[0] | (ptr
[1] << 8);
115 static void dump_ne_header( const IMAGE_OS2_HEADER
*ne
)
117 printf( "File header:\n" );
118 printf( "Linker version: %d.%d\n", ne
->ne_ver
, ne
->ne_rev
);
119 printf( "Entry table: %x len %d\n", ne
->ne_enttab
, ne
->ne_cbenttab
);
120 printf( "Checksum: %08x\n", ne
->ne_crc
);
121 printf( "Flags: %04x\n", ne
->ne_flags
);
122 printf( "Auto data segment: %x\n", ne
->ne_autodata
);
123 printf( "Heap size: %d bytes\n", ne
->ne_heap
);
124 printf( "Stack size: %d bytes\n", ne
->ne_stack
);
125 printf( "Stack pointer: %x:%04x\n", HIWORD(ne
->ne_sssp
), LOWORD(ne
->ne_sssp
) );
126 printf( "Entry point: %x:%04x\n", HIWORD(ne
->ne_csip
), LOWORD(ne
->ne_csip
) );
127 printf( "Number of segments: %d\n", ne
->ne_cseg
);
128 printf( "Number of modrefs: %d\n", ne
->ne_cmod
);
129 printf( "Segment table: %x\n", ne
->ne_segtab
);
130 printf( "Resource table: %x\n", ne
->ne_rsrctab
);
131 printf( "Resident name table: %x\n", ne
->ne_restab
);
132 printf( "Module table: %x\n", ne
->ne_modtab
);
133 printf( "Import table: %x\n", ne
->ne_imptab
);
134 printf( "Non-resident table: %x\n", ne
->ne_nrestab
);
135 printf( "Exe type: %x\n", ne
->ne_exetyp
);
136 printf( "Other flags: %x\n", ne
->ne_flagsothers
);
137 printf( "Fast load area: %x-%x\n", ne
->ne_pretthunks
<< ne
->ne_align
,
138 (ne
->ne_pretthunks
+ne
->ne_psegrefbytes
) << ne
->ne_align
);
139 printf( "Expected version: %d.%d\n", HIBYTE(ne
->ne_expver
), LOBYTE(ne
->ne_expver
) );
142 static void dump_ne_names( const IMAGE_OS2_HEADER
*ne
)
144 const unsigned char *pstr
= (const unsigned char *)ne
+ ne
->ne_restab
;
146 printf( "\nResident name table:\n" );
149 printf( " %4d: %*.*s\n", get_word(pstr
+ *pstr
+ 1), *pstr
, *pstr
, pstr
+ 1 );
150 pstr
+= *pstr
+ 1 + sizeof(WORD
);
152 if (ne
->ne_cbnrestab
)
154 unsigned int pos
= ne
->ne_nrestab
;
155 printf( "\nNon-resident name table:\n" );
156 while ((pstr
= PRD(pos
, 0)) && *pstr
)
158 printf( " %4d: %*.*s\n", get_word(pstr
+ *pstr
+ 1), *pstr
, *pstr
, pstr
+ 1 );
159 pos
+= *pstr
+ 1 + sizeof(WORD
);
164 static const char *get_resource_type( WORD id
)
166 static char buffer
[5];
169 case NE_RSCTYPE_CURSOR
: return "CURSOR";
170 case NE_RSCTYPE_BITMAP
: return "BITMAP";
171 case NE_RSCTYPE_ICON
: return "ICON";
172 case NE_RSCTYPE_MENU
: return "MENU";
173 case NE_RSCTYPE_DIALOG
: return "DIALOG";
174 case NE_RSCTYPE_STRING
: return "STRING";
175 case NE_RSCTYPE_FONTDIR
: return "FONTDIR";
176 case NE_RSCTYPE_FONT
: return "FONT";
177 case NE_RSCTYPE_ACCELERATOR
: return "ACCELERATOR";
178 case NE_RSCTYPE_RCDATA
: return "RCDATA";
179 case NE_RSCTYPE_GROUP_CURSOR
: return "CURSOR_GROUP";
180 case NE_RSCTYPE_GROUP_ICON
: return "ICON_GROUP";
182 sprintf( buffer
, "%04x", id
);
187 static void dump_ne_resources( const IMAGE_OS2_HEADER
*ne
)
189 const NE_NAMEINFO
*name
;
190 const void *res_ptr
= (const char *)ne
+ ne
->ne_rsrctab
;
191 WORD size_shift
= get_word(res_ptr
);
192 const NE_TYPEINFO
*info
= (const NE_TYPEINFO
*)((const WORD
*)res_ptr
+ 1);
195 printf( "\nResources:\n" );
196 while (info
->type_id
!= 0 && (const char *)info
< (const char *)ne
+ ne
->ne_restab
)
198 name
= (const NE_NAMEINFO
*)(info
+ 1);
199 for (count
= info
->count
; count
> 0; count
--, name
++)
201 if (name
->id
& 0x8000) printf( " %d", (name
->id
& ~0x8000) );
202 else printf( " %.*s", *((const unsigned char *)res_ptr
+ name
->id
),
203 (const char *)res_ptr
+ name
->id
+ 1 );
204 if (info
->type_id
& 0x8000) printf( " %s", get_resource_type(info
->type_id
) );
205 else printf( " %.*s", *((const unsigned char *)res_ptr
+ info
->type_id
),
206 (const char *)res_ptr
+ info
->type_id
+ 1 );
207 printf(" flags %04x length %04x\n", name
->flags
, name
->length
<< size_shift
);
208 dump_data( PRD(name
->offset
<< size_shift
, name
->length
<< size_shift
),
209 name
->length
<< size_shift
, " " );
211 info
= (const NE_TYPEINFO
*)name
;
215 static const char *get_export_name( const IMAGE_OS2_HEADER
*ne
, int ordinal
)
217 static char name
[256];
221 /* search the resident names */
225 if (pass
== 0) /* resident names */
227 pstr
= (const BYTE
*)ne
+ ne
->ne_restab
;
228 if (*pstr
) pstr
+= *pstr
+ 1 + sizeof(WORD
); /* skip first entry (module name) */
230 else /* non-resident names */
232 if (!ne
->ne_cbnrestab
) break;
233 pstr
= PRD(ne
->ne_nrestab
, 0);
237 WORD ord
= get_word(pstr
+ *pstr
+ 1);
240 memcpy( name
, pstr
+ 1, *pstr
);
244 pstr
+= *pstr
+ 1 + sizeof(WORD
);
252 static void dump_ne_exports( const IMAGE_OS2_HEADER
*ne
)
254 const BYTE
*ptr
= (const BYTE
*)ne
+ ne
->ne_enttab
;
255 const BYTE
*end
= ptr
+ ne
->ne_cbenttab
;
258 if (!ne
->ne_cbenttab
|| !*ptr
) return;
260 printf( "\nExported entry points:\n" );
262 while (ptr
< end
&& *ptr
)
268 case 0: /* next bundle */
271 case 0xff: /* movable */
272 for (i
= 0; i
< count
; i
++)
274 printf( " %4d MOVABLE %d:%04x %s\n",
275 ordinal
+ i
, ptr
[3], get_word(ptr
+ 4),
276 get_export_name( ne
, ordinal
+ i
) );
281 case 0xfe: /* constant */
282 for (i
= 0; i
< count
; i
++)
284 printf( " %4d CONST %04x %s\n",
285 ordinal
+ i
, get_word(ptr
+ 1),
286 get_export_name( ne
, ordinal
+ i
) );
292 for (i
= 0; i
< count
; i
++)
294 printf( " %4d FIXED %d:%04x %s\n",
295 ordinal
+ i
, type
, get_word(ptr
+ 1),
296 get_export_name( ne
, ordinal
+ i
) );
305 static const char *get_reloc_name( BYTE addr_type
, int additive
)
307 switch(addr_type
& 0x7f)
309 case NE_RADDR_LOWBYTE
: return additive
? "byte add" : "byte";
310 case NE_RADDR_OFFSET16
: return additive
? "off16 add" : "off16";
311 case NE_RADDR_POINTER32
: return additive
? "ptr32 add" : "ptr32";
312 case NE_RADDR_SELECTOR
: return additive
? "sel add" : "sel";
313 case NE_RADDR_POINTER48
: return additive
? "ptr48 add" : "ptr48";
314 case NE_RADDR_OFFSET32
: return additive
? "off32 add" : "off32";
319 static const char *get_seg_flags( WORD flags
)
321 static char buffer
[256];
324 #define ADD_FLAG(x) if (flags & NE_SEGFLAGS_##x) strcat( buffer, " " #x );
332 ADD_FLAG(EXECUTEONLY
);
334 ADD_FLAG(RELOC_DATA
);
336 ADD_FLAG(DISCARDABLE
);
342 strcat( buffer
, ")" );
347 static void dump_relocations( const IMAGE_OS2_HEADER
*ne
, WORD count
,
348 const struct relocation_entry
*rep
)
350 const WORD
*modref
= (const WORD
*)((const BYTE
*)ne
+ ne
->ne_modtab
);
351 const BYTE
*mod_name
, *func_name
;
354 for (i
= 0; i
< count
; i
++, rep
++)
356 int additive
= rep
->relocation_type
& NE_RELFLAG_ADDITIVE
;
357 switch (rep
->relocation_type
& 3)
359 case NE_RELTYPE_ORDINAL
:
360 mod_name
= (const BYTE
*)ne
+ ne
->ne_imptab
+ modref
[rep
->target1
- 1];
361 printf( "%6d: %s = %*.*s.%d\n", i
+ 1, get_reloc_name( rep
->address_type
, additive
),
362 *mod_name
, *mod_name
, mod_name
+ 1, rep
->target2
);
364 case NE_RELTYPE_NAME
:
365 mod_name
= (const BYTE
*)ne
+ ne
->ne_imptab
+ modref
[rep
->target1
- 1];
366 func_name
= (const BYTE
*)ne
+ ne
->ne_imptab
+ rep
->target2
;
367 printf( "%6d: %s = %*.*s.%*.*s\n", i
+ 1, get_reloc_name( rep
->address_type
, additive
),
368 *mod_name
, *mod_name
, mod_name
+ 1,
369 *func_name
, *func_name
, func_name
+ 1 );
371 case NE_RELTYPE_INTERNAL
:
372 if ((rep
->target1
& 0xff) == 0xff)
374 /* the module itself */
375 mod_name
= (const BYTE
*)ne
+ ne
->ne_restab
;
376 printf( "%6d: %s = %*.*s.%d\n", i
+ 1, get_reloc_name( rep
->address_type
, additive
),
377 *mod_name
, *mod_name
, mod_name
+ 1, rep
->target2
);
380 printf( "%6d: %s = %d:%04x\n", i
+ 1, get_reloc_name( rep
->address_type
, additive
),
381 rep
->target1
, rep
->target2
);
383 case NE_RELTYPE_OSFIXUP
:
384 /* Relocation type 7:
386 * These appear to be used as fixups for the Windows
387 * floating point emulator. Let's just ignore them and
388 * try to use the hardware floating point. Linux should
389 * successfully emulate the coprocessor if it doesn't
392 printf( "%6d: %s = TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
393 i
+ 1, get_reloc_name( rep
->address_type
, additive
),
394 rep
->relocation_type
, rep
->offset
,
395 rep
->target1
, rep
->target2
);
401 static void dump_ne_segment( const IMAGE_OS2_HEADER
*ne
, int segnum
)
403 const struct ne_segtable_entry
*table
= (const struct ne_segtable_entry
*)((const BYTE
*)ne
+ ne
->ne_segtab
);
404 const struct ne_segtable_entry
*seg
= table
+ segnum
- 1;
406 printf( "\nSegment %d:\n", segnum
);
407 printf( " File offset: %08x\n", seg
->seg_data_offset
<< ne
->ne_align
);
408 printf( " Length: %08x\n", seg
->seg_data_length
);
409 printf( " Flags: %08x %s\n", seg
->seg_flags
, get_seg_flags(seg
->seg_flags
) );
410 printf( " Alloc size: %08x\n", seg
->min_alloc
);
411 if (seg
->seg_flags
& NE_SEGFLAGS_RELOC_DATA
)
413 const BYTE
*ptr
= PRD((seg
->seg_data_offset
<< ne
->ne_align
) + seg
->seg_data_length
, 0);
414 WORD count
= get_word(ptr
);
416 printf( " Relocations:\n" );
417 dump_relocations( ne
, count
, (const struct relocation_entry
*)ptr
);
424 const IMAGE_DOS_HEADER
*dos
;
425 const IMAGE_OS2_HEADER
*ne
;
427 dos
= PRD(0, sizeof(*dos
));
429 ne
= PRD(dos
->e_lfanew
, sizeof(*ne
));
432 if (globals
.do_dumpheader
|| !globals
.dumpsect
)
433 dump_ne_header( ne
);
434 if (globals
.do_dumpheader
)
436 if (globals
.dumpsect
)
438 BOOL all
= strcmp(globals
.dumpsect
, "ALL") == 0;
440 if (all
|| !strcmp(globals
.dumpsect
, "resource"))
441 dump_ne_resources( ne
);
442 if (all
|| !strcmp(globals
.dumpsect
, "export"))
443 dump_ne_exports( ne
);
445 if (globals
.do_dumpheader
)
446 for (i
= 1; i
<= ne
->ne_cseg
; i
++) dump_ne_segment( ne
, i
);