/** @copydoc RTDBGMODVTDBG::pfnLineAdd */ static DECLCALLBACK(int) rtDbgModContainer_LineAdd(PRTDBGMODINT pMod, const char *pszFile, size_t cchFile, uint32_t uLineNo, uint32_t iSeg, RTUINTPTR off, uint32_t *piOrdinal) { PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv; /* * Validate the input address. */ AssertMsgReturn(iSeg < pThis->cSegs, ("iSeg=%#x cSegs=%#x\n", iSeg, pThis->cSegs), VERR_DBG_INVALID_SEGMENT_INDEX); AssertMsgReturn(off < pThis->paSegs[iSeg].cb, ("off=%RTptr cbSeg=%RTptr\n", off, pThis->paSegs[iSeg].cb), VERR_DBG_INVALID_SEGMENT_OFFSET); /* * Create a new entry. */ #ifdef RTDBGMODCNT_WITH_MEM_CACHE PRTDBGMODCTNLINE pLine = (PRTDBGMODCTNLINE)RTMemCacheAlloc(pThis->hLineNumAllocator); #else PRTDBGMODCTNLINE pLine = (PRTDBGMODCTNLINE)RTMemAllocZ(sizeof(*pLine)); #endif if (!pLine) return VERR_NO_MEMORY; pLine->AddrCore.Key = off; pLine->OrdinalCore.Key = pThis->iNextLineOrdinal; pLine->uLineNo = uLineNo; pLine->iSeg = iSeg; pLine->pszFile = RTStrCacheEnterN(g_hDbgModStrCache, pszFile, cchFile); int rc; if (pLine->pszFile) { if (RTAvlUIntPtrInsert(&pThis->paSegs[iSeg].LineAddrTree, &pLine->AddrCore)) { if (RTAvlU32Insert(&pThis->LineOrdinalTree, &pLine->OrdinalCore)) { if (piOrdinal) *piOrdinal = pThis->iNextLineOrdinal; pThis->iNextLineOrdinal++; return VINF_SUCCESS; } rc = VERR_INTERNAL_ERROR_5; RTAvlUIntPtrRemove(&pThis->paSegs[iSeg].LineAddrTree, pLine->AddrCore.Key); } /* bail out */ rc = VERR_DBG_ADDRESS_CONFLICT; RTStrCacheRelease(g_hDbgModStrCache, pLine->pszFile); } else rc = VERR_NO_MEMORY; #ifdef RTDBGMODCNT_WITH_MEM_CACHE RTMemCacheFree(pThis->hLineNumAllocator, pLine); #else RTMemFree(pLine); #endif return rc; }
RTDECL(const char *) RTStrCacheEnter(RTSTRCACHE hStrCache, const char *psz) { return RTStrCacheEnterN(hStrCache, psz, strlen(psz)); }
/** @copydoc RTDBGMODVTDBG::pfnSegmentAdd */ static DECLCALLBACK(int) rtDbgModContainer_SegmentAdd(PRTDBGMODINT pMod, RTUINTPTR uRva, RTUINTPTR cb, const char *pszName, size_t cchName, uint32_t fFlags, PRTDBGSEGIDX piSeg) { PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv; /* * Input validation (the bits the caller cannot do). */ /* Overlapping segments are not yet supported. Will use flags to deal with it if it becomes necessary. */ RTUINTPTR uRvaLast = uRva + RT_MAX(cb, 1) - 1; RTUINTPTR uRvaLastMax = uRvaLast; RTDBGSEGIDX iSeg = pThis->cSegs; while (iSeg-- > 0) { RTUINTPTR uCurRva = pThis->paSegs[iSeg].off; RTUINTPTR uCurRvaLast = uCurRva + RT_MAX(pThis->paSegs[iSeg].cb, 1) - 1; if ( uRva <= uCurRvaLast && uRvaLast >= uCurRva && ( /* HACK ALERT! Allow empty segments to share space (bios/watcom, elf). */ (cb != 0 && pThis->paSegs[iSeg].cb != 0) || ( cb == 0 && uRva != uCurRva && uRva != uCurRvaLast) || ( pThis->paSegs[iSeg].cb == 0 && uCurRva != uRva && uCurRva != uRvaLast) ) ) AssertMsgFailedReturn(("uRva=%RTptr uRvaLast=%RTptr (cb=%RTptr) \"%s\";\n" "uRva=%RTptr uRvaLast=%RTptr (cb=%RTptr) \"%s\" iSeg=%#x\n", uRva, uRvaLast, cb, pszName, uCurRva, uCurRvaLast, pThis->paSegs[iSeg].cb, pThis->paSegs[iSeg].pszName, iSeg), VERR_DBG_SEGMENT_INDEX_CONFLICT); if (uRvaLastMax < uCurRvaLast) uRvaLastMax = uCurRvaLast; } /* Strict ordered segment addition at the moment. */ iSeg = pThis->cSegs; AssertMsgReturn(!piSeg || *piSeg == NIL_RTDBGSEGIDX || *piSeg == iSeg, ("iSeg=%#x *piSeg=%#x\n", iSeg, *piSeg), VERR_DBG_INVALID_SEGMENT_INDEX); /* * Add an entry to the segment table, extending it if necessary. */ if (!(iSeg % 8)) { void *pvSegs = RTMemRealloc(pThis->paSegs, sizeof(RTDBGMODCTNSEGMENT) * (iSeg + 8)); if (!pvSegs) return VERR_NO_MEMORY; pThis->paSegs = (PRTDBGMODCTNSEGMENT)pvSegs; } pThis->paSegs[iSeg].SymAddrTree = NULL; pThis->paSegs[iSeg].LineAddrTree = NULL; pThis->paSegs[iSeg].off = uRva; pThis->paSegs[iSeg].cb = cb; pThis->paSegs[iSeg].fFlags = fFlags; pThis->paSegs[iSeg].pszName = RTStrCacheEnterN(g_hDbgModStrCache, pszName, cchName); if (pThis->paSegs[iSeg].pszName) { if (piSeg) *piSeg = iSeg; pThis->cSegs++; pThis->cb = uRvaLastMax + 1; if (!pThis->cb) pThis->cb = RTUINTPTR_MAX; return VINF_SUCCESS; } return VERR_NO_MEMORY; }
/** @copydoc RTDBGMODVTDBG::pfnSymbolAdd */ static DECLCALLBACK(int) rtDbgModContainer_SymbolAdd(PRTDBGMODINT pMod, const char *pszSymbol, size_t cchSymbol, RTDBGSEGIDX iSeg, RTUINTPTR off, RTUINTPTR cb, uint32_t fFlags, uint32_t *piOrdinal) { PRTDBGMODCTN pThis = (PRTDBGMODCTN)pMod->pvDbgPriv; /* * Address validation. The other arguments have already been validated. */ AssertMsgReturn( iSeg == RTDBGSEGIDX_ABS || iSeg < pThis->cSegs, ("iSeg=%#x cSegs=%#x\n", iSeg, pThis->cSegs), VERR_DBG_INVALID_SEGMENT_INDEX); AssertMsgReturn( iSeg >= RTDBGSEGIDX_SPECIAL_FIRST || off <= pThis->paSegs[iSeg].cb, ("off=%RTptr cb=%RTptr cbSeg=%RTptr\n", off, cb, pThis->paSegs[iSeg].cb), VERR_DBG_INVALID_SEGMENT_OFFSET); /* Be a little relaxed wrt to the symbol size. */ int rc = VINF_SUCCESS; if (iSeg != RTDBGSEGIDX_ABS && off + cb > pThis->paSegs[iSeg].cb) { cb = pThis->paSegs[iSeg].cb - off; rc = VINF_DBG_ADJUSTED_SYM_SIZE; } /* * Create a new entry. */ PRTDBGMODCTNSYMBOL pSymbol = (PRTDBGMODCTNSYMBOL)RTMemAllocZ(sizeof(*pSymbol)); if (!pSymbol) return VERR_NO_MEMORY; pSymbol->AddrCore.Key = off; pSymbol->AddrCore.KeyLast = off + (cb ? cb - 1 : 0); pSymbol->OrdinalCore.Key = pThis->iNextSymbolOrdinal; pSymbol->iSeg = iSeg; pSymbol->cb = cb; pSymbol->fFlags = fFlags; pSymbol->NameCore.pszString = RTStrCacheEnterN(g_hDbgModStrCache, pszSymbol, cchSymbol); if (pSymbol->NameCore.pszString) { if (RTStrSpaceInsert(&pThis->Names, &pSymbol->NameCore)) { PAVLRUINTPTRTREE pAddrTree = iSeg == RTDBGSEGIDX_ABS ? &pThis->AbsAddrTree : &pThis->paSegs[iSeg].SymAddrTree; if (RTAvlrUIntPtrInsert(pAddrTree, &pSymbol->AddrCore)) { if (RTAvlU32Insert(&pThis->SymbolOrdinalTree, &pSymbol->OrdinalCore)) { if (piOrdinal) *piOrdinal = pThis->iNextSymbolOrdinal; pThis->iNextSymbolOrdinal++; return rc; } /* bail out */ rc = VERR_INTERNAL_ERROR_5; RTAvlrUIntPtrRemove(pAddrTree, pSymbol->AddrCore.Key); } else rc = VERR_DBG_ADDRESS_CONFLICT; RTStrSpaceRemove(&pThis->Names, pSymbol->NameCore.pszString); } else rc = VERR_DBG_DUPLICATE_SYMBOL; RTStrCacheRelease(g_hDbgModStrCache, pSymbol->NameCore.pszString); } else rc = VERR_NO_MEMORY; RTMemFree(pSymbol); return rc; }
/** * Basic API checks. * We'll return if any of these fails. */ static void tst1(RTSTRCACHE hStrCache) { const char *psz; /* Simple string entering and length. */ RTTESTI_CHECK_RETV(psz = RTStrCacheEnter(hStrCache, "abcdefgh")); RTTESTI_CHECK_RETV(strcmp(psz, "abcdefgh") == 0); RTTESTI_CHECK_RETV(RTStrCacheLength(psz) == strlen("abcdefgh")); RTTESTI_CHECK_RETV(RTStrCacheRelease(hStrCache, psz) == 0); RTTESTI_CHECK_RETV(psz = RTStrCacheEnter(hStrCache, "abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RETV(strcmp(psz, "abcdefghijklmnopqrstuvwxyz") == 0); RTTESTI_CHECK_RETV(RTStrCacheLength(psz) == strlen("abcdefghijklmnopqrstuvwxyz")); RTTESTI_CHECK_RETV(RTStrCacheRelease(hStrCache, psz) == 0); /* Unterminated strings. */ RTTESTI_CHECK_RETV(psz = RTStrCacheEnterN(hStrCache, "0123456789", 3)); RTTESTI_CHECK_RETV(strcmp(psz, "012") == 0); RTTESTI_CHECK_RETV(RTStrCacheLength(psz) == strlen("012")); RTTESTI_CHECK_RETV(RTStrCacheRelease(hStrCache, psz) == 0); RTTESTI_CHECK_RETV(psz = RTStrCacheEnterN(hStrCache, "0123456789abcdefghijklmnopqrstuvwxyz", 16)); RTTESTI_CHECK_RETV(strcmp(psz, "0123456789abcdef") == 0); RTTESTI_CHECK_RETV(RTStrCacheLength(psz) == strlen("0123456789abcdef")); RTTESTI_CHECK_RETV(RTStrCacheRelease(hStrCache, psz) == 0); /* String referencing. */ char szTest[4096+16]; memset(szTest, 'a', sizeof(szTest)); char szTest2[4096+16]; memset(szTest2, 'f', sizeof(szTest)); for (int32_t i = 4096; i > 3; i /= 3) { void *pv2; RTTESTI_CHECK_RETV(psz = RTStrCacheEnterN(hStrCache, szTest, i)); RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemFirstMismatchingU8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz)); RTTESTI_CHECK(RTStrCacheRetain(psz) == 2); RTTESTI_CHECK(RTStrCacheRetain(psz) == 3); RTTESTI_CHECK(RTStrCacheRetain(psz) == 4); RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemFirstMismatchingU8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz)); RTTESTI_CHECK(RTStrCacheRelease(hStrCache, psz) == 3); RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemFirstMismatchingU8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz)); RTTESTI_CHECK(RTStrCacheRetain(psz) == 4); RTTESTI_CHECK(RTStrCacheRetain(psz) == 5); RTTESTI_CHECK(RTStrCacheRetain(psz) == 6); RTTESTI_CHECK(RTStrCacheRelease(hStrCache, psz) == 5); RTTESTI_CHECK(RTStrCacheRelease(hStrCache, psz) == 4); RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemFirstMismatchingU8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz)); for (uint32_t cRefs = 3;; cRefs--) { RTTESTI_CHECK(RTStrCacheRelease(hStrCache, psz) == cRefs); if (cRefs == 0) break; RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemFirstMismatchingU8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x cRefs=%d\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz, cRefs)); for (uint32_t j = 0; j < 42; j++) { const char *psz2; RTTESTI_CHECK_RETV(psz2 = RTStrCacheEnterN(hStrCache, szTest2, i)); RTTESTI_CHECK_RETV(psz2 != psz); RTTESTI_CHECK(RTStrCacheRelease(hStrCache, psz2) == 0); RTTESTI_CHECK_MSG_RETV((pv2 = ASMMemFirstMismatchingU8(psz, i, 'a')) == NULL && !psz[i], ("i=%#x psz=%p off=%#x cRefs=%d\n", i, psz, (uintptr_t)pv2 - (uintptr_t)psz, cRefs)); } } } /* Lots of allocations. */ memset(szTest, 'b', sizeof(szTest)); memset(szTest2, 'e', sizeof(szTest)); const char *pszTest1Rets[4096 + 16]; const char *pszTest2Rets[4096 + 16]; for (uint32_t i = 1; i < RT_ELEMENTS(pszTest1Rets); i++) { RTTESTI_CHECK(pszTest1Rets[i] = RTStrCacheEnterN(hStrCache, szTest, i)); RTTESTI_CHECK(strlen(pszTest1Rets[i]) == i); RTTESTI_CHECK(pszTest2Rets[i] = RTStrCacheEnterN(hStrCache, szTest2, i)); RTTESTI_CHECK(strlen(pszTest2Rets[i]) == i); } if (RTStrCacheIsRealImpl()) { for (uint32_t i = 1; i < RT_ELEMENTS(pszTest1Rets); i++) { uint32_t cRefs; const char *psz1, *psz2; RTTESTI_CHECK((psz1 = RTStrCacheEnterN(hStrCache, szTest, i)) == pszTest1Rets[i]); RTTESTI_CHECK((psz2 = RTStrCacheEnterN(hStrCache, szTest2, i)) == pszTest2Rets[i]); RTTESTI_CHECK_MSG((cRefs = RTStrCacheRelease(hStrCache, psz1)) == 1, ("cRefs=%#x i=%#x\n", cRefs, i)); RTTESTI_CHECK_MSG((cRefs = RTStrCacheRelease(hStrCache, psz2)) == 1, ("cRefs=%#x i=%#x\n", cRefs, i)); } } for (uint32_t i = 1; i < RT_ELEMENTS(pszTest1Rets); i++) { uint32_t cRefs; RTTESTI_CHECK(strlen(pszTest1Rets[i]) == i); RTTESTI_CHECK_MSG((cRefs = RTStrCacheRelease(hStrCache, pszTest1Rets[i])) == 0, ("cRefs=%#x i=%#x\n", cRefs, i)); RTTESTI_CHECK(strlen(pszTest2Rets[i]) == i); RTTESTI_CHECK_MSG((cRefs = RTStrCacheRelease(hStrCache, pszTest2Rets[i])) == 0, ("cRefs=%#x i=%#x\n", cRefs, i)); } }