ntdll: Move some duplicated locale definitions to a common header.
[wine.git] / tools / winedump / ne.c
blobec73d16ce0d04759c0b05b9fbb0a2d8143c78ce3
1 /*
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
21 #include "config.h"
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <fcntl.h>
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winedump.h"
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 */
48 typedef struct
50 WORD offset;
51 WORD length;
52 WORD flags;
53 WORD id;
54 WORD handle;
55 WORD usage;
56 } NE_NAMEINFO;
58 typedef struct
60 WORD type_id;
61 WORD count;
62 DWORD resloader;
63 } NE_TYPEINFO;
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", 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", 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" );
143 while (*pstr)
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];
163 switch(id)
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";
177 default:
178 sprintf( buffer, "%04x", id );
179 return buffer;
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);
189 int count;
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];
214 const BYTE *pstr;
215 int pass = 0;
217 /* search the resident names */
219 while (pass < 2)
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);
231 while (*pstr)
233 WORD ord = get_word(pstr + *pstr + 1);
234 if (ord == ordinal)
236 memcpy( name, pstr + 1, *pstr );
237 name[*pstr] = 0;
238 return name;
240 pstr += *pstr + 1 + sizeof(WORD);
242 pass++;
244 name[0] = 0;
245 return name;
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;
252 int i, ordinal = 1;
254 if (!ne->ne_cbenttab || !*ptr) return;
256 printf( "\nExported entry points:\n" );
258 while (ptr < end && *ptr)
260 BYTE count = *ptr++;
261 BYTE type = *ptr++;
262 switch(type)
264 case 0: /* next bundle */
265 ordinal += count;
266 break;
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 ) );
273 ptr += 6;
275 ordinal += count;
276 break;
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 ) );
283 ptr += 3;
285 ordinal += count;
286 break;
287 default: /* fixed */
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 ) );
293 ptr += 3;
295 ordinal += count;
296 break;
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";
312 return "???";
315 static const char *get_seg_flags( WORD flags )
317 static char buffer[256];
319 buffer[0] = 0;
320 #define ADD_FLAG(x) if (flags & NE_SEGFLAGS_##x) strcat( buffer, " " #x );
321 ADD_FLAG(DATA);
322 ADD_FLAG(ALLOCATED);
323 ADD_FLAG(LOADED);
324 ADD_FLAG(ITERATED);
325 ADD_FLAG(MOVEABLE);
326 ADD_FLAG(SHAREABLE);
327 ADD_FLAG(PRELOAD);
328 ADD_FLAG(EXECUTEONLY);
329 ADD_FLAG(READONLY);
330 ADD_FLAG(RELOC_DATA);
331 ADD_FLAG(SELFLOAD);
332 ADD_FLAG(DISCARDABLE);
333 ADD_FLAG(32BIT);
334 #undef ADD_FLAG
335 if (buffer[0])
337 buffer[0] = '(';
338 strcat( buffer, ")" );
340 return 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;
348 WORD i;
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 );
359 break;
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 );
366 break;
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 );
375 else
376 printf( "%6d: %s = %d:%04x\n", i + 1, get_reloc_name( rep->address_type, additive ),
377 rep->target1, rep->target2 );
378 break;
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
386 * exist.
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 );
392 break;
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);
411 ptr += sizeof(WORD);
412 printf( " Relocations:\n" );
413 dump_relocations( ne, count, (const struct relocation_entry *)ptr );
417 void ne_dump( void )
419 unsigned int i;
420 const IMAGE_DOS_HEADER *dos;
421 const IMAGE_OS2_HEADER *ne;
423 dos = PRD(0, sizeof(*dos));
424 if (!dos) return;
425 ne = PRD(dos->e_lfanew, sizeof(*ne));
426 print_fake_dll();
428 if (globals.do_dumpheader || !globals.dumpsect)
429 dump_ne_header( ne );
430 if (globals.do_dumpheader)
431 dump_ne_names( ne );
432 if (globals.dumpsect)
434 BOOL all = strcmp(globals.dumpsect, "ALL") == 0;
436 if (all || !strcmp(globals.dumpsect, "resource"))
437 dump_ne_resources( ne );
438 if (all || !strcmp(globals.dumpsect, "export"))
439 dump_ne_exports( ne );
441 if (globals.do_dumpheader)
442 for (i = 1; i <= ne->ne_cseg; i++) dump_ne_segment( ne, i );