Added dumping of NE segments and relocations.

diff --git a/tools/winedump/ne.c b/tools/winedump/ne.c
index 5ad66af..02af56b 100644
--- a/tools/winedump/ne.c
+++ b/tools/winedump/ne.c
@@ -33,6 +33,36 @@
 #include "wine/winbase16.h"
 #include "winedump.h"
 
+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
+
 static inline WORD get_word( const BYTE *ptr )
 {
     return ptr[0] | (ptr[1] << 8);
@@ -228,8 +258,125 @@
     }
 }
 
+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;
+}
+
+static void dump_relocations( const void *base, const IMAGE_OS2_HEADER *ne, WORD count,
+                              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;
+        }
+    }
+}
+
+static void dump_ne_segment( const void *base, const IMAGE_OS2_HEADER *ne, int segnum )
+{
+    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)
+    {
+        const BYTE *ptr = (const BYTE *)base + (seg->seg_data_offset << ne->ne_align) + seg->seg_data_length;
+        WORD count = get_word(ptr);
+        ptr += sizeof(WORD);
+        printf( "  Relocations:\n" );
+        dump_relocations( base, ne, count, (const struct relocation_entry *)ptr );
+    }
+}
+
 void ne_dump( const void *exe, size_t exe_size )
 {
+    unsigned int i;
     const IMAGE_DOS_HEADER *dos = exe;
     const IMAGE_OS2_HEADER *ne = (const IMAGE_OS2_HEADER *)((const char *)dos + dos->e_lfanew);
 
@@ -237,4 +384,5 @@
     dump_ne_names( exe, ne );
     dump_ne_resources( exe, ne );
     dump_ne_exports( exe, ne );
+    for (i = 1; i <= ne->ne_cseg; i++) dump_ne_segment( exe, ne, i );
 }