VirtualBox

Changeset 77146 in vbox


Ignore:
Timestamp:
Feb 3, 2019 8:59:09 PM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
128616
Message:

DBGPlugInFreeBsd.cpp: Trying out a new algorithm to find the boundaries of the .dynstr and .dynsm sections after the .gnu.hash section was introduced breaking the old code. WIP, disabled by default

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Debugger/DBGPlugInFreeBsd.cpp

    r76553 r77146  
    4242*   Structures and Typedefs                                                                                                      *
    4343*********************************************************************************************************************************/
     44
     45/**
     46 * FreeBSD .dynstr and .dynsym location probing state.
     47 */
     48typedef enum FBSDPROBESTATE
     49{
     50    /** Invalid state. */
     51    FBSDPROBESTATE_INVALID = 0,
     52    /** Searching for the end of the .dynstr section (terminator). */
     53    FBSDPROBESTATE_DYNSTR_END,
     54    /** Last symbol was a symbol terminator character. */
     55    FBSDPROBESTATE_DYNSTR_SYM_TERMINATOR,
     56    /** Last symbol was a symbol character. */
     57    FBSDPROBESTATE_DYNSTR_SYM_CHAR,
     58} FBSDPROBESTATE;
    4459
    4560/**
     
    218233                 pThis, pszName, uKernelStart, cbKernel, pAddrDynsym, pAddrDynsym->FlatPtr, cSymbols, pAddrDynstr, pAddrDynstr->FlatPtr, cbDynstr));
    219234
    220     char *pbDynstr = (char *)RTMemAllocZ(cbDynstr);
     235    char *pbDynstr = (char *)RTMemAllocZ(cbDynstr + 1); /* Extra terminator. */
    221236    int rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, pAddrDynstr, pbDynstr, cbDynstr);
    222237    if (RT_SUCCESS(rc))
     
    251266                    /* Add it without the type char. */
    252267                    RT_NOREF(uType);
    253                     if (AddrVal <= uKernelStart + cbKernel)
     268                    if (   AddrVal <= uKernelStart + cbKernel
     269                        && idxSymStr < cbDynstr)
    254270                    {
    255271                        rc = RTDbgModSymbolAdd(hMod, &pbDynstr[idxSymStr], RTDBGSEGIDX_RVA, AddrVal - uKernelStart,
     
    322338     *
    323339     * All checked FreeBSD kernels so far have the following layout in the kernel:
    324      *     [.interp] - contiains the /red/herring string we used for probing earlier
    325      *     [.hash]   - contains the hashes of the symbol names, 8 byte alignment on 64bit, 4 byte on 32bit
    326      *     [.dynsym] - contains the ELF symbol descriptors, 8 byte alignment, 4 byte on 32bit
    327      *     [.dynstr] - contains the symbol names as a string table, 1 byte alignmnt
    328      *     [.text]   - contains the executable code, 16 byte alignment.
    329      * The sections are always adjacent (sans alignment) so we just parse the .hash section right after
    330      * .interp, ELF states that it can contain 32bit or 64bit words but all observed kernels
    331      * always use 32bit words. It contains two counters at the beginning which we can use to
    332      * deduct the .hash section size and the beginning of .dynsym.
    333      * .dynsym contains an array of symbol descriptors which have a fixed size depending on the
    334      * guest bitness.
    335      * Finding the end of .dynsym is not easily doable as there is no counter available (it lives
    336      * in the section headers) at this point so we just have to check whether the record is valid
    337      * and if not check if it contains an ASCII string which marks the start of the .dynstr section.
     340     *     [.interp]   - contains the /red/herring string we used for probing earlier
     341     *     [.hash]     - contains the hashes of the symbol names, 8 byte alignment on 64bit, 4 byte on 32bit
     342     *     [.gnu.hash] - GNU hash section. (introduced somewhere between 10.0 and 12.0 @todo Find out when exactly)
     343     *     [.dynsym]   - contains the ELF symbol descriptors, 8 byte alignment, 4 byte on 32bit
     344     *     [.dynstr]   - contains the symbol names as a string table, 1 byte alignmnt
     345     *     [.text]     - contains the executable code, 16 byte alignment.
     346     *
     347     * To find the start of the .dynsym and .dynstr sections we scan backwards from the start of the .text section
     348     * and check for all characters allowed for symbol names and count the amount of symbols found. When the start of the
     349     * .dynstr section is reached the number of entries in .dynsym is known and we can deduce the start address.
     350     *
     351     * This applied to the old code before the FreeBSD kernel introduced the .gnu.hash section
     352     * (keeping it here for informational pruposes):
     353     *     The sections are always adjacent (sans alignment) so we just parse the .hash section right after
     354     *     .interp, ELF states that it can contain 32bit or 64bit words but all observed kernels
     355     *     always use 32bit words. It contains two counters at the beginning which we can use to
     356     *     deduct the .hash section size and the beginning of .dynsym.
     357     *     .dynsym contains an array of symbol descriptors which have a fixed size depending on the
     358     *     guest bitness.
     359     *     Finding the end of .dynsym is not easily doable as there is no counter available (it lives
     360     *     in the section headers) at this point so we just have to check whether the record is valid
     361     *     and if not check if it contains an ASCII string which marks the start of the .dynstr section.
    338362     */
    339363
     364#if 0
     365    DBGFADDRESS AddrInterpEnd = pThis->AddrKernelInterp;
     366    DBGFR3AddrAdd(&AddrInterpEnd, sizeof(g_abNeedleInterp));
     367
     368    DBGFADDRESS AddrCur = pThis->AddrKernelText;
     369    int rc = VINF_SUCCESS;
     370    uint32_t cSymbols = 0;
     371    size_t cbKernel = 512 * _1M;
     372    RTGCUINTPTR uKernelStart = pThis->AddrKernelElfStart.FlatPtr;
     373    FBSDPROBESTATE enmState = FBSDPROBESTATE_DYNSTR_END; /* Start searching for the end of the .dynstr section. */
     374
     375    while (AddrCur.FlatPtr > AddrInterpEnd.FlatPtr)
     376    {
     377        char achBuf[_16K];
     378        size_t cbToRead = RT_MIN(sizeof(achBuf), AddrCur.FlatPtr - AddrInterpEnd.FlatPtr);
     379
     380        rc = DBGFR3MemRead(pUVM, 0 /*idCpu*/, DBGFR3AddrSub(&AddrCur, cbToRead), &achBuf[0], cbToRead);
     381        if (RT_FAILURE(rc))
     382            break;
     383
     384        for (unsigned i = cbToRead; i > 0; i--)
     385        {
     386            char ch = achBuf[i - 1];
     387
     388            switch (enmState)
     389            {
     390                case FBSDPROBESTATE_DYNSTR_END:
     391                {
     392                    if (ch != '\0')
     393                        enmState = FBSDPROBESTATE_DYNSTR_SYM_CHAR;
     394                    break;
     395                }
     396                case FBSDPROBESTATE_DYNSTR_SYM_TERMINATOR:
     397                {
     398                    if (   RT_C_IS_ALNUM(ch)
     399                        || ch == '_'
     400                        || ch == '.')
     401                        enmState = FBSDPROBESTATE_DYNSTR_SYM_CHAR;
     402                    else
     403                    {
     404                        /* Two consecutive terminator symbols mean end of .dynstr section. */
     405                        DBGFR3AddrAdd(&AddrCur, i);
     406                        DBGFADDRESS AddrDynstrStart = AddrCur;
     407                        DBGFADDRESS AddrDynsymStart = AddrCur;
     408                        DBGFR3AddrSub(&AddrDynsymStart, cSymbols * (pThis->f64Bit ? sizeof(Elf64_Sym) : sizeof(Elf64_Sym)));
     409                        LogFlowFunc(("Found all required section start addresses (.dynsym=%RGv cSymbols=%u, .dynstr=%RGv cb=%u)\n",
     410                                     AddrDynsymStart.FlatPtr, cSymbols, AddrDynstrStart.FlatPtr,
     411                                     pThis->AddrKernelText.FlatPtr - AddrDynstrStart.FlatPtr));
     412                        dbgDiggerFreeBsdLoadSymbols(pThis, pUVM, pszName, uKernelStart, cbKernel, &AddrDynsymStart, cSymbols, &AddrDynstrStart,
     413                                                    pThis->AddrKernelText.FlatPtr - AddrDynstrStart.FlatPtr);
     414                        return;
     415                    }
     416                    break;
     417                }
     418                case FBSDPROBESTATE_DYNSTR_SYM_CHAR:
     419                {
     420                    if (   !RT_C_IS_ALNUM(ch)
     421                        && ch != '_'
     422                        && ch != '.')
     423                    {
     424                        /* Non symbol character. */
     425                        if (ch == '\0')
     426                        {
     427                            enmState = FBSDPROBESTATE_DYNSTR_SYM_TERMINATOR;
     428                            cSymbols++;
     429                        }
     430                        else
     431                        {
     432                            /* Indicates the end of the .dynstr section. */
     433                            DBGFR3AddrAdd(&AddrCur, i);
     434                            DBGFADDRESS AddrDynstrStart = AddrCur;
     435                            DBGFADDRESS AddrDynsymStart = AddrCur;
     436                            DBGFR3AddrSub(&AddrDynsymStart, cSymbols * (pThis->f64Bit ? sizeof(Elf64_Sym) : sizeof(Elf32_Sym)));
     437                            LogFlowFunc(("Found all required section start addresses (.dynsym=%RGv cSymbols=%u, .dynstr=%RGv cb=%u)\n",
     438                                         AddrDynsymStart.FlatPtr, cSymbols, AddrDynstrStart.FlatPtr,
     439                                         pThis->AddrKernelText.FlatPtr - AddrDynstrStart.FlatPtr));
     440                            dbgDiggerFreeBsdLoadSymbols(pThis, pUVM, pszName, uKernelStart, cbKernel, &AddrDynsymStart, cSymbols, &AddrDynstrStart,
     441                                                        pThis->AddrKernelText.FlatPtr - AddrDynstrStart.FlatPtr);
     442                            return;
     443                        }
     444                    }
     445                    break;
     446                }
     447                default:
     448                    AssertFailedBreak();
     449            }
     450        }
     451    }
     452
     453    LogFlow(("Failed to find valid .dynsym and .dynstr sections (%Rrc), can't load kernel symbols\n", rc));
     454#else
    340455    /* Calculate the start of the .hash section. */
    341456    DBGFADDRESS AddrHashStart = pThis->AddrKernelInterp;
     
    438553                         pThis->AddrKernelText.FlatPtr - AddrHashStart.FlatPtr));
    439554    }
     555#endif
    440556}
    441557
     
    759875                        pThis->AddrKernelElfStart = HitAddr;
    760876                        pThis->AddrKernelInterp = HitAddrInterp;
    761                         pThis->AddrKernelText.FlatPtr = FBSD_UNION(pThis, &ElfHdr, e_entry);
     877                        DBGFR3AddrFromFlat(pUVM, &pThis->AddrKernelText, FBSD_UNION(pThis, &ElfHdr, e_entry));
    762878                        LogFunc(("Found %s FreeBSD kernel at %RGv (.interp section at %RGv, .text section at %RGv)\n",
    763879                                 pThis->f64Bit ? "amd64" : "i386", pThis->AddrKernelElfStart.FlatPtr,
Note: See TracChangeset for help on using the changeset viewer.

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