]> granicus.if.org Git - yasm/commitdiff
First cut at CodeView (version "8" / 2005 only). Completely untested.
authorPeter Johnson <peter@tortall.net>
Mon, 27 Mar 2006 02:15:19 +0000 (02:15 -0000)
committerPeter Johnson <peter@tortall.net>
Mon, 27 Mar 2006 02:15:19 +0000 (02:15 -0000)
* md5.c, md5.h: Import MD5 from public domain version in CVS source.
* libyasm/Makefile.inc: Attach to libyasm build.
* libyasm.h: Include md5.h.

* coretype.h (yasm_value): Add new section_rel member.
* value.h (yasm_value_init, yasm_value_init_sym): Initialize.
* value.c (yasm_value_output_basic): Don't output if set.
* xdf-objfmt.c (xdf_objfmt_output_value): Likewise.
* elf-objfmt.c (elf_objfmt_output_value): Likewise.
* coff-objfmt.c (coff_objfmt_output_value): Generate SECREL for this.

* coretype.h (YASM_PATHSEP): New define for path separator.
* vc8/config.h, vc/config.h, dj/config.h: Override.

* dbgfmts/codeview: New, adds "cv8" dbgfmt.
* dbgfmts/Makefile.inc: Hook into build.
* coff-objfmt.c: Enable cv8 dbgfmt for win32 and win64.  Change a few things
to more closely match MASM output.
(coff_section_data): Add isdebug flag so that section flags are set properly.
(coff_objfmt_secton_switch): Initialize to 0 here.
(coff_objfmt_init_remaining_section): Initialize to 1 and set various section
flags (DATA, DISCARD, READ) if section name starts with ".debug".
(coff_objfmt_output): If non-NULL dbgfmt, set object flags to say line numbers
are included.

* dwarfwin64_testhd.hex: Minor update due to coff_objfmt_output() change.

svn path=/trunk/yasm/; revision=1428

21 files changed:
Mkfiles/dj/config.h
Mkfiles/vc/config.h
Mkfiles/vc8/config.h
libyasm.h
libyasm/Makefile.inc
libyasm/coretype.h
libyasm/md5.c [new file with mode: 0644]
libyasm/md5.h [new file with mode: 0644]
libyasm/value.c
libyasm/value.h
modules/dbgfmts/Makefile.inc
modules/dbgfmts/codeview/Makefile.inc [new file with mode: 0644]
modules/dbgfmts/codeview/cv-dbgfmt.c [new file with mode: 0644]
modules/dbgfmts/codeview/cv-dbgfmt.h [new file with mode: 0644]
modules/dbgfmts/codeview/cv-symline.c [new file with mode: 0644]
modules/dbgfmts/codeview/cv-type.c [new file with mode: 0644]
modules/dbgfmts/codeview/cv8.txt [new file with mode: 0644]
modules/dbgfmts/dwarf2/tests/passwin64/dwarfwin64_testhd.hex
modules/objfmts/coff/coff-objfmt.c
modules/objfmts/elf/elf-objfmt.c
modules/objfmts/xdf/xdf-objfmt.c

index 0400cc1e7e6a7a1247cc7c4d82dab1bd6f16dc97..1cf2cbb90b480612b92eeaf3c8924ba5e678c46e 100644 (file)
@@ -1,6 +1,8 @@
 /* $Id$ */\r
 \r
 #define yasm__splitpath(path, tail)    yasm__splitpath_win(path, tail)\r
+#define YASM_PATHSEP   '\\'\r
+\r
 /* */\r
 /* #undef ENABLE_NLS */\r
 \r
index ad3d2b02c2450f8c2c1994b162600a4f591829fb..888017e95bbb4263a6a90801f9ce11b9843d3bac 100644 (file)
@@ -1,6 +1,7 @@
 /* $Id$ */\r
 \r
 #define yasm__splitpath(path, tail)    yasm__splitpath_win(path, tail)\r
+#define YASM_PATHSEP   '\\'\r
 \r
 /* */\r
 /* #undef ENABLE_NLS */\r
index 02e28e4840d62bdabd4e23cb2729904dd559e159..663a7e5e1855598f0105d54a8eb55028dc6b5b02 100644 (file)
@@ -1,6 +1,7 @@
 /* $Id: config.h 1137 2004-09-04 01:24:57Z peter $ */\r
 \r
 #define yasm__splitpath(path, tail)    yasm__splitpath_win(path, tail)\r
+#define YASM_PATHSEP   '\\'\r
 \r
 #define _CRT_SECURE_NO_DEPRECATE 1\r
 \r
index b35d5e5228e2675c2f716375291990787bc04a3b..f0de97b3db64187bfc80ef5685c14ae275a712b1 100644 (file)
--- a/libyasm.h
+++ b/libyasm.h
@@ -86,6 +86,7 @@
 #endif
 #include <libyasm/hamt.h>
 #include <libyasm/bitvect.h>
+#include <libyasm/md5.h>
 #endif
 
 #endif
index 0d0e610b653f557a6157c75eb10b5b8f6ad42118..db5351cfdf9d53bea4c2e439c31eb5f94506414b 100644 (file)
@@ -11,6 +11,7 @@ libyasm_a_SOURCES += libyasm/floatnum.c
 libyasm_a_SOURCES += libyasm/hamt.c
 libyasm_a_SOURCES += libyasm/intnum.c
 libyasm_a_SOURCES += libyasm/linemgr.c
+libyasm_a_SOURCES += libyasm/md5.c
 libyasm_a_SOURCES += libyasm/mergesort.c
 libyasm_a_SOURCES += libyasm/phash.c
 libyasm_a_SOURCES += libyasm/section.c
@@ -61,6 +62,7 @@ modinclude_HEADERS += libyasm/hamt.h
 modinclude_HEADERS += libyasm/intnum.h
 modinclude_HEADERS += libyasm/linemgr.h
 modinclude_HEADERS += libyasm/listfmt.h
+modinclude_HEADERS += libyasm/md5.h
 modinclude_HEADERS += libyasm/module.h
 modinclude_HEADERS += libyasm/objfmt.h
 modinclude_HEADERS += libyasm/optimizer.h
index 087b0acefdb22af9190cc6733aa5d563b6b8ff8e..4c51ef0a1608526013e9ca425b69e9380d5d27c4 100644 (file)
@@ -139,6 +139,14 @@ typedef struct yasm_value {
      * is needed to generate special relocations.
      */
     unsigned int ip_rel : 1;
+
+    /** Indicates the relative portion of the value should be relocated
+     * relative to its own section start rather than relative to the
+     * section start of the bytecode containing this value.  E.g. the value
+     * resulting from the relative portion should be the offset from its
+     * section start.  Boolean.
+     */
+    unsigned int section_rel : 1;
 } yasm_value;
 
 /** Maximum value of #yasm_value.rshift */
@@ -333,8 +341,14 @@ size_t yasm__splitpath_win(const char *path, /*@out@*/ const char **tail);
  defined (__DJGPP__) || defined (__OS2__) || defined (__CYGWIN__) || \
  defined (__CYGWIN32__)
 #  define yasm__splitpath(path, tail)  yasm__splitpath_win(path, tail)
+#  ifndef YASM_PATHSEP
+#   define YASM_PATHSEP '\\'
+#  endif
 # else
 #  define yasm__splitpath(path, tail)  yasm__splitpath_unix(path, tail)
+#  ifndef YASM_PATHSEP
+#   define YASM_PATHSEP '/'
+#  endif
 # endif
 #endif
 
diff --git a/libyasm/md5.c b/libyasm/md5.c
new file mode 100644 (file)
index 0000000..d53ef37
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+/* This code was modified in 1997 by Jim Kingdon of Cyclic Software to
+   not require an integer type which is exactly 32 bits.  This work
+   draws on the changes for the same purpose by Tatu Ylonen
+   <ylo@cs.hut.fi> as part of SSH, but since I didn't actually use
+   that code, there is no copyright issue.  I hereby disclaim
+   copyright in any changes I have made; this code remains in the
+   public domain.  */
+
+/* Note regarding cvs_* namespace: this avoids potential conflicts
+   with libraries such as some versions of Kerberos.  No particular
+   need to worry about whether the system supplies an MD5 library, as
+   this file is only about 3k of object code.  */
+
+#include <util.h>
+/*@unused@*/ RCSID("$Id$");
+
+#include "md5.h"
+
+/* Little-endian byte-swapping routines.  Note that these do not
+   depend on the size of datatypes such as cvs_uint32, nor do they require
+   us to detect the endianness of the machine we are running on.  It
+   is possible they should be macros for speed, but I would be
+   surprised if they were a performance bottleneck for MD5.  */
+
+static unsigned long
+getu32(const unsigned char *addr)
+{
+       return (((((unsigned long)addr[3] << 8) | addr[2]) << 8)
+               | addr[1]) << 8 | addr[0];
+}
+
+static void
+putu32(unsigned long data, unsigned char *addr)
+{
+       addr[0] = (unsigned char)data;
+       addr[1] = (unsigned char)(data >> 8);
+       addr[2] = (unsigned char)(data >> 16);
+       addr[3] = (unsigned char)(data >> 24);
+}
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+yasm_md5_init(yasm_md5_context *ctx)
+{
+       ctx->buf[0] = 0x67452301;
+       ctx->buf[1] = 0xefcdab89;
+       ctx->buf[2] = 0x98badcfe;
+       ctx->buf[3] = 0x10325476;
+
+       ctx->bits[0] = 0;
+       ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+yasm_md5_update(yasm_md5_context *ctx, unsigned char const *buf,
+               unsigned len)
+{
+       unsigned long t;
+
+       /* Update bitcount */
+
+       t = ctx->bits[0];
+       if ((ctx->bits[0] = (t + ((unsigned long)len << 3)) & 0xffffffff) < t)
+               ctx->bits[1]++; /* Carry from low to high */
+       ctx->bits[1] += len >> 29;
+
+       t = (t >> 3) & 0x3f;    /* Bytes already in shsInfo->data */
+
+       /* Handle any leading odd-sized chunks */
+
+       if ( t ) {
+               unsigned char *p = ctx->in + t;
+
+               t = 64-t;
+               if (len < t) {
+                       memcpy(p, buf, len);
+                       return;
+               }
+               memcpy(p, buf, t);
+               yasm_md5_transform (ctx->buf, ctx->in);
+               buf += t;
+               len -= t;
+       }
+
+       /* Process data in 64-byte chunks */
+
+       while (len >= 64) {
+               memcpy(ctx->in, buf, 64);
+               yasm_md5_transform (ctx->buf, ctx->in);
+               buf += 64;
+               len -= 64;
+       }
+
+       /* Handle any remaining bytes of data. */
+
+       memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+yasm_md5_final(unsigned char digest[16], yasm_md5_context *ctx)
+{
+       unsigned count;
+       unsigned char *p;
+
+       /* Compute number of bytes mod 64 */
+       count = (ctx->bits[0] >> 3) & 0x3F;
+
+       /* Set the first char of padding to 0x80.  This is safe since there is
+          always at least one byte free */
+       p = ctx->in + count;
+       *p++ = 0x80;
+
+       /* Bytes of padding needed to make 64 bytes */
+       count = 64 - 1 - count;
+
+       /* Pad out to 56 mod 64 */
+       if (count < 8) {
+               /* Two lots of padding:  Pad the first block to 64 bytes */
+               memset(p, 0, count);
+               yasm_md5_transform (ctx->buf, ctx->in);
+
+               /* Now fill the next block with 56 bytes */
+               memset(ctx->in, 0, 56);
+       } else {
+               /* Pad block to 56 bytes */
+               memset(p, 0, count-8);
+       }
+
+       /* Append length in bits and transform */
+       putu32(ctx->bits[0], ctx->in + 56);
+       putu32(ctx->bits[1], ctx->in + 60);
+
+       yasm_md5_transform (ctx->buf, ctx->in);
+       putu32(ctx->buf[0], digest);
+       putu32(ctx->buf[1], digest + 4);
+       putu32(ctx->buf[2], digest + 8);
+       putu32(ctx->buf[3], digest + 12);
+       memset(ctx, 0, sizeof(ctx));    /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+       ( w += f(x, y, z) + data, w &= 0xffffffff, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+yasm_md5_transform(unsigned long buf[4], const unsigned char inraw[64])
+{
+       register unsigned long a, b, c, d;
+       unsigned long in[16];
+       int i;
+
+       for (i = 0; i < 16; ++i)
+               in[i] = getu32 (inraw + 4 * i);
+
+       a = buf[0];
+       b = buf[1];
+       c = buf[2];
+       d = buf[3];
+
+       MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478,  7);
+       MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12);
+       MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17);
+       MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22);
+       MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf,  7);
+       MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12);
+       MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17);
+       MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22);
+       MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8,  7);
+       MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12);
+       MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17);
+       MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22);
+       MD5STEP(F1, a, b, c, d, in[12]+0x6b901122,  7);
+       MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12);
+       MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17);
+       MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22);
+
+       MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562,  5);
+       MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340,  9);
+       MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14);
+       MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20);
+       MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d,  5);
+       MD5STEP(F2, d, a, b, c, in[10]+0x02441453,  9);
+       MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14);
+       MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20);
+       MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6,  5);
+       MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6,  9);
+       MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14);
+       MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20);
+       MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905,  5);
+       MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8,  9);
+       MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14);
+       MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20);
+
+       MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942,  4);
+       MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11);
+       MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16);
+       MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23);
+       MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44,  4);
+       MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11);
+       MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16);
+       MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23);
+       MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6,  4);
+       MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11);
+       MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16);
+       MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23);
+       MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039,  4);
+       MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11);
+       MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16);
+       MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23);
+
+       MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244,  6);
+       MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10);
+       MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15);
+       MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21);
+       MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3,  6);
+       MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10);
+       MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15);
+       MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21);
+       MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f,  6);
+       MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10);
+       MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15);
+       MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21);
+       MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82,  6);
+       MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10);
+       MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15);
+       MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21);
+
+       buf[0] += a;
+       buf[1] += b;
+       buf[2] += c;
+       buf[3] += d;
+}
+#endif
+
+#ifdef TEST
+/* Simple test program.  Can use it to manually run the tests from
+   RFC1321 for example.  */
+#include <stdio.h>
+
+int
+main (int argc, char **argv)
+{
+       yasm_md5_context context;
+       unsigned char checksum[16];
+       int i;
+       int j;
+
+       if (argc < 2)
+       {
+               fprintf (stderr, "usage: %s string-to-hash\n", argv[0]);
+               exit (1);
+       }
+       for (j = 1; j < argc; ++j)
+       {
+               printf ("MD5 (\"%s\") = ", argv[j]);
+               yasm_md5_init (&context);
+               yasm_md5_update (&context, argv[j], strlen (argv[j]));
+               yasm_md5_final (checksum, &context);
+               for (i = 0; i < 16; i++)
+               {
+                       printf ("%02x", (unsigned int) checksum[i]);
+               }
+               printf ("\n");
+       }
+       return 0;
+}
+#endif /* TEST */
diff --git a/libyasm/md5.h b/libyasm/md5.h
new file mode 100644 (file)
index 0000000..52559a0
--- /dev/null
@@ -0,0 +1,28 @@
+/* See md5.c for explanation and copyright information.  */
+
+/*
+ * $Id$
+ */
+
+#ifndef YASM_MD5_H
+#define YASM_MD5_H
+
+/* Unlike previous versions of this code, uint32 need not be exactly
+   32 bits, merely 32 bits or more.  Choosing a data type which is 32
+   bits instead of 64 is not important; speed is considerably more
+   important.  ANSI guarantees that "unsigned long" will be big enough,
+   and always using it seems to have few disadvantages.  */
+
+typedef struct yasm_md5_context {
+       unsigned long buf[4];
+       unsigned long bits[2];
+       unsigned char in[64];
+} yasm_md5_context;
+
+void yasm_md5_init(yasm_md5_context *context);
+void yasm_md5_update(yasm_md5_context *context, unsigned char const *buf,
+                    unsigned len);
+void yasm_md5_final(unsigned char digest[16], yasm_md5_context *context);
+void yasm_md5_transform(unsigned long buf[4], const unsigned char in[64]);
+
+#endif /* !YASM_MD5_H */
index cc0e0e8c6892355a97cd5b0a22f42f0657d5bc9e..9bae80a6ff4096684d0996014a5bc26a0a6a7c29 100644 (file)
@@ -468,7 +468,7 @@ yasm_value_output_basic(yasm_value *value, /*@out@*/ unsigned char *buf,
        unsigned long dist;
 
        sym_local = yasm_symrec_get_label(value->rel, &rel_prevbc);
-       if (value->wrt || value->seg_of || !sym_local)
+       if (value->wrt || value->seg_of || value->section_rel || !sym_local)
            return 0;       /* we can't handle SEG, WRT, or external symbols */
        if (rel_prevbc->section != bc->section)
            return 0;       /* not in this section */
index 7873fb6665ddfde20b1286d4cc5abe4fd87d60f7..10f33b33b015ec0cf12ee66357fd0c9b825faaee 100644 (file)
@@ -135,6 +135,7 @@ void yasm_value_print(const yasm_value *value, FILE *f, int indent_level);
        (value)->rshift = 0; \
        (value)->curpos_rel = 0; \
        (value)->ip_rel = 0; \
+       (value)->section_rel = 0; \
     } while(0)
 
 #define yasm_value_init_sym(value, sym) \
