Index: /trunk/src/kmk/kmkbuiltin/kDepObj.c
===================================================================
--- /trunk/src/kmk/kmkbuiltin/kDepObj.c	(revision 2266)
+++ /trunk/src/kmk/kmkbuiltin/kDepObj.c	(revision 2267)
@@ -44,4 +44,5 @@
 #include "../../lib/k/kDefs.h"
 #include "../../lib/k/kTypes.h"
+#include "../../lib/k/kLdrFmts/pe.h"
 #include "../../lib/kDep.h"
 #include "kmkbuiltin.h"
@@ -73,5 +74,5 @@
 *   Structures and Typedefs                                                    *
 *******************************************************************************/
-/** @name OMF structure
+/** @name OMF Structures
  * @{ */
 #pragma pack(1)
@@ -117,4 +118,46 @@
 typedef KDEPOMFDEPFILE *PKDEPOMFDEPFILE;
 typedef const KDEPOMFDEPFILE *PCKDEPOMFDEPFILE;
+
+#pragma pack()
+/** @} */
+
+
+/** @name COFF Structures
+ * @{ */
+#pragma pack(1)
+
+typedef struct KDEPCVSYMHDR
+{
+    /** The record size minus the size field. */
+    KU16        cb;
+    /** The record type. */
+    KU16        uType;
+} KDEPCVSYMHDR;
+typedef KDEPCVSYMHDR *PKDEPCVSYMHDR;
+typedef const KDEPCVSYMHDR *PCKDEPCVSYMHDR;
+
+/** @name Selection of KDEPCVSYMHDR::uType values.
+ * @{ */
+#define K_CV8_S_MSTOOL      KU16_C(0x1116)
+/** @} */
+
+typedef struct KDEPCV8SYMHDR
+{
+    /** The record type. */
+    KU32        uType;
+    /** The record size minus the size field. */
+    KU32        cb;
+} KDEPCV8SYMHDR;
+typedef KDEPCV8SYMHDR *PKDEPCV8SYMHDR;
+typedef const KDEPCV8SYMHDR *PCKDEPCV8SYMHDR;
+
+/** @name Known KDEPCV8SYMHDR::uType Values.
+ * @{ */
+#define K_CV8_SYMBOL_INFO   KU32_C(0x000000f1)
+#define K_CV8_LINE_NUMBERS  KU32_C(0x000000f2)
+#define K_CV8_STRING_TABLE  KU32_C(0x000000f3)
+#define K_CV8_SOURCE_FILES  KU32_C(0x000000f4)
+#define K_CV8_COMDAT_XXXXX  KU32_C(0x000000f5) /**< no idea about the format... */
+/** @} */
 
 #pragma pack()
@@ -243,5 +286,5 @@
     PCKDEPOMFTHEADR pHdr = (PCKDEPOMFTHEADR)pbFile;
 
