VirtualBox

Changeset 2267 in kBuild for trunk/src


Ignore:
Timestamp:
Jan 24, 2009 2:00:40 AM (16 years ago)
Author:
bird
Message:

kDepObj: Taught it how to parse .debug$S section and find the source file info. CV8 and Visual C++ 2005 and later (+YASM). Not quite polished up yet, work in progress. References #82.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/kmkbuiltin/kDepObj.c

    r2263 r2267  
    4444#include "../../lib/k/kDefs.h"
    4545#include "../../lib/k/kTypes.h"
     46#include "../../lib/k/kLdrFmts/pe.h"
    4647#include "../../lib/kDep.h"
    4748#include "kmkbuiltin.h"
     
    7374*   Structures and Typedefs                                                    *
    7475*******************************************************************************/
    75 /** @name OMF structure
     76/** @name OMF Structures
    7677 * @{ */
    7778#pragma pack(1)
     
    117118typedef KDEPOMFDEPFILE *PKDEPOMFDEPFILE;
    118119typedef const KDEPOMFDEPFILE *PCKDEPOMFDEPFILE;
     120
     121#pragma pack()
     122/** @} */
     123
     124
     125/** @name COFF Structures
     126 * @{ */
     127#pragma pack(1)
     128
     129typedef struct KDEPCVSYMHDR
     130{
     131    /** The record size minus the size field. */
     132    KU16        cb;
     133    /** The record type. */
     134    KU16        uType;
     135} KDEPCVSYMHDR;
     136typedef KDEPCVSYMHDR *PKDEPCVSYMHDR;
     137typedef const KDEPCVSYMHDR *PCKDEPCVSYMHDR;
     138
     139/** @name Selection of KDEPCVSYMHDR::uType values.
     140 * @{ */
     141#define K_CV8_S_MSTOOL      KU16_C(0x1116)
     142/** @} */
     143
     144typedef struct KDEPCV8SYMHDR
     145{
     146    /** The record type. */
     147    KU32        uType;
     148    /** The record size minus the size field. */
     149    KU32        cb;
     150} KDEPCV8SYMHDR;
     151typedef KDEPCV8SYMHDR *PKDEPCV8SYMHDR;
     152typedef const KDEPCV8SYMHDR *PCKDEPCV8SYMHDR;
     153
     154/** @name Known KDEPCV8SYMHDR::uType Values.
     155 * @{ */
     156#define K_CV8_SYMBOL_INFO   KU32_C(0x000000f1)
     157#define K_CV8_LINE_NUMBERS  KU32_C(0x000000f2)
     158#define K_CV8_STRING_TABLE  KU32_C(0x000000f3)
     159#define K_CV8_SOURCE_FILES  KU32_C(0x000000f4)
     160#define K_CV8_COMDAT_XXXXX  KU32_C(0x000000f5) /**< no idea about the format... */
     161/** @} */
    119162
    120163#pragma pack()
     
    243286    PCKDEPOMFTHEADR pHdr = (PCKDEPOMFTHEADR)pbFile;
    244287
    245     if (cbFile < sizeof(*pHdr))
     288    if (cbFile <= sizeof(*pHdr))
    246289        return K_FALSE;
    247290    if (    pHdr->Hdr.bType != KDEPOMF_THEADR
     
    252295    if (pHdr->Hdr.cbRec != 1 + pHdr->Name.cch + 1)
    253296        return K_FALSE;
     297
     298    return K_TRUE;
     299}
     300
     301
     302/**
     303 * Parses a CodeView 8 symbol section.
     304 *
     305 * @returns 0 on success, 1 on failure.
     306 * @param   pbSyms      Pointer to the start of the symbol section.
     307 * @param   cbSyms      Size of the symbol section.
     308 */
     309int kDepObjCOFFParseCV8SymbolSection(const KU8 *pbSyms, KSIZE cbSyms)
     310{
     311    char const *    pchStrTab  = NULL;
     312    KU32            cbStrTab   = 0;
     313    KPCUINT         uSrcFiles  = {0};
     314    KU32            cbSrcFiles = 0;
     315    KU32            off        = 4;
     316    KU32            iSrc       = 0;
     317
     318    if (cbSyms < 16)
     319        return 1;
     320
     321    /*
     322     * The parsing loop.
     323     */
     324    while (off < cbSyms)
     325    {
     326        PCKDEPCV8SYMHDR pHdr = (PCKDEPCV8SYMHDR)(pbSyms + off);
     327        KPCUINT         uData;
     328        KU32            cbData;
     329        uData.pv = pHdr + 1;
     330
     331        if (off + sizeof(*pHdr) >= cbSyms)
     332        {
     333            fprintf(stderr, "%s: CV symbol table entry at %08" KX32_PRI " is too long; cbSyms=%#" KSIZE_PRI "\n",
     334                    argv0, off, cbSyms);
     335            return 1; /* FIXME */
     336        }
     337
     338        cbData = pHdr->cb;
     339        if (off + cbData + sizeof(*pHdr) > cbSyms)
     340        {
     341            fprintf(stderr, "%s: CV symbol table entry at %08" KX32_PRI " is too long; cbData=%#" KX32_PRI " cbSyms=%#" KSIZE_PRI "\n",
     342                    argv0, off, cbData, cbSyms);
     343            return 1; /* FIXME */
     344        }
     345
     346        /* If the size is 0, assume it covers the rest of the section. VC++ 2003 has
     347           been observed doing thing. */
     348        if (!cbData)
     349            cbData = cbSyms - off;
     350
     351        switch (pHdr->uType)
     352        {
     353            case K_CV8_SYMBOL_INFO:
     354                dprintf(("%06" KX32_PRI " %06" KX32_PRI ": Symbol Info\n", off, cbData));
     355                /*dump(uData.pb, cbData, 0);*/
     356                break;
     357
     358            case K_CV8_LINE_NUMBERS:
     359                dprintf(("%06" KX32_PRI " %06" KX32_PRI ": Line numbers\n", off, cbData));
     360                /*dump(uData.pb, cbData, 0);*/
     361                break;
     362
     363            case K_CV8_STRING_TABLE:
     364                dprintf(("%06" KX32_PRI " %06" KX32_PRI ": String table\n", off, cbData));
     365                if (pchStrTab)
     366                    fprintf(stderr, "%s: warning: Found yet another string table!\n");
     367                pchStrTab = uData.pch;
     368                cbStrTab = cbData;
     369                /*dump(uData.pb, cbData, 0);*/
     370                break;
     371
     372            case K_CV8_SOURCE_FILES:
     373                dprintf(("%06" KX32_PRI " %06" KX32_PRI ": Source files\n", off, cbData));
     374                if (uSrcFiles.pb)
     375                    fprintf(stderr, "%s: warning: Found yet another source files table!\n");
     376                uSrcFiles = uData;
     377                cbSrcFiles = cbData;
     378                /*dump(uData.pb, cbData, 0);*/
     379                break;
     380
     381            case K_CV8_COMDAT_XXXXX:
     382                dprintf(("%06" KX32_PRI " %06" KX32_PRI ": 0xf5 Unknown COMDAT stuff\n", off, cbData));
     383                /*dump(uData.pb, cbData, 0);*/
     384                break;
     385
     386            default:
     387                dprintf(("%06" KX32_PRI " %06" KX32_PRI ": Unknown type %#" KX32_PRI "\n",
     388                         off, cbData, pHdr->uType));
     389                dump(uData.pb, cbData, 0);
     390                break;
     391        }
     392
     393        /* next */
     394        cbData = (cbData + 3) & ~KU32_C(3);
     395        off += cbData + sizeof(*pHdr);
     396    }
     397
     398    /*
     399     * Did we find any source files and strings?
     400     */
     401    if (!pchStrTab || !uSrcFiles.pv)
     402    {
     403        dprintf(("No cylindrical smoking thing: pchStrTab=%p uSrcFiles.pv=%p\n", pchStrTab, uSrcFiles.pv));
     404        return 2;
     405    }
     406
     407    /*
     408     * Iterate the source file table.
     409     */
     410    off = 0;
     411    while (off < cbSrcFiles)
     412    {
     413        KU32        offFile;
     414        const char *pszFile;
     415        KSIZE       cchFile;
     416        KU16        u16Type;
     417        KPCUINT     uSrc;
     418        KU32        cbSrc;
     419
     420        /*
     421         * Validate and parse the entry (variable length record are fun).
     422         */
     423        if (off + 8 > cbSrcFiles)
     424        {
     425            fprintf(stderr, "%s: CV source file entry at %08" KX32_PRI " is too long; cbSrcFiles=%#" KSIZE_PRI "\n",
     426                    argv0, off, cbSrcFiles);
     427            return 1;
     428        }
     429        uSrc.pb = uSrcFiles.pb + off;
     430        u16Type = uSrc.pu16[2];
     431        cbSrc = u16Type == 0x0110 ? 6 + 16 + 2 : 6 + 2;
     432        if (off + cbSrc > cbSrcFiles)
     433        {
     434            fprintf(stderr, "%s: CV source file entry at %08" KX32_PRI " is too long; cbSrc=%#" KX32_PRI " cbSrcFiles=%#" KSIZE_PRI "\n",
     435                    argv0, off, cbSrc, cbSrcFiles);
     436            return 1;
     437        }
     438
     439        offFile = *uSrc.pu32;
     440        if (offFile > cbStrTab)
     441        {
     442            fprintf(stderr, "%s: CV source file entry at %08" KX32_PRI " is out side the string table; offFile=%#" KX32_PRI " cbStrTab=%#" KX32_PRI "\n",
     443                    argv0, off, offFile, cbStrTab);
     444            return 1;
     445        }
     446        pszFile = pchStrTab + offFile;
     447        cchFile = strlen(pszFile);
     448        if (cchFile == 0)
     449        {
     450            fprintf(stderr, "%s: CV source file entry at %08" KX32_PRI " has an empty file name; offFile=%#x" KX32_PRI "\n",
     451                    argv0, off, offFile);
     452            return 1;
     453        }
     454
     455        /*
     456         * Display the result and add it to the dependency database.
     457         */
     458        depAdd(pszFile, cchFile);
     459        if (u16Type == 0x0110)
     460            dprintf(("#%03" KU32_PRI ": {todo-md5-todo} '%s'\n",
     461                     iSrc, pszFile));
     462        else
     463            dprintf(("#%03" KU32_PRI ": type=%#06" KX16_PRI " '%s'\n", iSrc, u16Type, pszFile));
     464
     465
     466        /* next */
     467        iSrc++;
     468        off += cbSrc;
     469    }
     470
     471    if (iSrc == 0)
     472    {
     473        dprintf(("No cylindrical smoking thing: iSrc=0\n"));
     474        return 2;
     475    }
     476    dprintf(("iSrc=%" KU32_PRI "\n", iSrc));
     477    return 0;
     478}
     479
     480
     481/**
     482 * Parses the OMF file.
     483 *
     484 * @returns 0 on success, 1 on failure, 2 if no dependencies was found.
     485 * @param   pbFile      The start of the file.
     486 * @param   cbFile      The file size.
     487 */
     488int kDepObjCOFFParse(const KU8 *pbFile, KSIZE cbFile)
     489{
     490    IMAGE_FILE_HEADER const    *pFileHdr = (IMAGE_FILE_HEADER const *)pbFile;
     491    IMAGE_SECTION_HEADER const *paSHdrs  = (IMAGE_SECTION_HEADER const *)((KU8 const *)(pFileHdr + 1) + pFileHdr->SizeOfOptionalHeader);
     492    unsigned                    cSHdrs   = pFileHdr->NumberOfSections;
     493    unsigned                    iSHdr;
     494    KPCUINT                     u;
     495    int                         rcRet    = 2;
     496    int                         rc;
     497
     498    printf("COFF file!\n");
     499
     500    for (iSHdr = 0; iSHdr < cSHdrs; iSHdr++)
     501    {
     502        if (    !memcmp(paSHdrs[iSHdr].Name, ".debug$S", sizeof(".debug$S") - 1)
     503            &&  paSHdrs[iSHdr].SizeOfRawData > 4)
     504        {
     505            u.pb = pbFile + paSHdrs[iSHdr].PointerToRawData;
     506            dprintf(("CV symbol table: version=%x\n", *u.pu32));
     507            if (*u.pu32 == 0x000000004)
     508                rc = kDepObjCOFFParseCV8SymbolSection(u.pb, paSHdrs[iSHdr].SizeOfRawData);
     509            else
     510                rc = 2;
     511            dprintf(("rc=%d\n", rc));
     512            if (rcRet == 2)
     513                rcRet = rc;
     514            if (rcRet != 2)
     515                return rc;
     516        }
     517        printf("#%d: %.8s\n", iSHdr, paSHdrs[iSHdr].Name);
     518    }
     519    return rcRet;
     520}
     521
     522
     523/**
     524 * Checks if this file is a COFF file or not.
     525 *
     526 * @returns K_TRUE if it's COFF, K_FALSE otherwise.
     527 *
     528 * @param   pb      The start of the file.
     529 * @param   cb      The file size.
     530 */
     531KBOOL kDepObjCOFFTest(const KU8 *pbFile, KSIZE cbFile)
     532{
     533    IMAGE_FILE_HEADER const    *pFileHdr = (IMAGE_FILE_HEADER const *)pbFile;
     534    IMAGE_SECTION_HEADER const *paSHdrs  = (IMAGE_SECTION_HEADER const *)((KU8 const *)(pFileHdr + 1) + pFileHdr->SizeOfOptionalHeader);
     535    unsigned                    cSHdrs   = pFileHdr->NumberOfSections;
     536    unsigned                    iSHdr;
     537    KSIZE                       cbHdrs   = (const KU8 *)&paSHdrs[cSHdrs] - (const KU8 *)pbFile;
     538
     539    if (cbFile <= sizeof(*pFileHdr))
     540        return K_FALSE;
     541    if (    pFileHdr->Machine != IMAGE_FILE_MACHINE_I386
     542        &&  pFileHdr->Machine != IMAGE_FILE_MACHINE_AMD64)
     543        return K_FALSE;
     544    if (pFileHdr->SizeOfOptionalHeader != 0)
     545        return K_FALSE; /* COFF files doesn't have an optional header */
     546
     547    if (    pFileHdr->NumberOfSections <= 1
     548        ||  pFileHdr->NumberOfSections > cbFile)
     549        return K_FALSE;
     550
     551    if (cbHdrs >= cbFile)
     552        return K_FALSE;
     553
     554    if (    pFileHdr->PointerToSymbolTable != 0
     555        &&  (   pFileHdr->PointerToSymbolTable < cbHdrs
     556             || pFileHdr->PointerToSymbolTable > cbFile))
     557        return K_FALSE;
     558    if (    pFileHdr->PointerToSymbolTable == 0
     559        &&  pFileHdr->NumberOfSymbols != 0)
     560        return K_FALSE;
     561    if (    pFileHdr->Characteristics
     562        &   (  IMAGE_FILE_DLL
     563             | IMAGE_FILE_SYSTEM
     564             | IMAGE_FILE_UP_SYSTEM_ONLY
     565             | IMAGE_FILE_NET_RUN_FROM_SWAP
     566             | IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP
     567             | IMAGE_FILE_EXECUTABLE_IMAGE
     568             | IMAGE_FILE_RELOCS_STRIPPED))
     569        return K_FALSE;
     570
     571    for (iSHdr = 0; iSHdr < cSHdrs; iSHdr++)
     572    {
     573        if (    paSHdrs[iSHdr].PointerToRawData != 0
     574            &&  (   paSHdrs[iSHdr].PointerToRawData < cbHdrs
     575                 || paSHdrs[iSHdr].PointerToRawData >= cbFile
     576                 || paSHdrs[iSHdr].PointerToRawData + paSHdrs[iSHdr].SizeOfRawData > cbFile))
     577            return K_FALSE;
     578        if (    paSHdrs[iSHdr].PointerToRelocations != 0
     579            &&  (   paSHdrs[iSHdr].PointerToRelocations < cbHdrs
     580                 || paSHdrs[iSHdr].PointerToRelocations >= cbFile
     581                 || paSHdrs[iSHdr].PointerToRelocations + paSHdrs[iSHdr].NumberOfRelocations * 10 > cbFile)) /* IMAGE_RELOCATION */
     582            return K_FALSE;
     583        if (    paSHdrs[iSHdr].PointerToLinenumbers != 0
     584            &&  (   paSHdrs[iSHdr].PointerToLinenumbers < cbHdrs
     585                 || paSHdrs[iSHdr].PointerToLinenumbers >= cbFile
     586                 || paSHdrs[iSHdr].PointerToLinenumbers + paSHdrs[iSHdr].NumberOfLinenumbers *  6 > cbFile)) /* IMAGE_LINENUMBER */
     587            return K_FALSE;
     588    }
    254589
    255590    return K_TRUE;
     
    279614    if (kDepObjOMFTest(pbFile, cbFile))
    280615        rc = kDepObjOMFParse(pbFile, cbFile);
     616    else if (kDepObjCOFFTest(pbFile, cbFile))
     617        rc = kDepObjCOFFParse(pbFile, cbFile);
    281618    else
    282619    {
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette