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
31 struct ne_segtable_entry
33 WORD seg_data_offset
; /* Sector offset of segment data */
34 WORD seg_data_length
; /* Length of segment data */
35 WORD seg_flags
; /* Flags associated with this segment */
36 WORD min_alloc
; /* Minimum allocation size for this */
39 struct relocation_entry
41 BYTE address_type
; /* Relocation address type */
42 BYTE relocation_type
; /* Relocation type */
43 WORD offset
; /* Offset in segment to fixup */
44 WORD target1
; /* Target specification */
45 WORD target2
; /* Target specification */
65 #define NE_RADDR_LOWBYTE 0
66 #define NE_RADDR_SELECTOR 2
67 #define NE_RADDR_POINTER32 3
68 #define NE_RADDR_OFFSET16 5
69 #define NE_RADDR_POINTER48 11
70 #define NE_RADDR_OFFSET32 13
72 #define NE_RELTYPE_INTERNAL 0
73 #define NE_RELTYPE_ORDINAL 1
74 #define NE_RELTYPE_NAME 2
75 #define NE_RELTYPE_OSFIXUP 3
76 #define NE_RELFLAG_ADDITIVE 4
78 #define NE_SEGFLAGS_DATA 0x0001
79 #define NE_SEGFLAGS_ALLOCATED 0x0002
80 #define NE_SEGFLAGS_LOADED 0x0004
81 #define NE_SEGFLAGS_ITERATED 0x0008
82 #define NE_SEGFLAGS_MOVEABLE 0x0010
83 #define NE_SEGFLAGS_SHAREABLE 0x0020
84 #define NE_SEGFLAGS_PRELOAD 0x0040
85 #define NE_SEGFLAGS_EXECUTEONLY 0x0080
86 #define NE_SEGFLAGS_READONLY 0x0080
87 #define NE_SEGFLAGS_RELOC_DATA 0x0100
88 #define NE_SEGFLAGS_SELFLOAD 0x0800
89 #define NE_SEGFLAGS_DISCARDABLE 0x1000
90 #define NE_SEGFLAGS_32BIT 0x2000
92 #define NE_RSCTYPE_CURSOR 0x8001
93 #define NE_RSCTYPE_BITMAP 0x8002
94 #define NE_RSCTYPE_ICON 0x8003
95 #define NE_RSCTYPE_MENU 0x8004
96 #define NE_RSCTYPE_DIALOG 0x8005
97 #define NE_RSCTYPE_STRING 0x8006
98 #define NE_RSCTYPE_FONTDIR 0x8007
99 #define NE_RSCTYPE_FONT 0x8008
100 #define NE_RSCTYPE_ACCELERATOR 0x8009
101 #define NE_RSCTYPE_RCDATA 0x800a
102 #define NE_RSCTYPE_GROUP_CURSOR 0x800c
103 #define NE_RSCTYPE_GROUP_ICON 0x800e
104 #define NE_RSCTYPE_SCALABLE_FONTPATH 0x80cc
106 static inline WORD
get_word( const BYTE
*ptr
)
108 return ptr
[0] | (ptr
[1] << 8);
111 static void dump_ne_header( const IMAGE_OS2_HEADER
*ne
)
113 printf( "File header:\n" );
114 printf( "Linker version: %d.%d\n", ne
->ne_ver
, ne
->ne_rev
);
115 printf( "Entry table: %x len %d\n", ne
->ne_enttab
, ne
->ne_cbenttab
);
116 printf( "Checksum: %08x\n", (UINT
)ne
->ne_crc
);
117 printf( "Flags: %04x\n", ne
->ne_flags
);
118 printf( "Auto data segment: %x\n", ne
->ne_autodata
);
119 printf( "Heap size: %d bytes\n", ne
->ne_heap
);
120 printf( "Stack size: %d bytes\n", ne
->ne_stack
);
121 printf( "Stack pointer: %x:%04x\n", HIWORD(ne
->ne_sssp
), LOWORD(ne
->ne_sssp
) );
122 printf( "Entry point: %x:%04x\n", HIWORD(ne
->ne_csip
), LOWORD(ne
->ne_csip
) );
123 printf( "Number of segments: %d\n", ne
->ne_cseg
);
124 printf( "Number of modrefs: %d\n", ne
->ne_cmod
);
125 printf( "Segment table: %x\n", ne
->ne_segtab
);
126 printf( "Resource table: %x\n", ne
->ne_rsrctab
);
127 printf( "Resident name table: %x\n", ne
->ne_restab
);
128 printf( "Module table: %x\n", ne
->ne_modtab
);
129 printf( "Import table: %x\n", ne
->ne_imptab
);
130 printf( "Non-resident table: %x\n", (UINT
)ne
->ne_nrestab
);
131 printf( "Exe type: %x\n", ne
->ne_exetyp
);
132 printf( "Other flags: %x\n", ne
->ne_flagsothers
);
133 printf( "Fast load area: %x-%x\n", ne
->ne_pretthunks
<< ne
->ne_align
,
134 (ne
->ne_pretthunks
+ne
->ne_psegrefbytes
) << ne
->ne_align
);
135 printf( "Expected version: %d.%d\n", HIBYTE(ne
->ne_expver
), LOBYTE(ne
->ne_expver
) );
138 static void dump_ne_names( const IMAGE_OS2_HEADER
*ne
)
140 const unsigned char *pstr
= (const unsigned char *)ne
+ ne
->ne_restab
;
142 printf( "\nResident name table:\n" );
145 printf( " %4d: %*.*s\n", get_word(pstr
+ *pstr
+ 1), *pstr
, *pstr
, pstr
+ 1 );
146 pstr
+= *pstr
+ 1 + sizeof(WORD
);
148 if (ne
->ne_cbnrestab
)
150 unsigned int pos
= ne
->ne_nrestab
;
151 printf( "\nNon-resident name table:\n" );
152 while ((pstr
= PRD(pos
, 0)) && *pstr
)
154 printf( " %4d: %*.*s\n", get_word(pstr
+ *pstr
+ 1), *pstr
, *pstr
, pstr
+ 1 );
155 pos
+= *pstr
+ 1 + sizeof(WORD
);
160 static const char *get_resource_type( WORD id
)
162 static char buffer
[5];
165 case NE_RSCTYPE_CURSOR
: return "CURSOR";
166 case NE_RSCTYPE_BITMAP
: return "BITMAP";
167 case NE_RSCTYPE_ICON
: return "ICON";
168 case NE_RSCTYPE_MENU
: return "MENU";
169 case NE_RSCTYPE_DIALOG
: return "DIALOG";
170 case NE_RSCTYPE_STRING
: return "STRING";
171 case NE_RSCTYPE_FONTDIR
: return "FONTDIR";
172 case NE_RSCTYPE_FONT
: return "FONT";
173 case NE_RSCTYPE_ACCELERATOR
: return "ACCELERATOR";
174 case NE_RSCTYPE_RCDATA
: return "RCDATA";
175 case NE_RSCTYPE_GROUP_CURSOR
: return "CURSOR_GROUP";
176 case NE_RSCTYPE_GROUP_ICON
: return "ICON_GROUP";
178 sprintf( buffer
, "%04x", id
);
183 static void dump_ne_resources( const IMAGE_OS2_HEADER
*ne
)
185 const NE_NAMEINFO
*name
;
186 const void *res_ptr
= (const char *)ne
+ ne
->ne_rsrctab
;
187 WORD size_shift
= get_word(res_ptr
);
188 const NE_TYPEINFO
*info
= (const NE_TYPEINFO
*)((const WORD
*)res_ptr
+ 1);
191 printf( "\nResources:\n" );
192 while (info
->type_id
!= 0 && (const char *)info
< (const char *)ne
+ ne
->ne_restab
)
194 name
= (const NE_NAMEINFO
*)(info
+ 1);
195 for (count
= info
->count
; count
> 0; count
--, name
++)
197 if (name
->id
& 0x8000) printf( " %d", (name
->id
& ~0x8000) );
198 else printf( " %.*s", *((const unsigned char *)res_ptr
+ name
->id
),
199 (const char *)res_ptr
+ name
->id
+ 1 );
200 if (info
->type_id
& 0x8000) printf( " %s", get_resource_type(info
->type_id
) );
201 else printf( " %.*s", *((const unsigned char *)res_ptr
+ info
->type_id
),
202 (const char *)res_ptr
+ info
->type_id
+ 1 );
203 printf(" flags %04x length %04x\n", name
->flags
, name
->length
<< size_shift
);
204 dump_data( PRD(name
->offset
<< size_shift
, name
->length
<< size_shift
),
205 name
->length
<< size_shift
, " " );
207 info
= (const NE_TYPEINFO
*)name
;
211 static const char *get_export_name( const IMAGE_OS2_HEADER
*ne
, int ordinal
)
213 static char name
[256];
217 /* search the resident names */
221 if (pass
== 0) /* resident names */
223 pstr
= (const BYTE
*)ne
+ ne
->ne_restab
;
224 if (*pstr
) pstr
+= *pstr
+ 1 + sizeof(WORD
); /* skip first entry (module name) */
226 else /* non-resident names */
228 if (!ne
->ne_cbnrestab
) break;
229 pstr
= PRD(ne
->ne_nrestab
, 0);
233 WORD ord
= get_word(pstr
+ *pstr
+ 1);
236 memcpy( name
, pstr
+ 1, *pstr
);
240 pstr
+= *pstr
+ 1 + sizeof(WORD
);
248 static void dump_ne_exports( const IMAGE_OS2_HEADER
*ne
)
250 const BYTE
*ptr
= (const BYTE
*)ne
+ ne
->ne_enttab
;
251 const BYTE
*end
= ptr
+ ne
->ne_cbenttab
;
254 if (!ne
->ne_cbenttab
|| !*ptr
) return;
256 printf( "\nExported entry points:\n" );
258 while (ptr
< end
&& *ptr
)
264 case 0: /* next bundle */
267 case 0xff: /* movable */
268 for (i
= 0; i
< count
; i
++)
270 printf( " %4d MOVABLE %d:%04x %s\n",
271 ordinal
+ i
, ptr
[3], get_word(ptr
+ 4),
272 get_export_name( ne
, ordinal
+ i
) );
277 case 0xfe: /* constant */
278 for (i
= 0; i
< count
; i
++)
280 printf( " %4d CONST %04x %s\n",
281 ordinal
+ i
, get_word(ptr
+ 1),
282 get_export_name( ne
, ordinal
+ i
) );
288 for (i
= 0; i
< count
; i
++)
290 printf( " %4d FIXED %d:%04x %s\n",
291 ordinal
+ i
, type
, get_word(ptr
+ 1),
292 get_export_name( ne
, ordinal
+ i
) );
301 static const char *get_reloc_name( BYTE addr_type
, int additive
)
303 switch(addr_type
& 0x7f)
305 case NE_RADDR_LOWBYTE
: return additive
? "byte add" : "byte";
306 case NE_RADDR_OFFSET16
: return additive
? "off16 add" : "off16";
307 case NE_RADDR_POINTER32
: return additive
? "ptr32 add" : "ptr32";
308 case NE_RADDR_SELECTOR
: return additive
? "sel add" : "sel";
309 case NE_RADDR_POINTER48
: return additive
? "ptr48 add" : "ptr48";
310 case NE_RADDR_OFFSET32
: return additive
? "off32 add" : "off32";
315 static const char *get_seg_flags( WORD flags
)
317 static char buffer
[256];
320 #define ADD_FLAG(x) if (flags & NE_SEGFLAGS_##x) strcat( buffer, " " #x );
328 ADD_FLAG(EXECUTEONLY
);
330 ADD_FLAG(RELOC_DATA
);
332 ADD_FLAG(DISCARDABLE
);
338 strcat( buffer
, ")" );
343 static void dump_relocations( const IMAGE_OS2_HEADER
*ne
, WORD count
,
344 const struct relocation_entry
*rep
)
346 const WORD
*modref
= (const WORD
*)((const BYTE
*)ne
+ ne
->ne_modtab
);
347 const BYTE
*mod_name
, *func_name
;
350 for (i
= 0; i
< count
; i
++, rep
++)
352 int additive
= rep
->relocation_type
& NE_RELFLAG_ADDITIVE
;
353 switch (rep
->relocation_type
& 3)
355 case NE_RELTYPE_ORDINAL
:
356 mod_name
= (const BYTE
*)ne
+ ne
->ne_imptab
+ modref
[rep
->target1
- 1];
357 printf( "%6d: %s = %*.*s.%d\n", i
+ 1, get_reloc_name( rep
->address_type
, additive
),
358 *mod_name
, *mod_name
, mod_name
+ 1, rep
->target2
);
360 case NE_RELTYPE_NAME
:
361 mod_name
= (const BYTE
*)ne
+ ne
->ne_imptab
+ modref
[rep
->target1
- 1];
362 func_name
= (const BYTE
*)ne
+ ne
->ne_imptab
+ rep
->target2
;
363 printf( "%6d: %s = %*.*s.%*.*s\n", i
+ 1, get_reloc_name( rep
->address_type
, additive
),
364 *mod_name
, *mod_name
, mod_name
+ 1,
365 *func_name
, *func_name
, func_name
+ 1 );
367 case NE_RELTYPE_INTERNAL
:
368 if ((rep
->target1
& 0xff) == 0xff)
370 /* the module itself */
371 mod_name
= (const BYTE
*)ne
+ ne
->ne_restab
;
372 printf( "%6d: %s = %*.*s.%d\n", i
+ 1, get_reloc_name( rep
->address_type
, additive
),
373 *mod_name
, *mod_name
, mod_name
+ 1, rep
->target2
);
376 printf( "%6d: %s = %d:%04x\n", i
+ 1, get_reloc_name( rep
->address_type
, additive
),
377 rep
->target1
, rep
->target2
);
379 case NE_RELTYPE_OSFIXUP
:
380 /* Relocation type 7:
382 * These appear to be used as fixups for the Windows
383 * floating point emulator. Let's just ignore them and
384 * try to use the hardware floating point. Linux should
385 * successfully emulate the coprocessor if it doesn't
388 printf( "%6d: %s = TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
389 i
+ 1, get_reloc_name( rep
->address_type
, additive
),
390 rep
->relocation_type
, rep
->offset
,
391 rep
->target1
, rep
->target2
);
397 static void dump_ne_segment( const IMAGE_OS2_HEADER
*ne
, int segnum
)
399 const struct ne_segtable_entry
*table
= (const struct ne_segtable_entry
*)((const BYTE
*)ne
+ ne
->ne_segtab
);
400 const struct ne_segtable_entry
*seg
= table
+ segnum
- 1;
402 printf( "\nSegment %d:\n", segnum
);
403 printf( " File offset: %08x\n", seg
->seg_data_offset
<< ne
->ne_align
);
404 printf( " Length: %08x\n", seg
->seg_data_length
);
405 printf( " Flags: %08x %s\n", seg
->seg_flags
, get_seg_flags(seg
->seg_flags
) );
406 printf( " Alloc size: %08x\n", seg
->min_alloc
);
407 if (seg
->seg_flags
& NE_SEGFLAGS_RELOC_DATA
)
409 const BYTE
*ptr
= PRD((seg
->seg_data_offset
<< ne
->ne_align
) + seg
->seg_data_length
, 0);
410 WORD count
= get_word(ptr
);
412 printf( " Relocations:\n" );
413 dump_relocations( ne
, count
, (const struct relocation_entry
*)ptr
);
420 const IMAGE_DOS_HEADER
*dos
;
421 const IMAGE_OS2_HEADER
*ne
;
423 dos
= PRD(0, sizeof(*dos
));
425 ne
= PRD(dos
->e_lfanew
, sizeof(*ne
));
428 if (globals
.do_dumpheader
|| !globals
.dumpsect
)
429 dump_ne_header( ne
);
430 if (globals
.do_dumpheader
)
433 if (globals_dump_sect("resource"))
434 dump_ne_resources( ne
);
435 if (globals_dump_sect("export"))
436 dump_ne_exports( ne
);
437 if (globals
.do_dumpheader
)
438 for (i
= 1; i
<= ne
->ne_cseg
; i
++) dump_ne_segment( ne
, i
);