-    if (cbFile < sizeof(*pHdr))
+    if (cbFile <= sizeof(*pHdr))
         return K_FALSE;
     if (    pHdr->Hdr.bType != KDEPOMF_THEADR
@@ -252,4 +295,296 @@
     if (pHdr->Hdr.cbRec != 1 + pHdr->Name.cch + 1)
         return K_FALSE;
+
+    return K_TRUE;
+}
+
+
+/**
+ * Parses a CodeView 8 symbol section.
+ *
+ * @returns 0 on success, 1 on failure.
+ * @param   pbSyms      Pointer to the start of the symbol section.
+ * @param   cbSyms      Size of the symbol section.
+ */
+int kDepObjCOFFParseCV8SymbolSection(const KU8 *pbSyms, KSIZE cbSyms)
+{
+    char const *    pchStrTab  = NULL;
+    KU32            cbStrTab   = 0;
+    KPCUINT         uSrcFiles  = {0};
+    KU32            cbSrcFiles = 0;
+    KU32            off        = 4;
+    KU32            iSrc       = 0;
+
+    if (cbSyms < 16)
+        return 1;
+
+    /*
+     * The parsing loop.
+     */
+    while (off < cbSyms)
+    {
+        PCKDEPCV8SYMHDR pHdr = (PCKDEPCV8SYMHDR)(pbSyms + off);
+        KPCUINT         uData;
+        KU32            cbData;
+        uData.pv = pHdr + 1;
+
+        if (off + sizeof(*pHdr) >= cbSyms)
+        {
+            fprintf(stderr, "%s: CV symbol table entry at %08" KX32_PRI " is too long; cbSyms=%#" KSIZE_PRI "\n",
+                    argv0, off, cbSyms);
+            return 1; /* FIXME */
+        }
+
+        cbData = pHdr->cb;
+        if (off + cbData + sizeof(*pHdr) > cbSyms)
+        {
+            fprintf(stderr, "%s: CV symbol table entry at %08" KX32_PRI " is too long; cbData=%#" KX32_PRI " cbSyms=%#" KSIZE_PRI "\n",
+                    argv0, off, cbData, cbSyms);
+            return 1; /* FIXME */
+        }
+
+        /* If the size is 0, assume it covers the rest of the section. VC++ 2003 has
+           been observed doing thing. */
+        if (!cbData)
+            cbData = cbSyms - off;
+
+        switch (pHdr->uType)
+        {
+            case K_CV8_SYMBOL_INFO:
+                dprintf(("%06" KX32_PRI " %06" KX32_PRI ": Symbol Info\n", off, cbData));
+                /*dump(uData.pb, cbData, 0);*/
+                break;
+
+            case K_CV8_LINE_NUMBERS:
+                dprintf(("%06" KX32_PRI " %06" KX32_PRI ": Line numbers\n", off, cbData));
+                /*dump(uData.pb, cbData, 0);*/
+                break;
+
+            case K_CV8_STRING_TABLE:
+                dprintf(("%06" KX32_PRI " %06" KX32_PRI ": String table\n", off, cbData));
+                if (pchStrTab)
+                    fprintf(stderr, "%s: warning: Found yet another string table!\n");
+                pchStrTab = uData.pch;
+                cbStrTab = cbData;
+                /*dump(uData.pb, cbData, 0);*/
+                break;
+
+            case K_CV8_SOURCE_FILES:
+                dprintf(("%06" KX32_PRI " %06" KX32_PRI ": Source files\n", off, cbData));
+                if (uSrcFiles.pb)
+                    fprintf(stderr, "%s: warning: Found yet another source files table!\n");
+                uSrcFiles = uData;
+                cbSrcFiles = cbData;
+                /*dump(uData.pb, cbData, 0);*/
+                break;
+
+            case K_CV8_COMDAT_XXXXX:
+                dprintf(("%06" KX32_PRI " %06" KX32_PRI ": 0xf5 Unknown COMDAT stuff\n", off, cbData));
+                /*dump(uData.pb, cbData, 0);*/
+                break;
+
+            default:
+                dprintf(("%06" KX32_PRI " %06" KX32_PRI ": Unknown type %#" KX32_PRI "\n",
+                         off, cbData, pHdr->uType));
+                dump(uData.pb, cbData, 0);
+                break;
+        }
+
+        /* next */
+        cbData = (cbData + 3) & ~KU32_C(3);
+        off += cbData + sizeof(*pHdr);
+    }
+
+    /*
+     * Did we find any source files and strings?
+     */
+    if (!pchStrTab || !uSrcFiles.pv)
+    {
+        dprintf(("No cylindrical smoking thing: pchStrTab=%p uSrcFiles.pv=%p\n", pchStrTab, uSrcFiles.pv));
+        return 2;
+    }
+
+    /*
+     * Iterate the source file table.
+     */
+    off = 0;
+    while (off < cbSrcFiles)
+    {
+        KU32        offFile;
+        const char *pszFile;
+        KSIZE       cchFile;
+        KU16        u16Type;
+        KPCUINT     uSrc;
+        KU32        cbSrc;
+
+        /*
+         * Validate and parse the entry (variable length record are fun).
+         */
+        if (off + 8 > cbSrcFiles)
+        {
+            fprintf(stderr, "%s: CV source file entry at %08" KX32_PRI " is too long; cbSrcFiles=%#" KSIZE_PRI "\n",
+                    argv0, off, cbSrcFiles);
+            return 1;
+        }
+        uSrc.pb = uSrcFiles.pb + off;
+        u16Type = uSrc.pu16[2];
+        cbSrc = u16Type == 0x0110 ? 6 + 16 + 2 : 6 + 2;
+        if (off + cbSrc > cbSrcFiles)
+        {
+            fprintf(stderr, "%s: CV source file entry at %08" KX32_PRI " is too long; cbSrc=%#" KX32_PRI " cbSrcFiles=%#" KSIZE_PRI "\n",
+                    argv0, off, cbSrc, cbSrcFiles);
+            return 1;
+        }
+
+        offFile = *uSrc.pu32;
+        if (offFile > cbStrTab)
+        {
+            fprintf(stderr, "%s: CV source file entry at %08" KX32_PRI " is out side the string table; offFile=%#" KX32_PRI " cbStrTab=%#" KX32_PRI "\n",
+                    argv0, off, offFile, cbStrTab);
+            return 1;
+        }
+        pszFile = pchStrTab + offFile;
+        cchFile = strlen(pszFile);
+        if (cchFile == 0)
+        {
+            fprintf(stderr, "%s: CV source file entry at %08" KX32_PRI " has an empty file name; offFile=%#x" KX32_PRI "\n",
+                    argv0, off, offFile);
+            return 1;
+        }
+
+        /*
+         * Display the result and add it to the dependency database.
+         */
+        depAdd(pszFile, cchFile);
+        if (u16Type == 0x0110)
+            dprintf(("#%03" KU32_PRI ": {todo-md5-todo} '%s'\n",
+                     iSrc, pszFile));
+        else
+            dprintf(("#%03" KU32_PRI ": type=%#06" KX16_PRI " '%s'\n", iSrc, u16Type, pszFile));
+
+
+        /* next */
+        iSrc++;
+        off += cbSrc;
+    }
+
+    if (iSrc == 0)
+    {
+        dprintf(("No cylindrical smoking thing: iSrc=0\n"));
+        return 2;
+    }
+    dprintf(("iSrc=%" KU32_PRI "\n", iSrc));
+    return 0;
+}
+
+
+/**
+ * Parses the OMF file.
+ *
+ * @returns 0 on success, 1 on failure, 2 if no dependencies was found.
+ * @param   pbFile      The start of the file.
+ * @param   cbFile      The file size.
+ */
+int kDepObjCOFFParse(const KU8 *pbFile, KSIZE cbFile)
+{
+    IMAGE_FILE_HEADER const    *pFileHdr = (IMAGE_FILE_HEADER const *)pbFile;
+    IMAGE_SECTION_HEADER const *paSHdrs  = (IMAGE_SECTION_HEADER const *)((KU8 const *)(pFileHdr + 1) + pFileHdr->SizeOfOptionalHeader);
+    unsigned                    cSHdrs   = pFileHdr->NumberOfSections;
+    unsigned                    iSHdr;
+    KPCUINT                     u;
+    int                         rcRet    = 2;
+    int                         rc;
+
+    printf("COFF file!\n");
+
+    for (iSHdr = 0; iSHdr < cSHdrs; iSHdr++)
+    {
+        if (    !memcmp(paSHdrs[iSHdr].Name, ".debug$S", sizeof(".debug$S") - 1)
+            &&  paSHdrs[iSHdr].SizeOfRawData > 4)
+        {
+            u.pb = pbFile + paSHdrs[iSHdr].PointerToRawData;
+            dprintf(("CV symbol table: version=%x\n", *u.pu32));
+            if (*u.pu32 == 0x000000004)
+                rc = kDepObjCOFFParseCV8SymbolSection(u.pb, paSHdrs[iSHdr].SizeOfRawData);
+            else
+                rc = 2;
+            dprintf(("rc=%d\n", rc));
+            if (rcRet == 2)
+                rcRet = rc;
+            if (rcRet != 2)
+                return rc;
+        }
+        printf("#%d: %.8s\n", iSHdr, paSHdrs[iSHdr].Name);
+    }
+    return rcRet;
+}
+
+
+/**
+ * Checks if this file is a COFF file or not.
+ *
+ * @returns K_TRUE if it's COFF, K_FALSE otherwise.
+ *
+ * @param   pb      The start of the file.
+ * @param   cb      The file size.
+ */
+KBOOL kDepObjCOFFTest(const KU8 *pbFile, KSIZE cbFile)
+{
+    IMAGE_FILE_HEADER const    *pFileHdr = (IMAGE_FILE_HEADER const *)pbFile;
+    IMAGE_SECTION_HEADER const *paSHdrs  = (IMAGE_SECTION_HEADER const *)((KU8 const *)(pFileHdr + 1) + pFileHdr->SizeOfOptionalHeader);
+    unsigned                    cSHdrs   = pFileHdr->NumberOfSections;
+    unsigned                    iSHdr;
+    KSIZE                       cbHdrs   = (const KU8 *)&paSHdrs[cSHdrs] - (const KU8 *)pbFile;
+
+    if (cbFile <= sizeof(*pFileHdr))
+        return K_FALSE;
+    if (    pFileHdr->Machine != IMAGE_FILE_MACHINE_I386
+        &&  pFileHdr->Machine != IMAGE_FILE_MACHINE_AMD64)
+        return K_FALSE;
+    if (pFileHdr->SizeOfOptionalHeader != 0)
+        return K_FALSE; /* COFF files doesn't have an optional header */
+
+    if (    pFileHdr->NumberOfSections <= 1
+        ||  pFileHdr->NumberOfSections > cbFile)
+        return K_FALSE;
+
+    if (cbHdrs >= cbFile)
+        return K_FALSE;
+
+    if (    pFileHdr->PointerToSymbolTable != 0
+        &&  (   pFileHdr->PointerToSymbolTable < cbHdrs
+             || pFileHdr->PointerToSymbolTable > cbFile))
+        return K_FALSE;
+    if (    pFileHdr->PointerToSymbolTable == 0
+        &&  pFileHdr->NumberOfSymbols != 0)
+        return K_FALSE;
+    if (    pFileHdr->Characteristics
+        &   (  IMAGE_FILE_DLL
+             | IMAGE_FILE_SYSTEM
+             | IMAGE_FILE_UP_SYSTEM_ONLY
+             | IMAGE_FILE_NET_RUN_FROM_SWAP
+             | IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
+             | IMAGE_FILE_EXECUTABLE_IMAGE
+             | IMAGE_FILE_RELOCS_STRIPPED))
+        return K_FALSE;
+
+    for (iSHdr = 0; iSHdr < cSHdrs; iSHdr++)
+    {
+        if (    paSHdrs[iSHdr].PointerToRawData != 0
+            &&  (   paSHdrs[iSHdr].PointerToRawData < cbHdrs
+                 || paSHdrs[iSHdr].PointerToRawData >= cbFile
+                 || paSHdrs[iSHdr].PointerToRawData + paSHdrs[iSHdr].SizeOfRawData > cbFile))
+            return K_FALSE;
+        if (    paSHdrs[iSHdr].PointerToRelocations != 0
+            &&  (   paSHdrs[iSHdr].PointerToRelocations < cbHdrs
+                 || paSHdrs[iSHdr].PointerToRelocations >= cbFile
+                 || paSHdrs[iSHdr].PointerToRelocations + paSHdrs[iSHdr].NumberOfRelocations * 10 > cbFile)) /* IMAGE_RELOCATION */
+            return K_FALSE;
+        if (    paSHdrs[iSHdr].PointerToLinenumbers != 0
+            &&  (   paSHdrs[iSHdr].PointerToLinenumbers < cbHdrs
+                 || paSHdrs[iSHdr].PointerToLinenumbers >= cbFile
+                 || paSHdrs[iSHdr].PointerToLinenumbers + paSHdrs[iSHdr].NumberOfLinenumbers *  6 > cbFile)) /* IMAGE_LINENUMBER */
+            return K_FALSE;
+    }
 
     return K_TRUE;
@@ -279,4 +614,6 @@
     if (kDepObjOMFTest(pbFile, cbFile))
         rc = kDepObjOMFParse(pbFile, cbFile);
+    else if (kDepObjCOFFTest(pbFile, cbFile))
+        rc = kDepObjCOFFParse(pbFile, cbFile);
     else
     {
