From: Peter Johnson Date: Mon, 27 Mar 2006 02:15:19 +0000 (-0000) Subject: First cut at CodeView (version "8" / 2005 only). Completely untested. X-Git-Tag: v0.5.0rc2~5^2~14 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=93660bd073ad1009ff7b73a60121e2ca04133ac9;p=yasm First cut at CodeView (version "8" / 2005 only). Completely untested. * 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 --- diff --git a/Mkfiles/dj/config.h b/Mkfiles/dj/config.h index 0400cc1e..1cf2cbb9 100644 --- a/Mkfiles/dj/config.h +++ b/Mkfiles/dj/config.h @@ -1,6 +1,8 @@ /* $Id$ */ #define yasm__splitpath(path, tail) yasm__splitpath_win(path, tail) +#define YASM_PATHSEP '\\' + /* */ /* #undef ENABLE_NLS */ diff --git a/Mkfiles/vc/config.h b/Mkfiles/vc/config.h index ad3d2b02..888017e9 100644 --- a/Mkfiles/vc/config.h +++ b/Mkfiles/vc/config.h @@ -1,6 +1,7 @@ /* $Id$ */ #define yasm__splitpath(path, tail) yasm__splitpath_win(path, tail) +#define YASM_PATHSEP '\\' /* */ /* #undef ENABLE_NLS */ diff --git a/Mkfiles/vc8/config.h b/Mkfiles/vc8/config.h index 02e28e48..663a7e5e 100644 --- a/Mkfiles/vc8/config.h +++ b/Mkfiles/vc8/config.h @@ -1,6 +1,7 @@ /* $Id: config.h 1137 2004-09-04 01:24:57Z peter $ */ #define yasm__splitpath(path, tail) yasm__splitpath_win(path, tail) +#define YASM_PATHSEP '\\' #define _CRT_SECURE_NO_DEPRECATE 1 diff --git a/libyasm.h b/libyasm.h index b35d5e52..f0de97b3 100644 --- a/libyasm.h +++ b/libyasm.h @@ -86,6 +86,7 @@ #endif #include #include +#include #endif #endif diff --git a/libyasm/Makefile.inc b/libyasm/Makefile.inc index 0d0e610b..db5351cf 100644 --- a/libyasm/Makefile.inc +++ b/libyasm/Makefile.inc @@ -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 diff --git a/libyasm/coretype.h b/libyasm/coretype.h index 087b0ace..4c51ef0a 100644 --- a/libyasm/coretype.h +++ b/libyasm/coretype.h @@ -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 index 00000000..d53ef378 --- /dev/null +++ b/libyasm/md5.c @@ -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 + 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 +/*@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<>(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 + +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 index 00000000..52559a0d --- /dev/null +++ b/libyasm/md5.h @@ -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 */ diff --git a/libyasm/value.c b/libyasm/value.c index cc0e0e8c..9bae80a6 100644 --- a/libyasm/value.c +++ b/libyasm/value.c @@ -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 */ diff --git a/libyasm/value.h b/libyasm/value.h index 7873fb66..10f33b33 100644 --- a/libyasm/value.h +++ b/libyasm/value.h @@ -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) \ diff --git a/modules/dbgfmts/Makefile.inc b/modules/dbgfmts/Makefile.inc index 3dbfcf0d..cf0a5ffd 100644 --- a/modules/dbgfmts/Makefile.inc +++ b/modules/dbgfmts/Makefile.inc @@ -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 index 00000000..1a11f729 --- /dev/null +++ b/modules/dbgfmts/codeview/Makefile.inc @@ -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 index 00000000..ccf148ca --- /dev/null +++ b/modules/dbgfmts/codeview/cv-dbgfmt.c @@ -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 +/*@unused@*/ RCSID("$Id$"); + +#define YASM_LIB_INTERNAL +#define YASM_BC_INTERNAL +#include + +#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; ifilenames_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; ifilenames_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 index 00000000..0cf98990 --- /dev/null +++ b/modules/dbgfmts/codeview/cv-dbgfmt.h @@ -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 index 00000000..ec8495b5 --- /dev/null +++ b/modules/dbgfmts/codeview/cv-symline.c @@ -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 +#undef HAVE_CONFIG_H +#endif + +/* Need either unistd.h or direct.h (on Windows) to prototype getcwd() */ +#ifdef HAVE_UNISTD_H +#include +#elif defined(WIN32) || defined(_WIN32) +#include +#endif + +#include +/*@unused@*/ RCSID("$Id$"); + +#define YASM_LIB_INTERNAL +#define YASM_BC_INTERNAL +#include + +#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 (; filenumfilenames_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; ifilenames_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; ifilenames_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; ifilenames_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; ifilenames_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; inum_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 index 00000000..d3261313 --- /dev/null +++ b/modules/dbgfmts/codeview/cv-type.c @@ -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 +/*@unused@*/ RCSID("$Id$"); + +#define YASM_LIB_INTERNAL +#define YASM_BC_INTERNAL +#include + +#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; inum_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; inum_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; inum_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 index 00000000..572b355c --- /dev/null +++ b/modules/dbgfmts/codeview/cv8.txt @@ -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 + diff --git a/modules/dbgfmts/dwarf2/tests/passwin64/dwarfwin64_testhd.hex b/modules/dbgfmts/dwarf2/tests/passwin64/dwarfwin64_testhd.hex index 8c76e4c5..b74107a2 100644 --- a/modules/dbgfmts/dwarf2/tests/passwin64/dwarfwin64_testhd.hex +++ b/modules/dbgfmts/dwarf2/tests/passwin64/dwarfwin64_testhd.hex @@ -16,7 +16,7 @@ 00 00 00 -04 +00 00 2e 74 diff --git a/modules/objfmts/coff/coff-objfmt.c b/modules/objfmts/coff/coff-objfmt.c index 4cf329a0..1ad5d884 100644 --- a/modules/objfmts/coff/coff-objfmt.c +++ b/modules/objfmts/coff/coff-objfmt.c @@ -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, diff --git a/modules/objfmts/elf/elf-objfmt.c b/modules/objfmts/elf/elf-objfmt.c index a8b3ce88..8867bcc1 100644 --- a/modules/objfmts/elf/elf-objfmt.c +++ b/modules/objfmts/elf/elf-objfmt.c @@ -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; } diff --git a/modules/objfmts/xdf/xdf-objfmt.c b/modules/objfmts/xdf/xdf-objfmt.c index 1c11d232..c454e55c 100644 --- a/modules/objfmts/xdf/xdf-objfmt.c +++ b/modules/objfmts/xdf/xdf-objfmt.c @@ -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;