@@ -146,6 +147,7 @@ void yasm_value_print(const yasm_value *value, FILE *f, int indent_level);
        (value)->rshift = 0; \
        (value)->curpos_rel = 0; \
        (value)->ip_rel = 0; \
+       (value)->section_rel = 0; \
     } while(0)
 
 #define yasm_value_delete(value) \
index 3dbfcf0d49de1bf75e15523dc6c1d9b187277f4c..cf0a5ffdf4164f4e4eeae5cfe900a6c6492ddf33 100644 (file)
@@ -1,9 +1,11 @@
 # $Id$
 
+EXTRA_DIST += modules/dbgfmts/codeview/Makefile.inc
 EXTRA_DIST += modules/dbgfmts/dwarf2/Makefile.inc
 EXTRA_DIST += modules/dbgfmts/null/Makefile.inc
 EXTRA_DIST += modules/dbgfmts/stabs/Makefile.inc
 
+include modules/dbgfmts/codeview/Makefile.inc
 include modules/dbgfmts/dwarf2/Makefile.inc
 include modules/dbgfmts/null/Makefile.inc
 include modules/dbgfmts/stabs/Makefile.inc
diff --git a/modules/dbgfmts/codeview/Makefile.inc b/modules/dbgfmts/codeview/Makefile.inc
new file mode 100644 (file)
index 0000000..1a11f72
--- /dev/null
@@ -0,0 +1,13 @@
+# $Id$
+
+libyasm_a_SOURCES += modules/dbgfmts/codeview/cv-dbgfmt.h
+libyasm_a_SOURCES += modules/dbgfmts/codeview/cv-dbgfmt.c
+libyasm_a_SOURCES += modules/dbgfmts/codeview/cv-symline.c
+libyasm_a_SOURCES += modules/dbgfmts/codeview/cv-type.c
+
+YASM_MODULES += dbgfmt_cv8
+
+EXTRA_DIST += modules/dbgfmts/codeview/cv8.txt
+
+#EXTRA_DIST += modules/dbgfmts/codeview/tests/Makefile.inc
+#include modules/dbgfmts/codeview/tests/Makefile.inc
diff --git a/modules/dbgfmts/codeview/cv-dbgfmt.c b/modules/dbgfmts/codeview/cv-dbgfmt.c
new file mode 100644 (file)
index 0000000..ccf148c
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * CodeView debugging formats implementation for Yasm
+ *
+ *  Copyright (C) 2006  Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <util.h>
+/*@unused@*/ RCSID("$Id$");
+
+#define YASM_LIB_INTERNAL
+#define YASM_BC_INTERNAL
+#include <libyasm.h>
+
+#include "cv-dbgfmt.h"
+
+yasm_dbgfmt_module yasm_cv8_LTX_dbgfmt;
+
+
+static /*@null@*/ /*@only@*/ yasm_dbgfmt *
+cv_dbgfmt_create(yasm_object *object, yasm_objfmt *of, yasm_arch *a,
+                yasm_dbgfmt_module *module, int version)
+{
+    yasm_dbgfmt_cv *dbgfmt_cv = yasm_xmalloc(sizeof(yasm_dbgfmt_cv));
+    size_t i;
+
+    dbgfmt_cv->dbgfmt.module = module;
+
+    dbgfmt_cv->object = object;
+    dbgfmt_cv->symtab = yasm_object_get_symtab(object);
+    dbgfmt_cv->linemap = yasm_object_get_linemap(object);
+    dbgfmt_cv->arch = a;
+
+    dbgfmt_cv->filenames_allocated = 32;
+    dbgfmt_cv->filenames_size = 0;
+    dbgfmt_cv->filenames =
+       yasm_xmalloc(sizeof(cv_filename)*dbgfmt_cv->filenames_allocated);
+    for (i=0; i<dbgfmt_cv->filenames_allocated; i++) {
+       dbgfmt_cv->filenames[i].pathname = NULL;
+       dbgfmt_cv->filenames[i].filename = NULL;
+       dbgfmt_cv->filenames[i].str_off = 0;
+       dbgfmt_cv->filenames[i].info_off = 0;
+    }
+
+    dbgfmt_cv->version = version;
+
+    return (yasm_dbgfmt *)dbgfmt_cv;
+}
+
+static /*@null@*/ /*@only@*/ yasm_dbgfmt *
+cv8_dbgfmt_create(yasm_object *object, yasm_objfmt *of, yasm_arch *a)
+{
+    return cv_dbgfmt_create(object, of, a, &yasm_cv8_LTX_dbgfmt, 8);
+}
+
+static void
+cv_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt)
+{
+    yasm_dbgfmt_cv *dbgfmt_cv = (yasm_dbgfmt_cv *)dbgfmt;
+    size_t i;
+    for (i=0; i<dbgfmt_cv->filenames_size; i++) {
+       if (dbgfmt_cv->filenames[i].pathname)
+           yasm_xfree(dbgfmt_cv->filenames[i].pathname);
+    }
+    yasm_xfree(dbgfmt_cv->filenames);
+    yasm_xfree(dbgfmt);
+}
+
+/* Add a bytecode to a section, updating offset on insertion;
+ * no optimization necessary.
+ */
+yasm_bytecode *
+yasm_cv__append_bc(yasm_section *sect, yasm_bytecode *bc)
+{
+    yasm_bytecode *precbc = yasm_section_bcs_last(sect);
+    bc->offset = precbc ? precbc->offset + precbc->len : 0;
+    yasm_section_bcs_append(sect, bc);
+    return precbc;
+}
+
+static void
+cv_dbgfmt_generate(yasm_dbgfmt *dbgfmt)
+{
+    yasm_dbgfmt_cv *dbgfmt_cv = (yasm_dbgfmt_cv *)dbgfmt;
+
+    yasm_cv__generate_symline(dbgfmt_cv);
+
+    yasm_cv__generate_type(dbgfmt_cv);
+}
+
+static int
+cv_dbgfmt_directive(yasm_dbgfmt *dbgfmt, const char *name,
+                   yasm_section *sect, yasm_valparamhead *valparams,
+                   unsigned long line)
+{
+    return 1;      /* TODO */
+}
+
+/* Define dbgfmt structure -- see dbgfmt.h for details */
+yasm_dbgfmt_module yasm_cv8_LTX_dbgfmt = {
+    "CodeView debugging format for VC8",
+    "cv8",
+    cv8_dbgfmt_create,
+    cv_dbgfmt_destroy,
+    cv_dbgfmt_directive,
+    cv_dbgfmt_generate
+};
diff --git a/modules/dbgfmts/codeview/cv-dbgfmt.h b/modules/dbgfmts/codeview/cv-dbgfmt.h
new file mode 100644 (file)
index 0000000..0cf9899
--- /dev/null
@@ -0,0 +1,62 @@
+/* $Id$
+ * CodeView debugging formats implementation for Yasm
+ *
+ *  Copyright (C) 2006  Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef YASM_CV_DBGFMT_H
+#define YASM_CV_DBGFMT_H
+
+typedef struct {
+    char *pathname;            /* full pathname (drive+basepath+filename) */
+    char *filename;            /* filename as yasm knows it internally */
+    unsigned long str_off;     /* offset into pathname string table */
+    unsigned long info_off;    /* offset into source info table */
+    unsigned char digest[16];  /* MD5 digest of source file */
+} cv_filename;
+
+/* Global data */
+typedef struct yasm_dbgfmt_cv {
+    yasm_dbgfmt_base dbgfmt;       /* base structure */
+
+    yasm_object *object;
+    yasm_symtab *symtab;
+    yasm_linemap *linemap;
+    yasm_arch *arch;
+
+    cv_filename *filenames;
+    size_t filenames_size;
+    size_t filenames_allocated;
+
+    int version;
+} yasm_dbgfmt_cv;
+
+yasm_bytecode *yasm_cv__append_bc(yasm_section *sect, yasm_bytecode *bc);
+
+/* Symbol/Line number functions */
+yasm_section *yasm_cv__generate_symline(yasm_dbgfmt_cv *dbgfmt_cv);
+
+/* Type functions */
+yasm_section *yasm_cv__generate_type(yasm_dbgfmt_cv *dbgfmt_cv);
+
+#endif
diff --git a/modules/dbgfmts/codeview/cv-symline.c b/modules/dbgfmts/codeview/cv-symline.c
new file mode 100644 (file)
index 0000000..ec8495b
--- /dev/null
@@ -0,0 +1,1130 @@
+/*
+ * CodeView debugging format - symbol and line information
+ *
+ *  Copyright (C) 2006  Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#undef HAVE_CONFIG_H
+#endif
+
+/* Need either unistd.h or direct.h (on Windows) to prototype getcwd() */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#elif defined(WIN32) || defined(_WIN32)
+#include <direct.h>
+#endif
+
+#include <util.h>
+/*@unused@*/ RCSID("$Id$");
+
+#define YASM_LIB_INTERNAL
+#define YASM_BC_INTERNAL
+#include <libyasm.h>
+
+#include "cv-dbgfmt.h"
+
+enum cv8_symheadtype {
+    CV8_DEBUG_SYMS     = 0xF1, /* CV5 symbol information */
+    CV8_LINE_NUMS      = 0xF2, /* line numbers for a section */
+    CV8_FILE_STRTAB    = 0xF3, /* filename string table */
+    CV8_FILE_INFO      = 0xF4  /* source file info */
+};
+
+enum cv_symtype {
+    /* Non-modal Symbols */
+    CV_S_COMPILE       = 0x0001,       /* Compile Flag */
+    CV_S_REGISTER      = 0x0002,       /* Register */
+    CV_S_CONSTANT      = 0x0003,       /* Constant */
+    CV_S_UDT           = 0x0004,       /* User-defined Type */
+    CV_S_SSEARCH       = 0x0005,       /* Start Search */
+    CV_S_END           = 0x0006,       /* End of Block */
+    CV_S_SKIP          = 0x0007,       /* Skip Record */
+    CV_S_OBJNAME       = 0x0009,       /* Object File Name */
+    CV_S_ENDARG                = 0x000a,       /* End of Arguments */
+    CV_S_COBOLUDT      = 0x000b,       /* COBOL User-defined Type */
+    CV_S_MANYREG       = 0x000c,       /* Many Registers */
+    CV_S_RETURN                = 0x000d,       /* Function Return */
+    CV_S_ENTRYTHIS     = 0x000e,       /* "this" at Method Entry */
+
+    /* Symbols for 16:16 Segmented Architectures */
+    CV_S_BPREL16       = 0x0100,       /* BP Relative 16:16 */
+    CV_S_LDATA16       = 0x0101,       /* Local Data 16:16 */
+    CV_S_GDATA16       = 0x0102,       /* Global Data Symbol 16:16 */
+    CV_S_PUB16         = 0x0103,       /* Public Symbol 16:16 */
+    CV_S_LPROC16       = 0x0104,       /* Local Start 16:16 */
+    CV_S_GPROC16       = 0x0105,       /* Global Start 16:16 */
+    CV_S_THUNK16       = 0x0106,       /* Thunk Start 16:16 */
+    CV_S_BLOCK16       = 0x0107,       /* Block Start 16:16 */
+    CV_S_WITH16                = 0x0108,       /* With Start 16:16 */
+    CV_S_LABEL16       = 0x0109,       /* Code Label 16:16 */
+    CV_S_CEXMODEL16    = 0x0110,       /* Change Execution Model 16:16 */
+    CV_S_VFTPATH16     = 0x010b,       /* Virtual Function Table Path 16:16 */
+    CV_S_REGREL16      = 0x010c,       /* Register Relative 16:16 */
+
+    /* Symbols for 16:32 Segmented Architectures */
+    CV_S_BPREL32       = 0x0200,       /* BP Relative 16:32 */
+    CV_S_LDATA32       = 0x0201,       /* Local Data 16:32 */
+    CV_S_GDATA32       = 0x0202,       /* Global Data Symbol 16:32 */
+    CV_S_PUB32         = 0x0203,       /* Public Symbol 16:32 */
+    CV_S_LPROC32       = 0x0204,       /* Local Start 16:32 */
+    CV_S_GPROC32       = 0x0205,       /* Global Start 16:32 */
+    CV_S_THUNK32       = 0x0206,       /* Thunk Start 16:32 */
+    CV_S_BLOCK32       = 0x0207,       /* Block Start 16:32 */
+    CV_S_WITH32                = 0x0208,       /* With Start 16:32 */
+    CV_S_LABEL32       = 0x0209,       /* Code Label 16:32 */
+    CV_S_CEXMODEL32    = 0x0210,       /* Change Execution Model 16:32 */
+    CV_S_VFTPATH32     = 0x020b,       /* Virtual Function Table Path 16:32 */
+    CV_S_REGREL32      = 0x020c,       /* Register Relative 16:32 */
+    CV_S_LTHREAD32     = 0x020d,       /* Local Thread Storage 16:32 */
+    CV_S_GTHREAD32     = 0x020e,       /* Global Thread Storage 16:32 */
+
+    /* Symbols for MIPS */
+    CV_S_LPROCMIPS     = 0x0300,       /* Local procedure start MIPS */
+    CV_S_GPROCMIPS     = 0x0301,       /* Global procedure start MIPS */
+
+    /* Symbols for CV8 - strings are 0 terminated rather than length-prefix.
+     * Incomplete and unofficial.
+     */
+    CV8_S_OBJNAME      = 0x1101,       /* Object File Name */
+    CV8_S_LABEL32      = 0x1105,       /* Code Label 16:32 */
+    CV8_S_LDATA32      = 0x110c,       /* Local Data 16:32 */
+    CV8_S_GDATA32      = 0x110d,       /* Global Data 16:32 */
+    CV8_S_LPROC32      = 0x1110,       /* Local Start 16:32 */
+    CV8_S_COMPILE      = 0x1116        /* Compile Flag */
+};
+
+typedef struct cv8_symhead {
+    yasm_dbgfmt_cv *dbgfmt_cv;
+    enum cv8_symheadtype type;
+    yasm_bytecode *start_prevbc;
+    yasm_bytecode *end_prevbc;
+    int first;     /* nonzero if first symhead in section */
+} cv8_symhead;
+
+typedef struct cv8_fileinfo {
+    yasm_dbgfmt_cv *dbgfmt_cv;
+    const cv_filename *fn;
+} cv8_fileinfo;
+
+/* Note: each line number group is associated with a file AND a section */
+typedef struct cv8_linepair {
+    unsigned long offset;
+    unsigned long line;
+} cv8_linepair;
+
+/* Decrease linked list overhead a bit doing it this way */
+typedef struct cv8_lineset {
+    STAILQ_ENTRY(cv8_lineset) link;
+    cv8_linepair pairs[126];
+    size_t num_pairs;
+} cv8_lineset;
+
+typedef struct cv8_lineinfo {
+    STAILQ_ENTRY(cv8_lineinfo) link;
+    yasm_dbgfmt_cv *dbgfmt_cv;
+    const cv_filename *fn;     /* filename associated with line numbers */
+    yasm_section *sect;                /* section line numbers are for */
+    yasm_symrec *sectsym;      /* symbol for beginning of sect */
+    unsigned long num_linenums;
+    STAILQ_HEAD(, cv8_lineset) linesets;
+} cv8_lineinfo;
+
+/* Symbols use a bit of meta-programming to encode formats: each character
+ * of format represents the output generated, as follows:
+ * 'b' : 1 byte value (integer)
+ * 'h' : 2 byte value (integer)
+ * 'w' : 4 byte value (integer)
+ * 'Y' : symrec SECREL+SECTION (pointer)
+ * 'T' : type index (integer)
+ * 'S' : length-prefixed string (pointer)
+ * 'Z' : 0-terminated string (pointer)
+ */
+typedef struct cv_sym {
+    yasm_dbgfmt_cv *dbgfmt_cv;
+    enum cv_symtype type;
+    const char *format;
+    union {
+       unsigned long i;
+       void *p;
+    } args[10];
+} cv_sym;
+
+/* Bytecode callback function prototypes */
+static void cv8_symhead_bc_destroy(void *contents);
+static void cv8_symhead_bc_print(const void *contents, FILE *f,
+                                int indent_level);
+static yasm_bc_resolve_flags cv8_symhead_bc_resolve
+    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+static int cv8_symhead_bc_tobytes
+    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+     yasm_output_value_func output_value,
+     /*@null@*/ yasm_output_reloc_func output_reloc);
+
+static void cv8_fileinfo_bc_destroy(void *contents);
+static void cv8_fileinfo_bc_print(const void *contents, FILE *f,
+                                 int indent_level);
+static yasm_bc_resolve_flags cv8_fileinfo_bc_resolve
+    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+static int cv8_fileinfo_bc_tobytes
+    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+     yasm_output_value_func output_value,
+     /*@null@*/ yasm_output_reloc_func output_reloc);
+
+static void cv8_lineinfo_bc_destroy(void *contents);
+static void cv8_lineinfo_bc_print(const void *contents, FILE *f,
+                                 int indent_level);
+static yasm_bc_resolve_flags cv8_lineinfo_bc_resolve
+    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+static int cv8_lineinfo_bc_tobytes
+    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+     yasm_output_value_func output_value,
+     /*@null@*/ yasm_output_reloc_func output_reloc);
+
+static void cv_sym_bc_destroy(void *contents);
+static void cv_sym_bc_print(const void *contents, FILE *f, int indent_level);
+static yasm_bc_resolve_flags cv_sym_bc_resolve
+    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+static int cv_sym_bc_tobytes
+    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+     yasm_output_value_func output_value,
+     /*@null@*/ yasm_output_reloc_func output_reloc);
+
+/* Bytecode callback structures */
+static const yasm_bytecode_callback cv8_symhead_bc_callback = {
+    cv8_symhead_bc_destroy,
+    cv8_symhead_bc_print,
+    yasm_bc_finalize_common,
+    cv8_symhead_bc_resolve,
+    cv8_symhead_bc_tobytes
+};
+
+static const yasm_bytecode_callback cv8_fileinfo_bc_callback = {
+    cv8_fileinfo_bc_destroy,
+    cv8_fileinfo_bc_print,
+    yasm_bc_finalize_common,
+    cv8_fileinfo_bc_resolve,
+    cv8_fileinfo_bc_tobytes
+};
+
+static const yasm_bytecode_callback cv8_lineinfo_bc_callback = {
+    cv8_lineinfo_bc_destroy,
+    cv8_lineinfo_bc_print,
+    yasm_bc_finalize_common,
+    cv8_lineinfo_bc_resolve,
+    cv8_lineinfo_bc_tobytes
+};
+
+static const yasm_bytecode_callback cv_sym_bc_callback = {
+    cv_sym_bc_destroy,
+    cv_sym_bc_print,
+    yasm_bc_finalize_common,
+    cv_sym_bc_resolve,
+    cv_sym_bc_tobytes
+};
+
+static cv8_symhead *cv8_add_symhead(yasm_dbgfmt_cv *dbgfmt_cv,
+                                   yasm_section *sect, unsigned long type,
+                                   int first);
+static void cv8_set_symhead_end(cv8_symhead *head, yasm_bytecode *end_prevbc);
+
+static yasm_bytecode *cv8_add_fileinfo
+    (yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect, const cv_filename *fn);
+
+static unsigned long cv_sym_size(const cv_sym *cvs);
+
+
+static cv_sym *
+cv8_add_sym_objname(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+                   /*@keep@*/ char *objname)
+{
+    yasm_bytecode *bc;
+    cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
+    cvs->dbgfmt_cv = dbgfmt_cv;
+    cvs->type = CV8_S_OBJNAME;
+    cvs->format = "wZ";
+    cvs->args[0].i = 0;                /* signature (0=asm) */
+    cvs->args[1].p = objname;  /* object filename */
+
+    bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
+    bc->len = cv_sym_size(cvs);
+    yasm_cv__append_bc(sect, bc);
+    return cvs;
+}
+
+static cv_sym *
+cv8_add_sym_compile(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+                   /*@keep@*/ char *creator)
+{
+    yasm_bytecode *bc;
+    cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
+    cvs->dbgfmt_cv = dbgfmt_cv;
+    cvs->type = CV8_S_COMPILE;
+    cvs->format = "wwwwZ";
+    cvs->args[0].i = 3;                /* language (3=Masm) */
+
+    /* target processor; 0xD0 = AMD64 */
+    if (strcmp(yasm_arch_keyword(dbgfmt_cv->arch), "x86") == 0) {
+       if (strcmp(yasm_arch_get_machine(dbgfmt_cv->arch), "amd64") == 0)
+           cvs->args[1].i = 0xD0;
+       else
+           cvs->args[1].i = 0x6;       /* 686, FIXME */
+    } else
+       cvs->args[1].i = 0;             /* XXX: unknown */
+
+    cvs->args[2].i = 0;                /* flags (assume 0 for now) */
+    cvs->args[3].i = 0;                /* creator version number (assume 0 for now) */
+    cvs->args[4].p = creator;  /* creator string */
+
+    bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
+    bc->len = cv_sym_size(cvs);
+    yasm_cv__append_bc(sect, bc);
+    return cvs;
+}
+
+static cv_sym *
+cv8_add_sym_label(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+                 yasm_symrec *sym)
+{
+    yasm_bytecode *bc;
+    cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
+    cvs->dbgfmt_cv = dbgfmt_cv;
+    cvs->type = CV8_S_LABEL32;
+    cvs->format = "YbZ";
+    cvs->args[0].p = sym;      /* symrec for label */
+    cvs->args[1].i = 0;                /* flags (assume 0 for now) */
+    cvs->args[2].p = yasm__xstrdup(yasm_symrec_get_name(sym));
+
+    bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
+    bc->len = cv_sym_size(cvs);
+    yasm_cv__append_bc(sect, bc);
+    return cvs;
+}
+
+static cv_sym *
+cv8_add_sym_data(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+                unsigned long type, yasm_symrec *sym, int is_global)
+{
+    yasm_bytecode *bc;
+    cv_sym *cvs = yasm_xmalloc(sizeof(cv_sym));
+    cvs->dbgfmt_cv = dbgfmt_cv;
+    cvs->type = is_global ? CV8_S_GDATA32 : CV8_S_LDATA32;
+    cvs->format = "wYZ";
+    cvs->args[0].i = type;     /* type index */
+    cvs->args[1].p = sym;      /* symrec for label */
+    cvs->args[2].p = yasm__xstrdup(yasm_symrec_get_name(sym));
+
+    bc = yasm_bc_create_common(&cv_sym_bc_callback, cvs, 0);
+    bc->len = cv_sym_size(cvs);
+    yasm_cv__append_bc(sect, bc);
+    return cvs;
+}
+
+static /*@only@*/ char *
+cv_make_pathname(const char *filename)
+{
+    char *curdir, *pathname;
+    static const char pathsep[2] = { YASM_PATHSEP, '\0' };
+
+    curdir = getcwd(NULL, 0);
+
+    pathname = yasm_xmalloc(strlen(curdir) + strlen(filename) + 2);
+    strcpy(pathname, curdir);
+    strcat(pathname, pathsep);
+    strcat(pathname, filename);
+
+    free(curdir);
+
+    return pathname;
+}
+
+static size_t
+cv_dbgfmt_add_file(yasm_dbgfmt_cv *dbgfmt_cv, size_t filenum,
+                  const char *filename)
+{
+    char *pathname;
+    size_t i;
+    yasm_md5_context context;
+    FILE *f;
+    unsigned char *buf;
+    size_t len;
+
+    /* Put the filename into the filename table */
+    if (filenum == 0) {
+       /* Look to see if we already have that filename in the table */
+       for (; filenum<dbgfmt_cv->filenames_size; filenum++) {
+           if (!dbgfmt_cv->filenames[filenum].filename ||
+               strcmp(dbgfmt_cv->filenames[filenum].filename, filename) == 0)
+               break;
+       }
+    } else
+       filenum--;      /* array index is 0-based */
+
+    /* Realloc table if necessary */
+    if (filenum >= dbgfmt_cv->filenames_allocated) {
+       size_t old_allocated = dbgfmt_cv->filenames_allocated;
+       dbgfmt_cv->filenames_allocated = filenum+32;
+       dbgfmt_cv->filenames = yasm_xrealloc(dbgfmt_cv->filenames,
+           sizeof(cv_filename)*dbgfmt_cv->filenames_allocated);
+       for (i=old_allocated; i<dbgfmt_cv->filenames_allocated; i++) {
+           dbgfmt_cv->filenames[i].pathname = NULL;
+           dbgfmt_cv->filenames[i].filename = NULL;
+           dbgfmt_cv->filenames[i].str_off = 0;
+           dbgfmt_cv->filenames[i].info_off = 0;
+       }
+    }
+
+    /* Calculate MD5 checksum of file */
+    buf = yasm_xmalloc(1024);
+    yasm_md5_init(&context);
+    f = fopen(filename, "rb");
+    if (!f)
+       yasm__fatal(N_("codeview: could not open source file"));
+    while ((len = fread(buf, 1, 1024, f)) > 0)
+       yasm_md5_update(&context, buf, len);
+    yasm_md5_final(dbgfmt_cv->filenames[filenum].digest, &context);
+    fclose(f);
+    yasm_xfree(buf);
+
+    /* Actually save in table */
+    if (dbgfmt_cv->filenames[filenum].pathname)
+       yasm_xfree(dbgfmt_cv->filenames[filenum].pathname);
+    if (dbgfmt_cv->filenames[filenum].filename)
+       yasm_xfree(dbgfmt_cv->filenames[filenum].filename);
+
+    pathname = cv_make_pathname(filename);
+    dbgfmt_cv->filenames[filenum].pathname = pathname;
+    dbgfmt_cv->filenames[filenum].filename = yasm__xstrdup(filename);
+
+    /* Update table size */
+    if (filenum >= dbgfmt_cv->filenames_size)
+       dbgfmt_cv->filenames_size = filenum + 1;
+
+    return filenum;
+}
+
+static yasm_bytecode *
+cv_append_str(yasm_section *sect, const char *str)
+{
+    yasm_datavalhead dvs;
+    yasm_bytecode *bc;
+
+    yasm_dvs_initialize(&dvs);
+    yasm_dvs_append(&dvs, yasm_dv_create_string(yasm__xstrdup(str),
+                                               strlen(str)));
+    bc = yasm_bc_create_data(&dvs, 1, 1, 0);
+    yasm_bc_finalize(bc, yasm_cv__append_bc(sect, bc));
+    yasm_bc_resolve(bc, 0, NULL);
+    return bc;
+}
+
+typedef struct cv_line_info {
+    yasm_section *debug_symline;
+    yasm_dbgfmt_cv *dbgfmt_cv;
+    unsigned int num_lineinfos;
+    STAILQ_HEAD(, cv8_lineinfo) cv8_lineinfos;
+    /*@null@*/ cv8_lineinfo *cv8_cur_li;
+    /*@null@*/ cv8_lineset *cv8_cur_ls;
+} cv_line_info;
+
+static int
+cv_generate_line_bc(yasm_bytecode *bc, /*@null@*/ void *d)
+{
+    cv_line_info *info = (cv_line_info *)d;
+    yasm_dbgfmt_cv *dbgfmt_cv = info->dbgfmt_cv;
+    size_t i;
+    const char *filename;
+    unsigned long line;
+    /*@null@*/ yasm_bytecode *nextbc = yasm_bc__next(bc);
+    yasm_section *sect = yasm_bc_get_section(bc);
+    cv8_lineset *ls;
+
+    if (nextbc && bc->offset == nextbc->offset)
+       return 0;
+
+    yasm_linemap_lookup(dbgfmt_cv->linemap, bc->line, &filename, &line);
+
+    if (!info->cv8_cur_li
+       || strcmp(filename, info->cv8_cur_li->fn->filename) != 0) {
+       yasm_bytecode *sectbc;
+       char symname[8];
+
+       /* first see if we already have a lineinfo that is for this section and
+        * filename
+        */
+       STAILQ_FOREACH(info->cv8_cur_li, &info->cv8_lineinfos, link) {
+           if (sect == info->cv8_cur_li->sect
+               && strcmp(filename, info->cv8_cur_li->fn->filename) == 0)
+               break;
+       }
+
+       if (info->cv8_cur_li) {
+           info->cv8_cur_ls = STAILQ_LAST(&info->cv8_cur_li->linesets,
+                                          cv8_lineset, link);
+           goto done;          /* found one */
+       }
+
+       /* Nope; find file */
+       for (i=0; i<dbgfmt_cv->filenames_size; i++) {
+           if (strcmp(filename, dbgfmt_cv->filenames[i].filename) == 0)
+               break;
+       }
+       if (i >= dbgfmt_cv->filenames_size)
+           yasm_internal_error(N_("could not find filename in table"));
+
+       /* and create new lineinfo structure */
+       info->cv8_cur_li = yasm_xmalloc(sizeof(cv8_lineinfo));
+       info->cv8_cur_li->dbgfmt_cv = dbgfmt_cv;
+       info->cv8_cur_li->fn = &dbgfmt_cv->filenames[i];
+       info->cv8_cur_li->sect = sect;
+       sectbc = yasm_section_bcs_first(sect);
+       if (sectbc->symrecs && sectbc->symrecs[0])
+           info->cv8_cur_li->sectsym = sectbc->symrecs[0];
+       else {
+           sprintf(symname, ".%06u", info->num_lineinfos++);
+           info->cv8_cur_li->sectsym =
+               yasm_symtab_define_label(dbgfmt_cv->symtab, symname, sectbc,
+                                        1, 0);
+       }
+       info->cv8_cur_li->num_linenums = 0;
+       STAILQ_INIT(&info->cv8_cur_li->linesets);
+       STAILQ_INSERT_TAIL(&info->cv8_lineinfos, info->cv8_cur_li, link);
+       info->cv8_cur_ls = NULL;
+    }
+done:
+
+    /* build new lineset if necessary */
+    if (!info->cv8_cur_ls || info->cv8_cur_ls->num_pairs >= 126) {
+       info->cv8_cur_ls = yasm_xmalloc(sizeof(cv8_lineset));
+       info->cv8_cur_ls->num_pairs = 0;
+       STAILQ_INSERT_TAIL(&info->cv8_cur_li->linesets, info->cv8_cur_ls, link);
+    }
+
+    /* add linepair for this bytecode */
+    info->cv8_cur_ls->pairs[info->cv8_cur_ls->num_pairs].offset = bc->offset;
+    info->cv8_cur_ls->pairs[info->cv8_cur_ls->num_pairs].line =
+       0x80000000 | line;
+    info->cv8_cur_ls->num_pairs++;
+    info->cv8_cur_li->num_linenums++;
+
+    return 0;
+}
+
+static int
+cv_generate_line_section(yasm_section *sect, /*@null@*/ void *d)
+{
+    cv_line_info *info = (cv_line_info *)d;
+    yasm_dbgfmt_cv *dbgfmt_cv = info->dbgfmt_cv;
+    /*@null@*/ yasm_bytecode *bc;
+    /*cv_line_state state;*/
+    unsigned long addr_delta;
+
+    if (!yasm_section_is_code(sect))
+       return 0;       /* not code, so no line data for this section */
+
+    info->cv8_cur_li = NULL;
+    info->cv8_cur_ls = NULL;
+
+    yasm_section_bcs_traverse(sect, info, cv_generate_line_bc);
+
+    return 0;
+}
+
+static int
+cv_generate_filename(const char *filename, void *d)
+{
+    yasm_dbgfmt_cv *dbgfmt_cv = (yasm_dbgfmt_cv *)d;
+    cv_dbgfmt_add_file(dbgfmt_cv, 0, filename);
+    return 0;
+}
+
+static int
+cv_generate_sym(yasm_symrec *sym, void *d)
+{
+    cv_line_info *info = (cv_line_info *)d;
+    yasm_bytecode *precbc;
+    unsigned long type;
+
+    /* only care about labels (for now) */
+    if (!yasm_symrec_get_label(sym, &precbc))
+       return 0;
+
+    /* TODO: add data types */
+    if (yasm_section_is_code(yasm_bc_get_section(precbc)))
+       cv8_add_sym_label(info->dbgfmt_cv, info->debug_symline, sym);
+    else
+       cv8_add_sym_data(info->dbgfmt_cv, info->debug_symline, 0, sym,
+           yasm_symrec_get_visibility(sym) & YASM_SYM_GLOBAL?1:0);
+
+    return 0;
+}
+
+yasm_section *
+yasm_cv__generate_symline(yasm_dbgfmt_cv *dbgfmt_cv)
+{
+    cv_line_info info;
+    int new;
+    size_t i;
+    cv8_symhead *head;
+    cv8_lineinfo *li;
+    yasm_bytecode *bc;
+    unsigned long off;
+
+    /* Generate filenames based on linemap */
+    yasm_linemap_traverse_filenames(dbgfmt_cv->linemap, dbgfmt_cv,
+                                   cv_generate_filename);
+
+    info.dbgfmt_cv = dbgfmt_cv;
+    info.debug_symline = yasm_object_get_general(dbgfmt_cv->object,
+                                                ".debug$S", 0, 1, 0, 0, &new,
+                                                0);
+    info.num_lineinfos = 0;
+    STAILQ_INIT(&info.cv8_lineinfos);
+    info.cv8_cur_li = NULL;
+    info.cv8_cur_ls = NULL;
+
+    /* source filenames string table */
+    head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_FILE_STRTAB, 1);
+    cv_append_str(info.debug_symline, "");
+    off = 1;
+    for (i=0; i<dbgfmt_cv->filenames_size; i++) {
+       if (!dbgfmt_cv->filenames[i].pathname) {
+           yasm__error(0, N_("codeview file number %d unassigned"), i+1);
+           continue;
+       }
+       bc = cv_append_str(info.debug_symline,
+                          dbgfmt_cv->filenames[i].pathname);
+       dbgfmt_cv->filenames[i].str_off = off;
+       off += bc->len;
+    }
+    cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
+
+    /* Align 4 */
+    bc = yasm_bc_create_align
+       (yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), 0),
+        NULL, NULL, NULL, 0);
+    yasm_bc_finalize(bc, yasm_cv__append_bc(info.debug_symline, bc));
+    yasm_bc_resolve(bc, 0, NULL);
+
+    /* source file info table */
+    head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_FILE_INFO, 0);
+    off = 0;
+    for (i=0; i<dbgfmt_cv->filenames_size; i++) {
+       if (!dbgfmt_cv->filenames[i].pathname)
+           continue;
+       bc = cv8_add_fileinfo(dbgfmt_cv, info.debug_symline,
+                             &dbgfmt_cv->filenames[i]);
+       dbgfmt_cv->filenames[i].info_off = off;
+       off += bc->len;
+    }
+    cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
+
+    /* Already aligned 4 */
+
+    /* Generate line numbers for sections */
+    yasm_object_sections_traverse(dbgfmt_cv->object, (void *)&info,
+                                 cv_generate_line_section);
+
+    /* Output line numbers for sections */
+    STAILQ_FOREACH(li, &info.cv8_lineinfos, link) {
+       head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_LINE_NUMS,
+                              0);
+       bc = yasm_bc_create_common(&cv8_lineinfo_bc_callback, li, 0);
+       bc->len = 24+li->num_linenums*8;
+       yasm_cv__append_bc(info.debug_symline, bc);
+       cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
+    }
+
+    /* Already aligned 4 */
+
+    /* Output debugging symbols */
+    head = cv8_add_symhead(dbgfmt_cv, info.debug_symline, CV8_DEBUG_SYMS, 0);
+    /* add object and compile flag first */
+    cv8_add_sym_objname(dbgfmt_cv, info.debug_symline,
+       cv_make_pathname(yasm_object_get_object_fn(dbgfmt_cv->object)));
+    cv8_add_sym_compile(dbgfmt_cv, info.debug_symline,
+                       yasm__xstrdup(PACKAGE_STRING));
+    /* then iterate through symbol table */
+    yasm_symtab_traverse(dbgfmt_cv->symtab, &info, cv_generate_sym);
+    cv8_set_symhead_end(head, yasm_section_bcs_last(info.debug_symline));
+
+    /* Align 4 at end */
+    bc = yasm_bc_create_align
+       (yasm_expr_create_ident(yasm_expr_int(yasm_intnum_create_uint(4)), 0),
+        NULL, NULL, NULL, 0);
+    yasm_bc_finalize(bc, yasm_cv__append_bc(info.debug_symline, bc));
+    yasm_bc_resolve(bc, 0, NULL);
+
+    return info.debug_symline;
+}
+
+static void
+cv_out_sym(yasm_symrec *sym, unsigned long off, yasm_bytecode *bc,
+          unsigned char **bufp, void *d, yasm_output_value_func output_value)
+{
+    yasm_value val;
+
+    /* sym in its section */
+    yasm_value_init_sym(&val, sym);
+    val.section_rel = 1;
+    output_value(&val, *bufp, 4, 32, 0, off, bc, 0, d);
+    *bufp += 4;
+
+    /* section index */
+    yasm_value_init_sym(&val, sym);
+    val.seg_of = 1;
+    output_value(&val, *bufp, 2, 16, 0, off+4, bc, 0, d);
+    *bufp += 2;
+}
+
+static cv8_symhead *
+cv8_add_symhead(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+               unsigned long type, int first)
+{
+    cv8_symhead *head;
+    yasm_bytecode *bc;
+
+    head = yasm_xmalloc(sizeof(cv8_symhead));
+    head->dbgfmt_cv = dbgfmt_cv;
+    head->type = type;
+    head->first = first;
+    head->start_prevbc = yasm_section_bcs_last(sect);
+
+    bc = yasm_bc_create_common(&cv8_symhead_bc_callback, head, 0);
+    if (first)
+       bc->len = 12;
+    else
+       bc->len = 8;
+
+    head->end_prevbc = bc;
+    yasm_cv__append_bc(sect, bc);
+    return head;
+}
+
+static void
+cv8_set_symhead_end(cv8_symhead *head, yasm_bytecode *end_prevbc)
+{
+    head->end_prevbc = end_prevbc;
+}
+
+static void
+cv8_symhead_bc_destroy(void *contents)
+{
+    yasm_xfree(contents);
+}
+
+static void
+cv8_symhead_bc_print(const void *contents, FILE *f, int indent_level)
+{
+    /* TODO */
+}
+
+static yasm_bc_resolve_flags
+cv8_symhead_bc_resolve(yasm_bytecode *bc, int save,
+                      yasm_calc_bc_dist_func calc_bc_dist)
+{
+    yasm_internal_error(N_("tried to resolve a codeview symhead bytecode"));
+    /*@notreached@*/
+    return YASM_BC_RESOLVE_MIN_LEN;
+}
+
+static int
+cv8_symhead_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                      yasm_output_value_func output_value,
+                      yasm_output_reloc_func output_reloc)
+{
+    cv8_symhead *head = (cv8_symhead *)bc->contents;
+    yasm_dbgfmt_cv *dbgfmt_cv = head->dbgfmt_cv;
+    unsigned char *buf = *bufp;
+    yasm_intnum *intn, *cval;
+
+    cval = yasm_intnum_create_uint(4);
+    /* Output "version" if first */
+    if (head->first) {
+       yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0,
+                                0);
+       buf += 4;
+    }
+
+    /* Type contained - 4 bytes */
+    yasm_intnum_set_uint(cval, head->type);
+    yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0, 0);
+    buf += 4;
+
+    /* Total length of info (following this field) - 4 bytes */
+    yasm_intnum_set_uint(cval, bc->len);
+    intn = yasm_common_calc_bc_dist(head->start_prevbc, head->end_prevbc);
+    yasm_intnum_calc(intn, YASM_EXPR_SUB, cval, bc->line);
+    yasm_arch_intnum_tobytes(dbgfmt_cv->arch, intn, buf, 4, 32, 0, bc, 0, 0);
+    buf += 4;
+    yasm_intnum_destroy(intn);
+
+    *bufp = buf;
+
+    yasm_intnum_destroy(cval);
+    return 0;
+}
+
+static yasm_bytecode *
+cv8_add_fileinfo(yasm_dbgfmt_cv *dbgfmt_cv, yasm_section *sect,
+                const cv_filename *fn)
+{
+    cv8_fileinfo *fi;
+    yasm_bytecode *bc;
+
+    fi = yasm_xmalloc(sizeof(cv8_fileinfo));
+    fi->dbgfmt_cv = dbgfmt_cv;
+    fi->fn = fn;
+
+    bc = yasm_bc_create_common(&cv8_fileinfo_bc_callback, fi, 0);
+    bc->len = 24;
+
+    yasm_cv__append_bc(sect, bc);
+    return bc;
+}
+
+static void
+cv8_fileinfo_bc_destroy(void *contents)
+{
+    yasm_xfree(contents);
+}
+
+static void
+cv8_fileinfo_bc_print(const void *contents, FILE *f, int indent_level)
+{
+    /* TODO */
+}
+
+static yasm_bc_resolve_flags
+cv8_fileinfo_bc_resolve(yasm_bytecode *bc, int save,
+                       yasm_calc_bc_dist_func calc_bc_dist)
+{
+    yasm_internal_error(N_("tried to resolve a codeview fileinfo bytecode"));
+    /*@notreached@*/
+    return YASM_BC_RESOLVE_MIN_LEN;
+}
+
+static int
+cv8_fileinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                       yasm_output_value_func output_value,
+                       yasm_output_reloc_func output_reloc)
+{
+    cv8_fileinfo *fi = (cv8_fileinfo *)bc->contents;
+    yasm_dbgfmt_cv *dbgfmt_cv = fi->dbgfmt_cv;
+    unsigned char *buf = *bufp;
+    yasm_intnum *intn, *cval;
+    int i;
+
+    /* Offset in filename string table */
+    cval = yasm_intnum_create_uint(fi->fn->str_off);
+    yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0, 0);
+    buf += 4;
+
+    /* Checksum type/length */
+    yasm_intnum_set_uint(cval, 0x0110);
+    yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 0, 0);
+    buf += 2;
+
+    /* Checksum */
+    for (i=0; i<16; i++)
+       YASM_WRITE_8(buf, fi->fn->digest[i]);
+
+    /* Pad */
+    YASM_WRITE_8(buf, 0);
+    YASM_WRITE_8(buf, 0);
+
+    *bufp = buf;
+
+    yasm_intnum_destroy(cval);
+    return 0;
+}
+
+static void
+cv8_lineinfo_bc_destroy(void *contents)
+{
+    cv8_lineinfo *li = (cv8_lineinfo *)contents;
+    cv8_lineset *ls1, *ls2;
+
+    /* delete line sets */
+    ls1 = STAILQ_FIRST(&li->linesets);
+    while (ls1) {
+       ls2 = STAILQ_NEXT(ls1, link);
+       yasm_xfree(ls1);
+       ls1 = ls2;
+    }
+
+    yasm_xfree(contents);
+}
+
+static void
+cv8_lineinfo_bc_print(const void *contents, FILE *f, int indent_level)
+{
+    /* TODO */
+}
+
+static yasm_bc_resolve_flags
+cv8_lineinfo_bc_resolve(yasm_bytecode *bc, int save,
+                       yasm_calc_bc_dist_func calc_bc_dist)
+{
+    yasm_internal_error(N_("tried to resolve a codeview linehead bytecode"));
+    /*@notreached@*/
+    return YASM_BC_RESOLVE_MIN_LEN;
+}
+
+static int
+cv8_lineinfo_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                       yasm_output_value_func output_value,
+                       yasm_output_reloc_func output_reloc)
+{
+    cv8_lineinfo *li = (cv8_lineinfo *)bc->contents;
+    yasm_dbgfmt_cv *dbgfmt_cv = li->dbgfmt_cv;
+    unsigned char *buf = *bufp;
+    yasm_intnum *cval;
+    unsigned long i;
+    cv8_lineset *ls;
+
+    /* start offset and section */
+    cv_out_sym(li->sectsym, 0, bc, &buf, d, output_value);
+
+    /* Two bytes of pad/alignment */
+    YASM_WRITE_8(buf, 0);
+    YASM_WRITE_8(buf, 0);
+
+    /* Section length covered by line number info */
+    cval = yasm_common_calc_bc_dist(yasm_section_bcs_first(li->sect),
+                                   yasm_section_bcs_last(li->sect));
+    yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0, 0);
+    buf += 4;
+
+    /* Offset of source file in info table */
+    yasm_intnum_set_uint(cval, li->fn->info_off);
+    yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0, 0);
+    buf += 4;
+
+    /* Number of line number pairs */
+    yasm_intnum_set_uint(cval, li->num_linenums);
+    yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0, 0);
+    buf += 4;
+
+    /* Number of bytes of line number pairs + 12 (no, I don't know why) */
+    yasm_intnum_set_uint(cval, li->num_linenums*8+12);
+    yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 0, 0);
+    buf += 4;
+
+    /* Offset / line number pairs */
+    i = 0;
+    STAILQ_FOREACH(ls, &li->linesets, link) {
+       unsigned long j;
+       for (j=0; i<li->num_linenums && j<126; i++, j++) {
+           /* offset in section */
+           yasm_intnum_set_uint(cval, ls->pairs[j].offset);
+           yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc,
+                                    0, 0);
+           buf += 4;
+
+           /* line number in file */
+           yasm_intnum_set_uint(cval, ls->pairs[j].line);
+           yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc,
+                                    0, 0);
+           buf += 4;
+       }
+    }
+
+    *bufp = buf;
+
+    yasm_intnum_destroy(cval);
+    return 0;
+}
+
+static unsigned long
+cv_sym_size(const cv_sym *cvs)
+{
+    const char *ch = cvs->format;
+    unsigned long len = 4;  /* sym length and type */
+    unsigned long slen;
+    int arg = 0;
+
+    while (*ch) {
+       switch (*ch) {
+           case 'b':
+               len++;
+               arg++;
+               break;
+           case 'h':
+               len += 2;
+               arg++;
+               break;
+           case 'w':
+               len += 4;
+               arg++;
+               break;
+           case 'Y':
+               len += 6;       /* XXX: will be 4 in 16-bit version */
+               arg++;
+               break;
+           case 'T':
+               len += 4;       /* XXX: will be 2 in CV4 */
+               arg++;
+               break;
+           case 'S':
+               len += 1;       /* XXX: is this 1 or 2? */
+               slen = strlen((const char *)cvs->args[arg++].p);
+               len += slen <= 0xff ? slen : 0xff;
+               break;
+           case 'Z':
+               len += strlen((const char *)cvs->args[arg++].p) + 1;
+               break;
+           default:
+               yasm_internal_error(N_("unknown sym format character"));
+       }
+       ch++;
+    }
+
+    return len;
+}
+
+static void
+cv_sym_bc_destroy(void *contents)
+{
+    cv_sym *cvs = (cv_sym *)contents;
+    const char *ch = cvs->format;
+    int arg = 0;
+
+    while (*ch) {
+       switch (*ch) {
+           case 'b':
+           case 'h':
+           case 'w':
+           case 'Y':
+           case 'T':
+               arg++;
+               break;  /* nothing to destroy */
+           case 'S':
+           case 'Z':
+               yasm_xfree(cvs->args[arg++].p);
+               break;
+           default:
+               yasm_internal_error(N_("unknown sym format character"));
+       }
+       ch++;
+    }
+
+    yasm_xfree(contents);
+}
+
+static void
+cv_sym_bc_print(const void *contents, FILE *f, int indent_level)
+{
+    /* TODO */
+}
+
+static yasm_bc_resolve_flags
+cv_sym_bc_resolve(yasm_bytecode *bc, int save,
+                 yasm_calc_bc_dist_func calc_bc_dist)
+{
+    yasm_internal_error(N_("tried to resolve a codeview sym bytecode"));
+    /*@notreached@*/
+    return YASM_BC_RESOLVE_MIN_LEN;
+}
+
+static int
+cv_sym_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                 yasm_output_value_func output_value,
+                 yasm_output_reloc_func output_reloc)
+{
+    cv_sym *cvs = (cv_sym *)bc->contents;
+    yasm_dbgfmt_cv *dbgfmt_cv = cvs->dbgfmt_cv;
+    unsigned char *buf = *bufp;
+    yasm_intnum *cval;
+    const char *ch = cvs->format;
+    size_t len;
+    int arg = 0;
+
+
+    /* Total length of record (following this field) - 2 bytes */
+    cval = yasm_intnum_create_uint(bc->len-2);
+    yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 1, 0);
+    buf += 2;
+
+    /* Type contained - 2 bytes */
+    yasm_intnum_set_uint(cval, cvs->type);
+    yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 0, 0);
+    buf += 2;
+
+    while (*ch) {
+       switch (*ch) {
+           case 'b':
+               YASM_WRITE_8(buf, cvs->args[arg].i);
+               arg++;
+               break;
+           case 'h':
+               yasm_intnum_set_uint(cval, cvs->args[arg++].i);
+               yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0,
+                                        bc, 0, 0);
+               buf += 2;
+               break;
+           case 'w':
+               yasm_intnum_set_uint(cval, cvs->args[arg++].i);
+               yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0,
+                                        bc, 0, 0);
+               buf += 4;
+               break;
+           case 'Y':
+               cv_out_sym((yasm_symrec *)cvs->args[arg++].p, 4, bc, &buf, d,
+                          output_value);
+               break;
+           case 'T':
+               yasm_intnum_set_uint(cval, cvs->args[arg++].i);
+               yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0,
+                                        bc, 0, 0);
+               buf += 4;       /* XXX: will be 2 in CV4 */
+               break;
+           case 'S':
+               len = strlen((char *)cvs->args[arg].p);
+               len = len <= 0xff ? len : 0xff;
+               YASM_WRITE_8(buf, len);
+               memcpy(buf, (char *)cvs->args[arg].p, len);
+               buf += len;
+               arg++;
+               break;
+           case 'Z':
+               len = strlen((char *)cvs->args[arg].p)+1;
+               memcpy(buf, (char *)cvs->args[arg].p, len);
+               buf += len;
+               arg++;
+               break;
+           default:
+               yasm_internal_error(N_("unknown leaf format character"));
+       }
+       ch++;
+    }
+
+    *bufp = buf;
+
+    yasm_intnum_destroy(cval);
+    return 0;
+}
diff --git a/modules/dbgfmts/codeview/cv-type.c b/modules/dbgfmts/codeview/cv-type.c
new file mode 100644 (file)
index 0000000..d326131
--- /dev/null
@@ -0,0 +1,779 @@
+/*
+ * CodeView debugging format - type information
+ *
+ *  Copyright (C) 2006  Peter Johnson
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the author nor the names of other contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <util.h>
+/*@unused@*/ RCSID("$Id$");
+
+#define YASM_LIB_INTERNAL
+#define YASM_BC_INTERNAL
+#include <libyasm.h>
+
+#include "cv-dbgfmt.h"
+
+enum cv_reservedtype {
+    /* Bitfields representation - type */
+    CV_TYPE_SPECIAL    = 0x00<<4,      /* Special */
+    CV_TYPE_SIGNED     = 0x01<<4,      /* Signed integral value */
+    CV_TYPE_UNSIGNED   = 0x02<<4,      /* Unsigned integral value */
+    CV_TYPE_BOOLEAN    = 0x03<<4,      /* Boolean */
+    CV_TYPE_REAL       = 0x04<<4,      /* Real */
+    CV_TYPE_COMPLEX    = 0x05<<4,      /* Complex */
+    CV_TYPE_SPECIAL2   = 0x06<<4,      /* Special2 */
+    CV_TYPE_REALINT    = 0x07<<4,      /* Really int value */
+
+    /* "size" of CV_TYPE_SPECIAL */
+    CV_SPECIAL_NOTYPE  = 0x00<<0,      /* No type */
+    CV_SPECIAL_ABS     = 0x01<<0,      /* Absolute symbol */
+    CV_SPECIAL_SEG     = 0x02<<0,      /* Segment */
+    CV_SPECIAL_VOID    = 0x03<<0,      /* Void */
+    CV_SPECIAL_CURRENCY        = 0x04<<0,      /* Basic 8-byte currency value */
+    CV_SPECIAL_NEARBSTR        = 0x05<<0,      /* Near Basic string */
+    CV_SPECIAL_FARBSTR = 0x06<<0,      /* Far Basic string */
+
+    /* Size of CV_TYPE_SIGNED, CV_TYPE_UNSIGNED, and CV_TYPE_BOOLEAN */
+    CV_INTEGER_1BYTE   = 0x00<<0,      /* 1 byte */
+    CV_INTEGER_2BYTE   = 0x01<<0,      /* 2 byte */
+    CV_INTEGER_4BYTE   = 0x02<<0,      /* 4 byte */
+    CV_INTEGER_8BYTE   = 0x03<<0,      /* 8 byte */
+
+    /* Size of CV_TYPE_REAL and CV_TYPE_COMPLEX */
+    CV_REAL_32BIT      = 0x00<<0,      /* 32 bit */
+    CV_REAL_64BIT      = 0x01<<0,      /* 64 bit */
+    CV_REAL_80BIT      = 0x02<<0,      /* 80 bit */
+    CV_REAL_128BIT     = 0x03<<0,      /* 128 bit */
+    CV_REAL_48BIT      = 0x04<<0,      /* 48 bit */
+
+    /* "size" of CV_TYPE_SPECIAL2 */
+    CV_SPECIAL2_BIT    = 0x00<<0,      /* Bit */
+    CV_SPECIAL2_PASCHAR        = 0x01<<0,      /* Pascal CHAR */
+
+    /* Size of CV_TYPE_REALINT */
+    CV_REALINT_CHAR    = 0x00<<0,      /* Char */
+    CV_REALINT_WCHAR   = 0x01<<0,      /* Wide character */
+    CV_REALINT_S2BYTE  = 0x02<<0,      /* 2-byte signed integer */
+    CV_REALINT_U2BYTE  = 0x03<<0,      /* 2-byte unsigned integer */
+    CV_REALINT_S4BYTE  = 0x04<<0,      /* 4-byte signed integer */
+    CV_REALINT_U4BYTE  = 0x05<<0,      /* 4-byte unsigned integer */
+    CV_REALINT_S8BYTE  = 0x06<<0,      /* 8-byte signed integer */
+    CV_REALINT_U8BYTE  = 0x07<<0,      /* 8-byte unsigned integer */
+
+    /* Mode */
+    CV_MODE_DIRECT     = 0x00<<8,      /* Direct; not a pointer */
+    CV_MODE_NEAR       = 0x01<<8,      /* Near pointer */
+    CV_MODE_FAR                = 0x02<<8,      /* Far pointer */
+    CV_MODE_HUGE       = 0x03<<8,      /* Huge pointer */
+    CV_MODE_NEAR32     = 0x04<<8,      /* 32-bit near pointer */
+    CV_MODE_FAR32      = 0x05<<8,      /* 32-bit far pointer */
+    CV_MODE_NEAR64     = 0x06<<8,      /* 64-bit near pointer */
+
+    /* Pure primitive type listing - based on above bitfields */
+
+    /* Special Types */
+    CV_T_NOTYPE                = 0x0000, /* Uncharacterized type (no type) */
+    CV_T_ABS           = 0x0001, /* Absolute symbol */
+    CV_T_SEGMENT       = 0x0002, /* Segment type */
+    CV_T_VOID          = 0x0003, /* Void */
+    CV_T_PVOID         = 0x0103, /* Near pointer to void */
+    CV_T_PFVOID                = 0x0203, /* Far pointer to void */
+    CV_T_PHVOID                = 0x0303, /* Huge pointer to void */
+    CV_T_32PVOID       = 0x0403, /* 32-bit near pointer to void */
+    CV_T_32PFVOID      = 0x0503, /* 32-bit far pointer to void */
+    CV_T_CURRENCY      = 0x0004, /* Basic 8-byte currency value */
+    CV_T_NBASICSTR     = 0x0005, /* Near Basic string */
+    CV_T_FBASICSTR     = 0x0006, /* Far Basic string */
+    CV_T_BIT           = 0x0060, /* Bit */
+    CV_T_PASCHAR       = 0x0061, /* Pascal CHAR */
+    /* Character Types */
+    CV_T_CHAR          = 0x0010, /* 8-bit signed */
+    CV_T_UCHAR         = 0x0020, /* 8-bit unsigned */
+    CV_T_PCHAR         = 0x0110, /* Near pointer to 8-bit signed */
+    CV_T_PUCHAR                = 0x0120, /* Near pointer to 8-bit unsigned */
+    CV_T_PFCHAR                = 0x0210, /* Far pointer to 8-bit signed */
+    CV_T_PFUCHAR       = 0x0220, /* Far pointer to 8-bit unsigned */
+    CV_T_PHCHAR                = 0x0310, /* Huge pointer to 8-bit signed */
+    CV_T_PHUCHAR       = 0x0320, /* Huge pointer to 8-bit unsigned */
+    CV_T_32PCHAR       = 0x0410, /* 16:32 near pointer to 8-bit signed */
+    CV_T_32PUCHAR      = 0x0420, /* 16:32 near pointer to 8-bit unsigned */
+    CV_T_32PFCHAR      = 0x0510, /* 16:32 far pointer to 8-bit signed */
+    CV_T_32PFUCHAR     = 0x0520, /* 16:32 far pointer to 8-bit unsigned */
+    /* Real Character Types */
+    CV_T_RCHAR         = 0x0070, /* Real char */
+    CV_T_PRCHAR                = 0x0170, /* Near pointer to a real char */
+    CV_T_PFRCHAR       = 0x0270, /* Far pointer to a real char */
+    CV_T_PHRCHAR       = 0x0370, /* Huge pointer to a real char */
+    CV_T_32PRCHAR      = 0x0470, /* 16:32 near pointer to a real char */
+    CV_T_32PFRCHAR     = 0x0570, /* 16:32 far pointer to a real char */
+    /* Wide Character Types */
+    CV_T_WCHAR         = 0x0071, /* Wide char */
+    CV_T_PWCHAR                = 0x0171, /* Near pointer to a wide char */
+    CV_T_PFWCHAR       = 0x0271, /* Far pointer to a wide char */
+    CV_T_PHWCHAR       = 0x0371, /* Huge pointer to a wide char */
+    CV_T_32PWCHAR      = 0x0471, /* 16:32 near pointer to a wide char */
+    CV_T_32PFWCHAR     = 0x0571, /* 16:32 far pointer to a wide char */
+    /* Real 16-bit Integer Types */
+    CV_T_INT2          = 0x0072, /* Real 16-bit signed int */
+    CV_T_UINT2         = 0x0073, /* Real 16-bit unsigned int */
+    CV_T_PINT2         = 0x0172, /* Near pointer to 16-bit signed int */
+    CV_T_PUINT2                = 0x0173, /* Near pointer to 16-bit unsigned int */
+    CV_T_PFINT2                = 0x0272, /* Far pointer to 16-bit signed int */
+    CV_T_PFUINT2       = 0x0273, /* Far pointer to 16-bit unsigned int */
+    CV_T_PHINT2                = 0x0372, /* Huge pointer to 16-bit signed int */
+    CV_T_PHUINT2       = 0x0373, /* Huge pointer to 16-bit unsigned int */
+    CV_T_32PINT2       = 0x0472, /* 16:32 near pointer to 16-bit signed int */
+    CV_T_32PUINT2      = 0x0473, /* 16:32 near pointer to 16-bit unsigned int */
+    CV_T_32PFINT2      = 0x0572, /* 16:32 far pointer to 16-bit signed int */
+    CV_T_32PFUINT2     = 0x0573, /* 16:32 far pointer to 16-bit unsigned int */
+    /* 16-bit Short Types */
+    CV_T_SHORT         = 0x0011, /* 16-bit signed */
+    CV_T_USHORT                = 0x0021, /* 16-bit unsigned */
+    CV_T_PSHORT                = 0x0111, /* Near pointer to 16-bit signed */
+    CV_T_PUSHORT       = 0x0121, /* Near pointer to 16-bit unsigned */
+    CV_T_PFSHORT       = 0x0211, /* Far pointer to 16-bit signed */
+    CV_T_PFUSHORT      = 0x0221, /* Far pointer to 16-bit unsigned */
+    CV_T_PHSHORT       = 0x0311, /* Huge pointer to 16-bit signed */
+    CV_T_PHUSHORT      = 0x0321, /* Huge pointer to 16-bit unsigned */
+    CV_T_32PSHORT      = 0x0411, /* 16:32 near pointer to 16-bit signed */
+    CV_T_32PUSHORT     = 0x0421, /* 16:32 near pointer to 16-bit unsigned */
+    CV_T_32PFSHORT     = 0x0511, /* 16:32 far pointer to 16-bit signed */
+    CV_T_32PFUSHORT    = 0x0521, /* 16:32 far pointer to 16-bit unsigned */
+    /* Real 32-bit Integer Types */
+    CV_T_INT4          = 0x0074, /* Real 32-bit signed int */
+    CV_T_UINT4         = 0x0075, /* Real 32-bit unsigned int */
+    CV_T_PINT4         = 0x0174, /* Near pointer to 32-bit signed int */
+    CV_T_PUINT4                = 0x0175, /* Near pointer to 32-bit unsigned int */
+    CV_T_PFINT4                = 0x0274, /* Far pointer to 32-bit signed int */
+    CV_T_PFUINT4       = 0x0275, /* Far pointer to 32-bit unsigned int */
+    CV_T_PHINT4                = 0x0374, /* Huge pointer to 32-bit signed int */
+    CV_T_PHUINT4       = 0x0375, /* Huge pointer to 32-bit unsigned int */
+    CV_T_32PINT4       = 0x0474, /* 16:32 near pointer to 32-bit signed int */
+    CV_T_32PUINT4      = 0x0475, /* 16:32 near pointer to 32-bit unsigned int */
+    CV_T_32PFINT4      = 0x0574, /* 16:32 far pointer to 32-bit signed int */
+    CV_T_32PFUINT4     = 0x0575, /* 16:32 far pointer to 32-bit unsigned int */
+    /* 32-bit Long Types */
+    CV_T_LONG          = 0x0012, /* 32-bit signed */
+    CV_T_ULONG         = 0x0022, /* 32-bit unsigned */
+    CV_T_PLONG         = 0x0112, /* Near pointer to 32-bit signed */
+    CV_T_PULONG                = 0x0122, /* Near pointer to 32-bit unsigned */
+    CV_T_PFLONG                = 0x0212, /* Far pointer to 32-bit signed */
+    CV_T_PFULONG       = 0x0222, /* Far pointer to 32-bit unsigned */
+    CV_T_PHLONG                = 0x0312, /* Huge pointer to 32-bit signed */
+    CV_T_PHULONG       = 0x0322, /* Huge pointer to 32-bit unsigned */
+    CV_T_32PLONG       = 0x0412, /* 16:32 near pointer to 32-bit signed */
+    CV_T_32PULONG      = 0x0422, /* 16:32 near pointer to 32-bit unsigned */
+    CV_T_32PFLONG      = 0x0512, /* 16:32 far pointer to 32-bit signed */
+    CV_T_32PFULONG     = 0x0522, /* 16:32 far pointer to 32-bit unsigned */
+    /* Real 64-bit int Types */
+    CV_T_INT8          = 0x0076, /* 64-bit signed int */
+    CV_T_UINT8         = 0x0077, /* 64-bit unsigned int */
+    CV_T_PINT8         = 0x0176, /* Near pointer to 64-bit signed int */
+    CV_T_PUINT8                = 0x0177, /* Near pointer to 64-bit unsigned int */
+    CV_T_PFINT8                = 0x0276, /* Far pointer to 64-bit signed int */
+    CV_T_PFUINT8       = 0x0277, /* Far pointer to 64-bit unsigned int */
+    CV_T_PHINT8                = 0x0376, /* Huge pointer to 64-bit signed int */
+    CV_T_PHUINT8       = 0x0377, /* Huge pointer to 64-bit unsigned int */
+    CV_T_32PINT8       = 0x0476, /* 16:32 near pointer to 64-bit signed int */
+    CV_T_32PUINT8      = 0x0477, /* 16:32 near pointer to 64-bit unsigned int */
+    CV_T_32PFINT8      = 0x0576, /* 16:32 far pointer to 64-bit signed int */
+    CV_T_32PFUINT8     = 0x0577, /* 16:32 far pointer to 64-bit unsigned int */
+    /* 64-bit Integral Types */
+    CV_T_QUAD          = 0x0013, /* 64-bit signed */
+    CV_T_UQUAD         = 0x0023, /* 64-bit unsigned */
+    CV_T_PQUAD         = 0x0113, /* Near pointer to 64-bit signed */
+    CV_T_PUQUAD                = 0x0123, /* Near pointer to 64-bit unsigned */
+    CV_T_PFQUAD                = 0x0213, /* Far pointer to 64-bit signed */
+    CV_T_PFUQUAD       = 0x0223, /* Far pointer to 64-bit unsigned */
+    CV_T_PHQUAD                = 0x0313, /* Huge pointer to 64-bit signed */
+    CV_T_PHUQUAD       = 0x0323, /* Huge pointer to 64-bit unsigned */
+    CV_T_32PQUAD       = 0x0413, /* 16:32 near pointer to 64-bit signed */
+    CV_T_32PUQUAD      = 0x0423, /* 16:32 near pointer to 64-bit unsigned */
+    CV_T_32PFQUAD      = 0x0513, /* 16:32 far pointer to 64-bit signed */
+    CV_T_32PFUQUAD     = 0x0523, /* 16:32 far pointer to 64-bit unsigned */
+    /* 32-bit Real Types */
+    CV_T_REAL32                = 0x0040, /* 32-bit real */
+    CV_T_PREAL32       = 0x0140, /* Near pointer to 32-bit real */
+    CV_T_PFREAL32      = 0x0240, /* Far pointer to 32-bit real */
+    CV_T_PHREAL32      = 0x0340, /* Huge pointer to 32-bit real */
+    CV_T_32PREAL32     = 0x0440, /* 16:32 near pointer to 32-bit real */
+    CV_T_32PFREAL32    = 0x0540, /* 16:32 far pointer to 32-bit real */
+    /* 48-bit Real Types */
+    CV_T_REAL48                = 0x0044, /* 48-bit real */
+    CV_T_PREAL48       = 0x0144, /* Near pointer to 48-bit real */
+    CV_T_PFREAL48      = 0x0244, /* Far pointer to 48-bit real */
+    CV_T_PHREAL48      = 0x0344, /* Huge pointer to 48-bit real */
+    CV_T_32PREAL48     = 0x0444, /* 16:32 near pointer to 48-bit real */
+    CV_T_32PFREAL48    = 0x0544, /* 16:32 far pointer to 48-bit real */
+    /* 64-bit Real Types */
+    CV_T_REAL64                = 0x0041, /* 64-bit real */
+    CV_T_PREAL64       = 0x0141, /* Near pointer to 64-bit real */
+    CV_T_PFREAL64      = 0x0241, /* Far pointer to 64-bit real */
+    CV_T_PHREAL64      = 0x0341, /* Huge pointer to 64-bit real */
+    CV_T_32PREAL64     = 0x0441, /* 16:32 near pointer to 64-bit real */
+    CV_T_32PFREAL64    = 0x0541, /* 16:32 far pointer to 64-bit real */
+    /* 80-bit Real Types */
+    CV_T_REAL80                = 0x0042, /* 80-bit real */
+    CV_T_PREAL80       = 0x0142, /* Near pointer to 80-bit real */
+    CV_T_PFREAL80      = 0x0242, /* Far pointer to 80-bit real */
+    CV_T_PHREAL80      = 0x0342, /* Huge pointer to 80-bit real */
+    CV_T_32PREAL80     = 0x0442, /* 16:32 near pointer to 80-bit real */
+    CV_T_32PFREAL80    = 0x0542, /* 16:32 far pointer to 80-bit real */
+    /* 128-bit Real Types */
+    CV_T_REAL128       = 0x0043, /* 128-bit real */
+    CV_T_PREAL128      = 0x0143, /* Near pointer to 128-bit real */
+    CV_T_PFREAL128     = 0x0243, /* Far pointer to 128-bit real */
+    CV_T_PHREAL128     = 0x0343, /* Huge pointer to 128-bit real */
+    CV_T_32PREAL128    = 0x0443, /* 16:32 near pointer to 128-bit real */
+    CV_T_32PFREAL128   = 0x0543, /* 16:32 far pointer to 128-bit real */
+    /* 32-bit Complex Types */
+    CV_T_CPLX32                = 0x0050, /* 32-bit complex */
+    CV_T_PCPLX32       = 0x0150, /* Near pointer to 32-bit complex */
+    CV_T_PFCPLX32      = 0x0250, /* Far pointer to 32-bit complex */
+    CV_T_PHCPLX32      = 0x0350, /* Huge pointer to 32-bit complex */
+    CV_T_32PCPLX32     = 0x0450, /* 16:32 near pointer to 32-bit complex */
+    CV_T_32PFCPLX32    = 0x0550, /* 16:32 far pointer to 32-bit complex */
+    /* 64-bit Complex Types */
+    CV_T_CPLX64                = 0x0051, /* 64-bit complex */
+    CV_T_PCPLX64       = 0x0151, /* Near pointer to 64-bit complex */
+    CV_T_PFCPLX64      = 0x0251, /* Far pointer to 64-bit complex */
+    CV_T_PHCPLX64      = 0x0351, /* Huge pointer to 64-bit complex */
+    CV_T_32PCPLX64     = 0x0451, /* 16:32 near pointer to 64-bit complex */
+    CV_T_32PFCPLX64    = 0x0551, /* 16:32 far pointer to 64-bit complex */
+    /* 80-bit Complex Types */
+    CV_T_CPLX80                = 0x0052, /* 80-bit complex */
+    CV_T_PCPLX80       = 0x0152, /* Near pointer to 80-bit complex */
+    CV_T_PFCPLX80      = 0x0252, /* Far pointer to 80-bit complex */
+    CV_T_PHCPLX80      = 0x0352, /* Huge pointer to 80-bit complex */
+    CV_T_32PCPLX80     = 0x0452, /* 16:32 near pointer to 80-bit complex */
+    CV_T_32PFCPLX80    = 0x0552, /* 16:32 far pointer to 80-bit complex */
+    /* 128-bit Complex Types */
+    CV_T_CPLX128       = 0x0053, /* 128-bit complex */
+    CV_T_PCPLX128      = 0x0153, /* Near pointer to 128-bit complex */
+    CV_T_PFCPLX128     = 0x0253, /* Far pointer to 128-bit complex */
+    CV_T_PHCPLX128     = 0x0353, /* Huge pointer to 128-bit real */
+    CV_T_32PCPLX128    = 0x0453, /* 16:32 near pointer to 128-bit complex */
+    CV_T_32PFCPLX128   = 0x0553, /* 16:32 far pointer to 128-bit complex */
+    /* Boolean Types */
+    CV_T_BOOL08                = 0x0030, /* 8-bit Boolean */
+    CV_T_BOOL16                = 0x0031, /* 16-bit Boolean */
+    CV_T_BOOL32                = 0x0032, /* 32-bit Boolean */
+    CV_T_BOOL64                = 0x0033, /* 64-bit Boolean */
+    CV_T_PBOOL08       = 0x0130, /* Near pointer to 8-bit Boolean */
+    CV_T_PBOOL16       = 0x0131, /* Near pointer to 16-bit Boolean */
+    CV_T_PBOOL32       = 0x0132, /* Near pointer to 32-bit Boolean */
+    CV_T_PBOOL64       = 0x0133, /* Near pointer to 64-bit Boolean */
+    CV_T_PFBOOL08      = 0x0230, /* Far pointer to 8-bit Boolean */
+    CV_T_PFBOOL16      = 0x0231, /* Far pointer to 16-bit Boolean */
+    CV_T_PFBOOL32      = 0x0232, /* Far pointer to 32-bit Boolean */
+    CV_T_PFBOOL32      = 0x0233, /* Far pointer to 64-bit Boolean */
+    CV_T_PHBOOL08      = 0x0330, /* Huge pointer to 8-bit Boolean */
+    CV_T_PHBOOL16      = 0x0331, /* Huge pointer to 16-bit Boolean */
+    CV_T_PHBOOL32      = 0x0332, /* Huge pointer to 32-bit Boolean */
+    CV_T_PHBOOL64      = 0x0333, /* Huge pointer to 64-bit Boolean */
+    CV_T_32PBOOL08     = 0x0430, /* 16:32 near pointer to 8-bit Boolean */
+    CV_T_32PBOOL16     = 0x0431, /* 16:32 near pointer to 16-bit Boolean */
+    CV_T_32PBOOL32     = 0x0432, /* 16:32 near pointer to 32-bit Boolean */
+    CV_T_32PBOOL64     = 0x0433, /* 16:32 near pointer to 64-bit Boolean */
+    CV_T_32PFBOOL08    = 0x0530, /* 16:32 far pointer to 8-bit Boolean */
+    CV_T_32PFBOOL16    = 0x0531, /* 16:32 far pointer to 16-bit Boolean */
+    CV_T_32PFBOOL32    = 0x0532, /* 16:32 far pointer to 32-bit Boolean */
+    CV_T_32PFBOOL64    = 0x0533, /* 16:32 far pointer to 64-bit Boolean */
+
+    /* Non-primitive types are stored in the TYPES section (generated in
+     * cv-type.c) and start at this index (e.g. 0x1000 is the first type
+     * in TYPES, 0x1001 the second, etc.
+     */
+    CV_FIRST_NONPRIM   = 0x1000
+};
+
+enum cv_leaftype {
+    /* Leaf indices for type records that can be referenced from symbols */
+    CV4_LF_MODIFIER    = 0x0001,       /* Type Modifier */
+    CV4_LF_POINTER     = 0x0002,       /* Pointer */
+    CV4_LF_ARRAY       = 0x0003,       /* Simple Array */
+    CV4_LF_CLASS       = 0x0004,       /* Classes */
+    CV4_LF_STRUCTURE   = 0x0005,       /* Structures */
+    CV4_LF_UNION       = 0x0006,       /* Unions */
+    CV4_LF_ENUM                = 0x0007,       /* Enumeration */
+    CV4_LF_PROCEDURE   = 0x0008,       /* Procedure */
+    CV4_LF_MFUNCTION   = 0x0009,       /* Member Function */
+    CV4_LF_VTSHAPE     = 0x000a,       /* Virtual Function Table Shape */
+    CV4_LF_BARRAY      = 0x000d,       /* Basic Array */
+    CV4_LF_LABEL       = 0x000e,       /* Label */
+    CV4_LF_NULL                = 0x000f,       /* Null */
+    CV4_LF_DIMARRAY    = 0x0011,       /* Multiply Dimensioned Array */
+    CV4_LF_VFTPATH     = 0x0012,       /* Path to Virtual Function Table */
+    CV4_LF_PRECOMP     = 0x0013,       /* Reference Precompiled Types */
+    CV4_LF_ENDPRECOMP  = 0x0014,       /* End of Precompiled Types */
+
+    /* CodeView 5.0 version */
+    CV5_LF_MODIFIER    = 0x1001,       /* Type Modifier */
+    CV5_LF_POINTER     = 0x1002,       /* Pointer */
+    CV5_LF_ARRAY       = 0x1003,       /* Simple Array */
+    CV5_LF_CLASS       = 0x1004,       /* Classes */
+    CV5_LF_STRUCTURE   = 0x1005,       /* Structures */
+    CV5_LF_UNION       = 0x1006,       /* Unions */
+    CV5_LF_ENUM                = 0x1007,       /* Enumeration */
+    CV5_LF_PROCEDURE   = 0x1008,       /* Procedure */
+    CV5_LF_MFUNCTION   = 0x1009,       /* Member Function */
+    CV5_LF_VTSHAPE     = 0x000a,       /* Virtual Function Table Shape */
+    CV5_LF_BARRAY      = 0x100d,       /* Basic Array */
+    CV5_LF_LABEL       = 0x000e,       /* Label */
+    CV5_LF_NULL                = 0x000f,       /* Null */
+    CV5_LF_DIMARRAY    = 0x100c,       /* Multiply Dimensioned Array */
+    CV5_LF_VFTPATH     = 0x100d,       /* Path to Virtual Function Table */
+    CV5_LF_PRECOMP     = 0x100e,       /* Reference Precompiled Types */
+    CV5_LF_ENDPRECOMP  = 0x0014,       /* End of Precompiled Types */
+    CV5_LF_TYPESERVER  = 0x0016,       /* Reference Typeserver */
+
+    /* Leaf indices for type records that can be referenced from other type
+     * records
+     */
+    CV4_LF_SKIP                = 0x0200,       /* Skip */
+    CV4_LF_ARGLIST     = 0x0201,       /* Argument List */
+    CV4_LF_DEFARG      = 0x0202,       /* Default Argument */
+    CV4_LF_LIST                = 0x0203,       /* Arbitrary List */
+    CV4_LF_FIELDLIST   = 0x0204,       /* Field List */
+    CV4_LF_DERIVED     = 0x0205,       /* Derived Classes */
+    CV4_LF_BITFIELD    = 0x0206,       /* Bit Fields */
+    CV4_LF_METHODLIST  = 0x0207,       /* Method List */
+    CV4_LF_DIMCONU     = 0x0208,       /* Dimensioned Array with Constant Upper Bound */
+    CV4_LF_DIMCONLU    = 0x0209,       /* Dimensioned Array with Constant Lower and Upper Bounds */
+    CV4_LF_DIMVARU     = 0x020a,       /* Dimensioned Array with Variable Upper Bound */
+    CV4_LF_DIMVARLU    = 0x020b,       /* Dimensioned Array with Variable Lower and Upper Bounds */
+    CV4_LF_REFSYM      = 0x020c,       /* Referenced Symbol */
+
+    /* CodeView 5.0 version */
+    CV5_LF_SKIP                = 0x1200,       /* Skip */
+    CV5_LF_ARGLIST     = 0x1201,       /* Argument List */
+    CV5_LF_DEFARG      = 0x1202,       /* Default Argument */
+    CV5_LF_FIELDLIST   = 0x1203,       /* Field List */
+    CV5_LF_DERIVED     = 0x1204,       /* Derived Classes */
+    CV5_LF_BITFIELD    = 0x1205,       /* Bit Fields */
+    CV5_LF_METHODLIST  = 0x1206,       /* Method List */
+    CV5_LF_DIMCONU     = 0x1207,       /* Dimensioned Array with Constant Upper Bound */
+    CV5_LF_DIMCONLU    = 0x1208,       /* Dimensioned Array with Constant Lower and Upper Bounds */
+    CV5_LF_DIMVARU     = 0x1209,       /* Dimensioned Array with Variable Upper Bound */
+    CV5_LF_DIMVARLU    = 0x120a,       /* Dimensioned Array with Variable Lower and Upper Bounds */
+    CV5_LF_REFSYM      = 0x020c,       /* Referenced Symbol */
+
+    /* Leaf indices for fields of complex lists */
+    CV4_LF_BCLASS      = 0x0400,       /* Real Base Class */
+    CV4_LF_VBCLASS     = 0x0401,       /* Direct Virtual Base Class */
+    CV4_LF_IVBCLASS    = 0x0402,       /* Indirect Virtual Base Class */
+    CV4_LF_ENUMERATE   = 0x0403,       /* Enumeration Name and Value */
+    CV4_LF_FRIENDFCN   = 0x0404,       /* Friend Function */
+    CV4_LF_INDEX       = 0x0405,       /* Index To Another Type Record */
+    CV4_LF_MEMBER      = 0x0406,       /* Data Member */
+    CV4_LF_STMEMBER    = 0x0407,       /* Static Data Member */
+    CV4_LF_METHOD      = 0x0408,       /* Method */
+    CV4_LF_NESTTYPE    = 0x0409,       /* Nested Type Definition */
+    CV4_LF_VFUNCTAB    = 0x040a,       /* Virtual Function Table Pointer */
+    CV4_LF_FRIENDCLS   = 0x040b,       /* Friend Class */
+    CV4_LF_ONEMETHOD   = 0x040c,       /* One Method */
+    CV4_LF_VFUNCOFF    = 0x040d,       /* Virtual Function Offset */
+
+    /* CodeView 5.0 version */
+    CV5_LF_BCLASS      = 0x1400,       /* Real Base Class */
+    CV5_LF_VBCLASS     = 0x1401,       /* Direct Virtual Base Class */
+    CV5_LF_IVBCLASS    = 0x1402,       /* Indirect Virtual Base Class */
+    CV5_LF_ENUMERATE   = 0x0403,       /* Enumeration Name and Value */
+    CV5_LF_FRIENDFCN   = 0x1403,       /* Friend Function */
+    CV5_LF_INDEX       = 0x1404,       /* Index To Another Type Record */
+    CV5_LF_MEMBER      = 0x1405,       /* Data Member */
+    CV5_LF_STMEMBER    = 0x1406,       /* Static Data Member */
+    CV5_LF_METHOD      = 0x1407,       /* Method */
+    CV5_LF_NESTTYPE    = 0x1408,       /* Nested Type Definition */
+    CV5_LF_VFUNCTAB    = 0x1409,       /* Virtual Function Table Pointer */
+    CV5_LF_FRIENDCLS   = 0x140a,       /* Friend Class */
+    CV5_LF_ONEMETHOD   = 0x140b,       /* One Method */
+    CV5_LF_VFUNCOFF    = 0x140c,       /* Virtual Function Offset */
+    CV5_LF_NESTTYPEEX  = 0x140d,       /* Nested Type Extended Definition */
+    CV5_LF_MEMBERMODIFY        = 0x140e,       /* Member Modification */
+    /* XXX: CodeView 5.0 spec also lists 0x040f as LF_MEMBERMODIFY? */
+
+    /* Leaf indices for numeric fields of symbols and type records */
+    CV_LF_NUMERIC      = 0x8000,
+    CV_LF_CHAR         = 0x8000,       /* Signed Char (8-bit) */
+    CV_LF_SHORT                = 0x8001,       /* Signed Short (16-bit) */
+    CV_LF_USHORT       = 0x8002,       /* Unsigned Short (16-bit) */
+    CV_LF_LONG         = 0x8003,       /* Signed Long (32-bit) */
+    CV_LF_ULONG                = 0x8004,       /* Unsigned Long (32-bit) */
+    CV_LF_REAL32       = 0x8005,       /* 32-bit Float */
+    CV_LF_REAL64       = 0x8006,       /* 64-bit Float */
+    CV_LF_REAL80       = 0x8007,       /* 80-bit Float */
+    CV_LF_REAL128      = 0x8008,       /* 128-bit Float */
+    CV_LF_QUADWORD     = 0x8009,       /* Signed Quad Word (64-bit) */
+    CV_LF_UQUADWORD    = 0x800a,       /* Unsigned Quad Word (64-bit) */
+    CV_LF_REAL48       = 0x800b,       /* 48-bit Float */
+    CV_LF_COMPLEX32    = 0x800c,       /* 32-bit Complex */
+    CV_LF_COMPLEX64    = 0x800d,       /* 64-bit Complex */
+    CV_LF_COMPLEX80    = 0x800e,       /* 80-bit Complex */
+    CV_LF_COMPLEX128   = 0x800f,       /* 128-bit Complex */
+    CV_LF_VARSTRING    = 0x8010,       /* Variable-length String */
+
+    /* Leaf padding bytes */
+    CV_LF_PAD0         = 0xf0,
+    CV_LF_PAD1         = 0xf1,
+    CV_LF_PAD2         = 0xf2,
+    CV_LF_PAD3         = 0xf3,
+    CV_LF_PAD4         = 0xf4,
+    CV_LF_PAD5         = 0xf5,
+    CV_LF_PAD6         = 0xf6,
+    CV_LF_PAD7         = 0xf7,
+    CV_LF_PAD8         = 0xf8,
+    CV_LF_PAD9         = 0xf9,
+    CV_LF_PAD10                = 0xfa,
+    CV_LF_PAD11                = 0xfb,
+    CV_LF_PAD12                = 0xfc,
+    CV_LF_PAD13                = 0xfc,
+    CV_LF_PAD14                = 0xfe,
+    CV_LF_PAD15                = 0xff
+};
+
+/* Leaves use a bit of meta-programming to encode formats: each character
+ * of format represents the output generated, as follows:
+ * 'b' : 1 byte value (integer)
+ * 'h' : 2 byte value (integer)
+ * 'w' : 4 byte value (integer)
+ * 'L' : subleaf, recurses into cv_leaf (pointer)
+ * 'T' : 4 byte type index, pulls cv_type.index from cv_type (pointer)
+ * 'S' : length-prefixed string (pointer)
+ */
+typedef struct cv_leaf {
+    enum cv_leaftype type;
+    const char *format;            /* format of args */
+    union {
+       unsigned long i;
+       void *p;
+    } args[6];
+} cv_leaf;
+
+typedef struct cv_type {
+    yasm_dbgfmt_cv *dbgfmt_cv;
+    unsigned long indx;            /* type # (must be same as output order) */
+    size_t num_leaves;
+    /*@null@*/ /*@only@*/ cv_leaf **leaves;
+} cv_type;
+
+/* Bytecode callback function prototypes */
+static void cv_type_bc_destroy(void *contents);
+static void cv_type_bc_print(const void *contents, FILE *f, int indent_level);
+static yasm_bc_resolve_flags cv_type_bc_resolve
+    (yasm_bytecode *bc, int save, yasm_calc_bc_dist_func calc_bc_dist);
+static int cv_type_bc_tobytes
+    (yasm_bytecode *bc, unsigned char **bufp, void *d,
+     yasm_output_value_func output_value,
+     /*@null@*/ yasm_output_reloc_func output_reloc);
+
+/* Bytecode callback structures */
+static const yasm_bytecode_callback cv_type_bc_callback = {
+    cv_type_bc_destroy,
+    cv_type_bc_print,
+    yasm_bc_finalize_common,
+    cv_type_bc_resolve,
+    cv_type_bc_tobytes
+};
+
+static cv_type *cv_type_create(yasm_dbgfmt_cv *dbgfmt_cv, unsigned long indx);
+static void cv_type_append_leaf(cv_type *type, /*@keep@*/ cv_leaf *leaf);
+
+
+static cv_leaf *
+cv_leaf_create_label(int is_far)
+{
+    cv_leaf *leaf = yasm_xmalloc(sizeof(cv_leaf));
+    leaf->type = CV5_LF_LABEL;
+    leaf->format = "h";
+    leaf->args[0].i = is_far ? 4 : 0;
+    return leaf;
+}
+
+yasm_section *
+yasm_cv__generate_type(yasm_dbgfmt_cv *dbgfmt_cv)
+{
+    int new;
+    unsigned long indx = CV_FIRST_NONPRIM;
+    yasm_section *debug_type;
+    yasm_bytecode *bc;
+    cv_type *type;
+
+    debug_type = yasm_object_get_general(dbgfmt_cv->object, ".debug$T", 0, 1,
+                                        0, 0, &new, 0);
+
+    /* Add label type */
+    type = cv_type_create(dbgfmt_cv, indx++);
+    cv_type_append_leaf(type, cv_leaf_create_label(0));
+    bc = yasm_bc_create_common(&cv_type_bc_callback, type, 0);
+    yasm_bc_finalize(bc, yasm_cv__append_bc(debug_type, bc));
+    yasm_bc_resolve(bc, 0, NULL);
+
+    return debug_type;
+}
+
+static void
+cv_leaf_destroy(cv_leaf *leaf)
+{
+    const char *ch = leaf->format;
+    int arg = 0;
+
+    while (*ch) {
+       switch (*ch) {
+           case 'b':
+           case 'h':
+           case 'w':
+               arg++;
+               break;  /* nothing to destroy */
+           case 'L':
+               cv_leaf_destroy((cv_leaf *)leaf->args[arg++].p);
+               break;
+           case 'T':
+               arg++;  /* nothing to destroy */
+               break;
+           case 'S':
+               yasm_xfree(leaf->args[arg++].p);
+               break;
+           default:
+               yasm_internal_error(N_("unknown leaf format character"));
+       }
+       ch++;
+    }
+}
+
+static unsigned long
+cv_leaf_size(const cv_leaf *leaf)
+{
+    const char *ch = leaf->format;
+    unsigned long len = 2;  /* leaf type */
+    unsigned long slen;
+    int arg = 0;
+
+    while (*ch) {
+       switch (*ch) {
+           case 'b':
+               len++;
+               arg++;
+               break;
+           case 'h':
+               len += 2;
+               arg++;
+               break;
+           case 'w':
+               len += 4;
+               arg++;
+               break;
+           case 'L':
+               len += cv_leaf_size((const cv_leaf *)leaf->args[arg++].p);
+               break;
+           case 'T':
+               len += 4;       /* XXX: will be 2 in CV4 */
+               arg++;
+               break;
+           case 'S':
+               len += 1;       /* XXX: is this 1 or 2? */
+               slen = strlen((const char *)leaf->args[arg++].p);
+               len += slen <= 0xff ? slen : 0xff;
+               break;
+           default:
+               yasm_internal_error(N_("unknown leaf format character"));
+       }
+       ch++;
+    }
+
+    return len;
+}
+
+static void
+cv_leaf_tobytes(const cv_leaf *leaf, yasm_bytecode *bc, yasm_arch *arch,
+               unsigned char **bufp, yasm_intnum *cval)
+{
+    unsigned char *buf = *bufp;
+    const char *ch = leaf->format;
+    size_t len;
+    int arg = 0;
+
+    /* leaf type */
+    yasm_intnum_set_uint(cval, leaf->type);
+    yasm_arch_intnum_tobytes(arch, cval, buf, 2, 16, 0, bc, 0, 0);
+    buf += 2;
+
+    while (*ch) {
+       switch (*ch) {
+           case 'b':
+               YASM_WRITE_8(buf, leaf->args[arg].i);
+               arg++;
+               break;
+           case 'h':
+               yasm_intnum_set_uint(cval, leaf->args[arg++].i);
+               yasm_arch_intnum_tobytes(arch, cval, buf, 2, 16, 0, bc, 0, 0);
+               buf += 2;
+               break;
+           case 'w':
+               yasm_intnum_set_uint(cval, leaf->args[arg++].i);
+               yasm_arch_intnum_tobytes(arch, cval, buf, 4, 32, 0, bc, 0, 0);
+               buf += 4;
+               break;
+           case 'L':
+               cv_leaf_tobytes((const cv_leaf *)leaf->args[arg++].p, bc, arch,
+                               &buf, cval);
+               break;
+           case 'T':
+               yasm_intnum_set_uint(cval,
+                   ((const cv_type *)leaf->args[arg++].p)->indx);
+               yasm_arch_intnum_tobytes(arch, cval, buf, 4, 32, 0, bc, 0, 0);
+               buf += 4;       /* XXX: will be 2 in CV4 */
+               break;
+           case 'S':
+               len = strlen((const char *)leaf->args[arg].p);
+               len = len <= 0xff ? len : 0xff;
+               YASM_WRITE_8(buf, len);
+               memcpy(buf, (const char *)leaf->args[arg].p, len);
+               buf += len;
+               arg++;
+               break;
+           default:
+               yasm_internal_error(N_("unknown leaf format character"));
+       }
+       ch++;
+    }
+
+    *bufp = buf;
+}
+
+static cv_type *
+cv_type_create(yasm_dbgfmt_cv *dbgfmt_cv, unsigned long indx)
+{
+    cv_type *type = yasm_xmalloc(sizeof(cv_type));
+
+    type->dbgfmt_cv = dbgfmt_cv;
+    type->indx = indx;
+    type->num_leaves = 0;
+
+    return type;
+}
+
+static void
+cv_type_append_leaf(cv_type *type, /*@keep@*/ cv_leaf *leaf)
+{
+    type->num_leaves++;
+
+    /* This is inefficient for large numbers of leaves, but that won't happen
+     * until we add structure support.
+     */
+    type->leaves = yasm_xrealloc(type->leaves,
+                                type->num_leaves*sizeof(cv_leaf *));
+
+    type->leaves[type->num_leaves-1] = leaf;
+}
+
+static void
+cv_type_bc_destroy(void *contents)
+{
+    cv_type *type = (cv_type *)contents;
+    size_t i;
+
+    for (i=0; i<type->num_leaves; i++)
+       cv_leaf_destroy(type->leaves[i]);
+    if (type->leaves)
+       yasm_xfree(type->leaves);
+    yasm_xfree(contents);
+}
+
+static void
+cv_type_bc_print(const void *contents, FILE *f, int indent_level)
+{
+    /* TODO */
+}
+
+static yasm_bc_resolve_flags
+cv_type_bc_resolve(yasm_bytecode *bc, int save,
+                  yasm_calc_bc_dist_func calc_bc_dist)
+{
+    cv_type *type = (cv_type *)bc->contents;
+    size_t i;
+
+    if (type->indx == CV_FIRST_NONPRIM)
+       bc->len = 4+2;
+    else
+       bc->len = 2;
+
+    for (i=0; i<type->num_leaves; i++)
+       bc->len += cv_leaf_size(type->leaves[i]);
+
+    /* Pad to multiple of 4 */
+    if (bc->len & 0x3)
+       bc->len += 4-(bc->len & 0x3);
+
+    return YASM_BC_RESOLVE_MIN_LEN;
+}
+
+static int
+cv_type_bc_tobytes(yasm_bytecode *bc, unsigned char **bufp, void *d,
+                  yasm_output_value_func output_value,
+                  yasm_output_reloc_func output_reloc)
+{
+    cv_type *type = (cv_type *)bc->contents;
+    yasm_dbgfmt_cv *dbgfmt_cv = type->dbgfmt_cv;
+    unsigned char *buf = *bufp;
+    yasm_intnum *cval;
+    size_t i;
+    unsigned long reclen = bc->len - 2;
+
+    cval = yasm_intnum_create_uint(4);     /* version */
+    if (type->indx == CV_FIRST_NONPRIM) {
+       yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 4, 32, 0, bc, 1,
+                                0);
+       buf += 4;
+       reclen -= 4;
+    }
+
+    /* Total length of record (following this field) - 2 bytes */
+    yasm_intnum_set_uint(cval, reclen);
+    yasm_arch_intnum_tobytes(dbgfmt_cv->arch, cval, buf, 2, 16, 0, bc, 1, 0);
+    buf += 2;
+
+    /* Leaves */
+    for (i=0; i<type->num_leaves; i++)
+       cv_leaf_tobytes(type->leaves[i], bc, dbgfmt_cv->arch, &buf, cval);
+
+    /* Pad to multiple of 4 */
+    switch ((buf-(*bufp)) & 0x3) {
+       case 3:
+           YASM_WRITE_8(buf, CV_LF_PAD3);
+       case 2:
+           YASM_WRITE_8(buf, CV_LF_PAD2);
+       case 1:
+           YASM_WRITE_8(buf, CV_LF_PAD1);
+       case 0:
+           break;
+    }
+
+    *bufp = buf;
+
+    yasm_intnum_destroy(cval);
+    return 0;
+}
diff --git a/modules/dbgfmts/codeview/cv8.txt b/modules/dbgfmts/codeview/cv8.txt
new file mode 100644 (file)
index 0000000..572b355
--- /dev/null
@@ -0,0 +1,86 @@
+   CV8 structures (for x86 and AMD64) - used by MSVC 8 (2005)
+   Everything listed in the order MASM seems to output it in.
+
+.debug$S: symbol and line number information
+    4 bytes - version (4)
+
+Each major portion of DEBUG$S starts with 4 byte type, 4 byte length
+(in bytes following the length field).  Each set is 4-byte aligned with 0s at
+the end (not included in length).
+
+0x000000F3: source filename string table
+    1 byte - 0 (0th filename)
+    0-terminated filename strings, 1 for each source file
+
+0x000000F4: source file info
+    for each source file:
+        4 bytes - offset of filename in source filename string table
+       {2 bytes - checksum type/length? (0x0110)
+        16 bytes - MD5 checksum of source file} OR
+       {2 bytes - no checksum (0)}
+       2 bytes - 0 (padding?)
+
+0x000000F2: line numbers for section
+    4 bytes - start offset in section (SECREL to section start)
+    2 bytes - section index (SECTION to section start)
+    2 bytes - pad/align (0)
+    4 bytes - section length covered by line number info
+    4 bytes - offset of source file in source file info table
+    4 bytes - number of line number pairs
+    4 bytes - number of bytes of line number pairs + 12
+
+    followed by pairs of:
+      4 bytes - offset in section
+      4 bytes - line number; if high bit is set,
+                end of statement/breakpointable (?) - e.g. lines containing
+               just labels should have line numbers
+
+0x000000F1: symbol information
+    enclosed data per below
+    (each element starts with 2 byte length, 2 byte type)
+    basically slightly updated versions of CV5 symbol info with 0-terminated
+    rather than length-prefixed strings
+
+0x1101 : Name of object file
+    4 byte signature (0 for asm)
+    0-terminated object filename
+0x1116 : creator signature (compile flag)
+    4 bytes - language (3=Masm)
+    4 bytes - target processor (0xD0 = AMD64)
+    4 bytes - flags
+    4 bytes - version
+    2 bytes - ?
+    0-terminated string containing creator name
+    2 alignment bytes? (0)
+0x1105 : Code Label 16:32/64
+    4 bytes SECREL of symbol
+    2 bytes SECTION of symbol
+    1 byte - flags
+    0-terminated string containing symbol name
+0x110C : local data 16:32/64
+    4 bytes type index of symbol
+    4 bytes SECREL of symbol
+    2 bytes SECTION of symbol
+    0-terminated string containing symbol name
+0x110D : global data 16:32/64
+    4 bytes type index of symbol
+    4 bytes SECREL of symbol
+    2 bytes SECTION of symbol
+    0-terminated string containing symbol name
+0x1110 : local/global (?) procedure start 16:32/64
+    4 bytes - parent
+    4 bytes - pend
+    4 bytes - pnext
+    4 bytes - procedure length (bytes)
+    4 bytes - debug start (offset from procedure start to frame setup)
+    4 bytes - debug end (offset from procedure start to frame cleanup)
+    4 bytes - type index of procedure type
+    4 bytes - offset of procedure (SECREL of symbol)
+    2 bytes - segment of procedure (SECTION of symbol)
+    1 byte - flags
+    0-terminated string containing procedure name
+
+.debug$T: type information
+    4 bytes - version (4)
+    followed by type information per CV5 spec, padded to 4-byte boundaries
+
index 8c76e4c50ac1e310ed41d9f29d7bf16b7efffd4a..b74107a250701ac67ea1e9a1082b853f6e0fe40c 100644 (file)
@@ -16,7 +16,7 @@
 00 
 00 
 00 
-04 
+00 
 00 
 2e 
 74 
index 4cf329a06a35515ad86ced3ba3c5dc187556fb0e..1ad5d884ccb4129121686744690bab0a3a752b52 100644 (file)
@@ -114,6 +114,7 @@ typedef struct coff_section_data {
     unsigned long nreloc;   /* number of relocation entries >64k -> error */
     unsigned long flags2;   /* internal flags (see COFF_FLAG_* above) */
     unsigned long strtab_name; /* strtab offset of name if name > 8 chars */
+    int isdebug;           /* is a debug section? */
 } coff_section_data;
 
 typedef enum coff_symrec_sclass {
@@ -357,6 +358,7 @@ coff_objfmt_init_new_section(yasm_objfmt_coff *objfmt_coff, yasm_section *sect,
     data->nreloc = 0;
     data->flags2 = 0;
     data->strtab_name = 0;
+    data->isdebug = 0;
     yasm_section_add_data(sect, &coff_section_data_cb, data);
 
     sym = yasm_symtab_define_label(objfmt_coff->symtab, sectname,
@@ -382,9 +384,16 @@ coff_objfmt_init_remaining_section(yasm_section *sect, /*@null@*/ void *d)
     csd = yasm_section_get_data(sect, &coff_section_data_cb);
     if (!csd) {
        /* Initialize new one */
-       csd = coff_objfmt_init_new_section(info->objfmt_coff, sect,
-                                          yasm_section_get_name(sect), 0);
-       csd->flags = COFF_STYP_TEXT;
+       const char *sectname = yasm_section_get_name(sect);
+       csd = coff_objfmt_init_new_section(info->objfmt_coff, sect, sectname,
+                                          0);
+       if (yasm__strncasecmp(sectname, ".debug", 6)==0) {
+           csd->flags = COFF_STYP_DATA;
+           if (info->objfmt_coff->win32)
+               csd->flags |= COFF_STYP_DISCARD|COFF_STYP_READ;
+           csd->isdebug = 1;
+       } else
+           csd->flags = COFF_STYP_TEXT;
     }
 
     return 0;
@@ -448,7 +457,8 @@ coff_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
 
     /* Handle other expressions, with relocation if necessary */
     if (value->rshift > 0
-       || (value->seg_of && (value->wrt || value->curpos_rel))) {
+       || (value->seg_of && (value->wrt || value->curpos_rel))
+       || (value->section_rel && (value->wrt || value->curpos_rel))) {
        yasm__error(bc->line, N_("coff: relocation too complex"));
        return 1;
     }
@@ -536,8 +546,8 @@ coff_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
                intn_minus = bc->offset;
        }
 
-       if (value->seg_of) {
-           /* Segment generation; zero value. */
+       if (value->seg_of || value->section_rel) {
+           /* Segment or section-relative generation; zero value. */
            intn_val = 0;
            intn_minus = 0;
        }
@@ -598,6 +608,13 @@ coff_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
                reloc->type = COFF_RELOC_AMD64_SECTION;
            else
                yasm_internal_error(N_("coff objfmt: unrecognized machine"));
+       } else if (value->section_rel) {
+           if (objfmt_coff->machine == COFF_MACHINE_I386)
+               reloc->type = COFF_RELOC_I386_SECREL;
+           else if (objfmt_coff->machine == COFF_MACHINE_AMD64)
+               reloc->type = COFF_RELOC_AMD64_SECREL;
+           else
+               yasm_internal_error(N_("coff objfmt: unrecognized machine"));
        } else {
            if (objfmt_coff->machine == COFF_MACHINE_I386) {
                if (info->csd->flags2 & COFF_FLAG_NOBASE)
@@ -732,7 +749,8 @@ coff_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
        }
     }
 
-    csd->addr = info->addr;
+    if (!csd->isdebug)
+       csd->addr = info->addr;
 
     if ((csd->flags & COFF_STYP_STD_MASK) == COFF_STYP_BSS) {
        yasm_bytecode *last = yasm_section_bcs_last(sect);
@@ -766,7 +784,8 @@ coff_objfmt_output_section(yasm_section *sect, /*@null@*/ void *d)
     if (csd->size == 0)
        return 0;
 
-    info->addr += csd->size;
+    if (!csd->isdebug)
+       info->addr += csd->size;
     csd->scnptr = (unsigned long)pos;
 
     /* No relocations to output?  Go on to next section */
@@ -863,11 +882,16 @@ coff_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
     } else
        strncpy((char *)localbuf, yasm_section_get_name(sect), 8);
     localbuf += 8;
-    YASM_WRITE_32_L(localbuf, csd->addr);      /* physical address */
-    if (COFF_SET_VMA)
-       YASM_WRITE_32_L(localbuf, csd->addr);   /* virtual address */
-    else
+    if (csd->isdebug) {
+       YASM_WRITE_32_L(localbuf, 0);           /* physical address */
        YASM_WRITE_32_L(localbuf, 0);           /* virtual address */
+    } else {
+       YASM_WRITE_32_L(localbuf, csd->addr);   /* physical address */
+       if (COFF_SET_VMA)
+           YASM_WRITE_32_L(localbuf, csd->addr);/* virtual address */
+       else
+           YASM_WRITE_32_L(localbuf, 0);       /* virtual address */
+    }
     YASM_WRITE_32_L(localbuf, csd->size);      /* section size */
     YASM_WRITE_32_L(localbuf, csd->scnptr);    /* file ptr to data */
     YASM_WRITE_32_L(localbuf, csd->relptr);    /* file ptr to relocs */
@@ -1084,8 +1108,7 @@ coff_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
 }
 
 static void
-coff_objfmt_output(yasm_objfmt *objfmt, FILE *f, int all_syms,
-                  /*@unused@*/ yasm_dbgfmt *df)
+coff_objfmt_output(yasm_objfmt *objfmt, FILE *f, int all_syms, yasm_dbgfmt *df)
 {
     yasm_objfmt_coff *objfmt_coff = (yasm_objfmt_coff *)objfmt;
     coff_objfmt_output_info info;
@@ -1178,7 +1201,9 @@ coff_objfmt_output(yasm_objfmt *objfmt, FILE *f, int all_syms,
     YASM_WRITE_32_L(localbuf, symtab_count);           /* number of symtabs */
     YASM_WRITE_16_L(localbuf, 0);      /* size of optional header (none) */
     /* flags */
-    flags = COFF_F_LNNO;
+    flags = 0;
+    if (strcmp(yasm_dbgfmt_keyword(df), "null")==0)
+       flags = COFF_F_LNNO;
     if (!all_syms)
        flags |= COFF_F_LSYMS;
     if (objfmt_coff->machine != COFF_MACHINE_AMD64)
@@ -1709,13 +1734,21 @@ yasm_objfmt_module yasm_coff_LTX_objfmt = {
     coff_objfmt_directive
 };
 
+/* Define valid debug formats to use with this object format */
+static const char *winXX_objfmt_dbgfmt_keywords[] = {
+    "null",
+    "dwarf2",
+    "cv8",
+    NULL
+};
+
 /* Define objfmt structure -- see objfmt.h for details */
 yasm_objfmt_module yasm_win32_LTX_objfmt = {
     "Win32",
     "win32",
     "obj",
     32,
-    coff_objfmt_dbgfmt_keywords,
+    winXX_objfmt_dbgfmt_keywords,
     "null",
     win32_objfmt_create,
     coff_objfmt_output,
@@ -1734,7 +1767,7 @@ yasm_objfmt_module yasm_win64_LTX_objfmt = {
     "win64",
     "obj",
     64,
-    coff_objfmt_dbgfmt_keywords,
+    winXX_objfmt_dbgfmt_keywords,
     "null",
     win64_objfmt_create,
     coff_objfmt_output,
index a8b3ce888531d596a3704d6cd8afb02ba8b2194c..8867bcc18b52527db8624b814528153dd8f5c2af 100644 (file)
@@ -322,7 +322,7 @@ elf_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
     }
 
     /* Handle other expressions, with relocation if necessary */
-    if (value->seg_of || value->rshift > 0) {
+    if (value->seg_of || value->section_rel || value->rshift > 0) {
        yasm__error(bc->line, N_("elf: relocation too complex"));
        return 1;
     }
index 1c11d232d695d17f19ccc798fdeb491dca0f6f8f..c454e55ccae26ba2c760952664c22f3c4f7edef1 100644 (file)
@@ -188,6 +188,11 @@ xdf_objfmt_output_value(yasm_value *value, unsigned char *buf, size_t destsize,
            return 0;
     }
 
+    if (value->section_rel) {
+       yasm__error(bc->line, N_("xdf: relocation too complex"));
+       return 1;
+    }
+
     intn_minus = 0;
     if (value->rel) {
        xdf_reloc *reloc;