Ignore:
Timestamp:
May 31, 2017, 4:25:33 PM (2 years ago)
Author:
nmedfort
Message:

Initial attempt to improve debugging capabilities with compilation stack traces on error.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • icGREP/icgrep-devel/icgrep/IR_Gen/CBuilder.cpp

    r5474 r5486  
    1212#include <llvm/IR/MDBuilder.h>
    1313#include <llvm/Support/raw_ostream.h>
     14#include <llvm/Support/Format.h>
    1415#include <toolchain/toolchain.h>
    1516#include <toolchain/driver.h>
     17#include <set>
     18#include <thread>
    1619#include <stdlib.h>
    1720#include <sys/mman.h>
    1821#include <unistd.h>
     22#include <stdio.h>
     23#ifdef HAS_ADDRESS_SANITIZER
     24#include <sanitizer/asan_interface.h>
     25#endif
     26#ifdef HAVE_LIBUNWIND
     27#define UNW_LOCAL_ONLY
     28#include <libunwind.h>
     29#else
     30using unw_word_t = uint64_t;
     31#endif
    1932
    2033using namespace llvm;
     34
     35void __report_failure(const char * msg, const unw_word_t * trace) {
     36    raw_fd_ostream out(STDERR_FILENO, false);
     37    #ifdef HAVE_LIBUNWIND
     38    if (trace) {
     39        out.changeColor(raw_fd_ostream::WHITE, true);
     40        out << "Compilation Stacktrace:\n";
     41        out.resetColor();
     42        while (*trace) {
     43            const auto pc = *trace++;
     44            out << format_hex(pc, 16) << "   ";
     45            const auto len = codegen::ProgramName.length() + 32;
     46            char cmd[len];
     47            snprintf(cmd, len,"addr2line -fpCe %s %p", codegen::ProgramName.data(), reinterpret_cast<void *>(pc));
     48            FILE * f = popen(cmd, "r");
     49            if (f) {
     50                char buffer[1024] = {0};
     51                while(fgets(buffer, sizeof(buffer), f)) {
     52                    out << buffer;
     53                }
     54                pclose(f);
     55            }
     56            ++trace;
     57        }
     58    }
     59    #endif
     60    out.changeColor(raw_fd_ostream::WHITE, true);
     61    out << "Assertion `" << msg << "' failed.\n";
     62    out.resetColor();
     63    out.flush();
     64}
    2165
    2266Value * CBuilder::CreateOpenCall(Value * filename, Value * oflag, Value * mode) {
     
    74118}
    75119
    76 
    77120Value * CBuilder::CreateUnlinkCall(Value * path) {
    78121    Module * const m = getModule();
     
    95138}
    96139
    97 
    98140Value * CBuilder::CreateStrlenCall(Value * str) {
    99141    Module * const m = getModule();
     
    104146    return CreateCall(strlenFn, str);
    105147}
    106 
    107148
    108149Function * CBuilder::GetPrintf() {
     
    224265    Function * f = m->getFunction("malloc");
    225266    if (f == nullptr) {
    226         // f = LinkFunction("malloc", &malloc);
    227267        PointerType * const voidPtrTy = getVoidPtrTy();
    228268        FunctionType * fty = FunctionType::get(voidPtrTy, {sizeTy}, false);
     
    269309    }
    270310    #ifdef STDLIB_HAS_ALIGNED_ALLOC
    271     Value * const ptr = CreateCall(f, {align, size});
     311    CallInst * const ptr = CreateCall(f, {align, size});
     312    ptr->setTailCall();
    272313    #else
    273314    Value * ptr = CreateAlloca(voidPtrTy);
    274     Value * success = CreateCall(f, {ptr, align, size});
     315    CallInst * success = CreateCall(f, {ptr, align, size});
     316    success->setTailCall();
    275317    if (codegen::EnableAsserts) {
    276         CreateAssert(CreateICmpEQ(success, getInt32(0)), "CreateAlignedMalloc: posix_memalign reported bad allocation");
     318        CreateAssert(CreateICmpEQ(success, getInt32(0)),
     319                     "CreateAlignedMalloc: posix_memalign reported bad allocation");
    277320    }
    278321    ptr = CreateLoad(ptr);
     
    281324    return ptr;
    282325}
    283 
    284326
    285327Value * CBuilder::CreateRealloc(Value * const ptr, Value * size) {
     
    294336        f->setDoesNotAlias(0);
    295337        f->setDoesNotAlias(1);
    296         // f = LinkFunction("realloc", &realloc);
    297338    }
    298339    Value * const addr = CreatePointerCast(ptr, voidPtrTy);
     
    312353        f = Function::Create(fty, Function::ExternalLinkage, "free", m);
    313354        f->setCallingConv(CallingConv::C);
    314         // f = LinkFunction("free", &std::free);
    315355    }
    316356    ptr = CreatePointerCast(ptr, voidPtrTy);
     
    354394    Value * ptr = CreateCall(fMMap, {addr, size, prot, flags, fd, offset});
    355395    if (codegen::EnableAsserts) {
    356         CreateAssert(CheckMMapSuccess(ptr), "CreateMMap: mmap failed to allocate memory");
     396        DataLayout DL(m);
     397        IntegerType * const intTy = getIntPtrTy(DL);
     398        Value * success = CreateICmpNE(CreatePtrToInt(addr, intTy), ConstantInt::getAllOnesValue(intTy)); // MAP_FAILED = -1
     399        CreateAssert(success, "CreateMMap: mmap failed to allocate memory");
    357400    }
    358401    return ptr;
     
    417460}
    418461
    419 Value * CBuilder::CheckMMapSuccess(Value * const addr) {
    420     Module * const m = getModule();
    421     DataLayout DL(m);
    422     IntegerType * const intTy = getIntPtrTy(DL);
    423     return CreateICmpNE(CreatePtrToInt(addr, intTy), ConstantInt::getAllOnesValue(intTy)); // MAP_FAILED = -1
    424 }
    425 
    426462#ifndef MREMAP_MAYMOVE
    427463#define MREMAP_MAYMOVE  1
     
    448484        ptr = CreateCall(fMRemap, {addr, oldSize, newSize, flags});
    449485        if (codegen::EnableAsserts) {
    450             CreateAssert(CheckMMapSuccess(ptr), "CreateMRemap: mremap failed to allocate memory");
     486            Value * success = CreateICmpNE(CreatePtrToInt(addr, intTy), ConstantInt::getAllOnesValue(intTy)); // MAP_FAILED = -1
     487            CreateAssert(success, "CreateMRemap: mremap failed to allocate memory");
    451488        }
    452489    } else { // no OS mremap support
     
    594631}
    595632
     633Value * CBuilder::CreatePThreadYield() {
     634    Module * const m = getModule();
     635    Function * f = m->getFunction("pthread_yield");
     636    if (f == nullptr) {
     637        FunctionType * fty = FunctionType::get(getInt32Ty(), false);
     638        f = Function::Create(fty, Function::ExternalLinkage, "pthread_yield", m);
     639        f->setCallingConv(CallingConv::C);
     640    }
     641    return CreateCall(f);
     642}
     643
    596644Value * CBuilder::CreatePThreadExitCall(Value * value_ptr) {
    597645    Module * const m = getModule();
     
    612660    Function * pthreadJoinFunc = m->getFunction("pthread_join");
    613661    if (pthreadJoinFunc == nullptr) {
    614         Type * pthreadTy = getSizeTy();
    615         FunctionType * fty = FunctionType::get(getInt32Ty(), {pthreadTy, getVoidPtrTy()->getPointerTo()}, false);
     662        FunctionType * fty = FunctionType::get(getInt32Ty(), {getSizeTy(), getVoidPtrTy()->getPointerTo()}, false);
    616663        pthreadJoinFunc = Function::Create(fty, Function::ExternalLinkage, "pthread_join", m);
    617664        pthreadJoinFunc->setCallingConv(CallingConv::C);
     
    620667}
    621668
    622 void CBuilder::CreateAssert(Value * const assertion, StringRef failureMessage) {   
    623     if (codegen::EnableAsserts) {
     669void CBuilder::CreateAssert(Value * assertion, StringRef failureMessage) {
     670    if (LLVM_UNLIKELY(codegen::EnableAsserts)) {
    624671        Module * const m = getModule();
    625         Function * function = m->getFunction("__assert");
     672        Function * function = m->getFunction("assert");
     673        IntegerType * const int1Ty = getInt1Ty();
    626674        if (LLVM_UNLIKELY(function == nullptr)) {
    627675            auto ip = saveIP();
    628             FunctionType * fty = FunctionType::get(getVoidTy(), { getInt1Ty(), getInt8PtrTy(), getSizeTy() }, false);
    629             function = Function::Create(fty, Function::PrivateLinkage, "__assert", m);
     676            PointerType * const int8PtrTy = getInt8PtrTy();
     677            IntegerType * const unwWordTy = TypeBuilder<unw_word_t, false>::get(getContext());
     678            PointerType * const unwWordPtrTy = unwWordTy->getPointerTo();
     679            FunctionType * fty = FunctionType::get(getVoidTy(), { int1Ty, int8PtrTy, unwWordPtrTy }, false);
     680            function = Function::Create(fty, Function::PrivateLinkage, "assert", m);
    630681            function->setDoesNotThrow();
    631682            function->setDoesNotAlias(2);
     
    635686            auto arg = function->arg_begin();
    636687            arg->setName("assertion");
    637             Value * e = &*arg++;
     688            Value * assertion = &*arg++;
    638689            arg->setName("msg");
    639690            Value * msg = &*arg++;
    640             arg->setName("sz");
    641             Value * sz = &*arg;
     691            arg->setName("trace");
     692            Value * trace = &*arg++;
    642693            SetInsertPoint(entry);
    643             CreateCondBr(e, failure, success);
    644             SetInsertPoint(failure);
    645             Value * len = CreateAdd(sz, getSize(21));
    646             ConstantInt * _11 = getSize(11);
    647             Value * bytes = CreatePointerCast(CreateMalloc(len), getInt8PtrTy());
    648             CreateMemCpy(bytes, GetString("Assertion `"), _11, 1);
    649             CreateMemCpy(CreateGEP(bytes, _11), msg, sz, 1);
    650             CreateMemCpy(CreateGEP(bytes, CreateAdd(sz, _11)), GetString("' failed.\n"), getSize(10), 1);
    651             CreateWriteCall(getInt32(2), bytes, len);
    652 
    653 
     694            IRBuilder<>::CreateCondBr(assertion, success, failure);
     695            IRBuilder<>::SetInsertPoint(failure);
     696            IRBuilder<>::CreateCall(LinkFunction("__report_failure", __report_failure), { msg, trace });
    654697            CreateExit(-1);
    655             CreateBr(success); // necessary to satisfy the LLVM verifier. this is not actually executed.
     698            IRBuilder<>::CreateBr(success); // necessary to satisfy the LLVM verifier. this is never executed.
    656699            SetInsertPoint(success);
    657             CreateRetVoid();
     700            IRBuilder<>::CreateRetVoid();
    658701            restoreIP(ip);
    659702        }
    660         CreateCall(function, {CreateICmpEQ(assertion, Constant::getNullValue(assertion->getType())), GetString(failureMessage), getSize(failureMessage.size())});
     703        if (assertion->getType() != int1Ty) {
     704            assertion = CreateICmpNE(assertion, Constant::getNullValue(assertion->getType()));
     705        }
     706        IntegerType * const unwWordTy = TypeBuilder<unw_word_t, false>::get(getContext());
     707        PointerType * const unwWordPtrTy = unwWordTy->getPointerTo();
     708        #ifdef HAVE_LIBUNWIND
     709        std::vector<unw_word_t> stack;
     710        unw_context_t context;
     711        unw_cursor_t cursor;
     712        // Initialize cursor to current frame for local unwinding.
     713        unw_getcontext(&context);
     714        unw_init_local(&cursor, &context);
     715        // Unwind frames one by one, going up the frame stack.
     716        stack.reserve(64);
     717        while (unw_step(&cursor) > 0) {
     718            unw_word_t pc;
     719            unw_get_reg(&cursor, UNW_REG_IP, &pc);
     720            stack.push_back(pc);
     721            if (pc == 0) {
     722                break;
     723            }
     724        }
     725        GlobalVariable * global = nullptr;
     726        const auto n = stack.size();
     727        IntegerType * const unwTy = TypeBuilder<unw_word_t, false>::get(getContext());
     728        for (GlobalVariable & gv : m->getGlobalList()) {
     729            Type * const ty = gv.getValueType();
     730            if (ty->isArrayTy() && ty->getArrayElementType() == unwTy && ty->getArrayNumElements() == n) {
     731                const ConstantDataArray * const array = cast<ConstantDataArray>(gv.getOperand(0));
     732                bool found = true;
     733                for (auto i = n - 1; i != 0; --i) {
     734                    if (LLVM_LIKELY(array->getElementAsInteger(i) != stack[i])) {
     735                        found = false;
     736                        break;
     737                    }
     738                }
     739                if (LLVM_UNLIKELY(found)) {
     740                    global = &gv;
     741                    break;
     742                }
     743            }
     744        }
     745        if (LLVM_LIKELY(global == nullptr)) {
     746            Constant * const initializer = ConstantDataArray::get(getContext(), stack);
     747            global = new GlobalVariable(*m, initializer->getType(), true, GlobalVariable::InternalLinkage, initializer);
     748        }
     749        Value * const trace = CreatePointerCast(global, unwWordPtrTy);
     750        #else
     751        Constant * const trace = ConstantPointerNull::get(unwWordPtrTy);
     752        #endif
     753        IRBuilder<>::CreateCall(function, {assertion, GetString(failureMessage), trace});
    661754    }
    662755}
     
    674767}
    675768
    676 llvm::BasicBlock * CBuilder::CreateBasicBlock(std::string && name) {
     769BasicBlock * CBuilder::CreateBasicBlock(std::string && name) {
    677770    return BasicBlock::Create(getContext(), name, GetInsertBlock()->getParent());
    678771}
     
    717810}
    718811
    719 Value * CBuilder::CreateExtractBitField(llvm::Value * bits, Value * start, Value * length) {
     812Value * CBuilder::CreateExtractBitField(Value * bits, Value * start, Value * length) {
    720813    Constant * One = ConstantInt::get(bits->getType(), 1);
    721814    return CreateAnd(CreateLShr(bits, start), CreateSub(CreateShl(One, length), One));
     
    745838}
    746839
    747 Function * CBuilder::LinkFunction(llvm::StringRef name, FunctionType * type, void * functionPtr) const {
     840Function * CBuilder::LinkFunction(StringRef name, FunctionType * type, void * functionPtr) const {
    748841    assert (mDriver);
    749842    return mDriver->addLinkFunction(getModule(), name, type, functionPtr);
    750843}
    751844
    752 CBuilder::CBuilder(llvm::LLVMContext & C, const unsigned GeneralRegisterWidthInBits)
     845#ifdef HAS_ADDRESS_SANITIZER
     846
     847#define CHECK_ADDRESS(Ptr) \
     848    if (codegen::EnableAsserts) { \
     849        Module * const m = getModule(); \
     850        PointerType * voidPtrTy = getVoidPtrTy(); \
     851        IntegerType * sizeTy = getSizeTy(); \
     852        Function * isPoisoned = m->getFunction("__asan_region_is_poisoned"); \
     853        if (isPoisoned == nullptr) { \
     854            auto isPoisonedTy = FunctionType::get(voidPtrTy, {voidPtrTy, sizeTy}, false); \
     855            isPoisoned = Function::Create(isPoisonedTy, Function::ExternalLinkage, "__asan_region_is_poisoned", m); \
     856        } \
     857        Value * const addr = CreatePointerCast(Ptr, voidPtrTy); \
     858        Constant * const size = ConstantInt::get(sizeTy, Ptr->getType()->getPointerElementType()->getPrimitiveSizeInBits()); \
     859        Value * check = CreateCall(isPoisoned, { addr, size }); \
     860        check = CreateICmpEQ(check, ConstantPointerNull::get(voidPtrTy)); \
     861        CreateAssert(check, "Valid memory address"); \
     862    }
     863
     864LoadInst * CBuilder::CreateLoad(Value *Ptr, const char * Name) {
     865    CHECK_ADDRESS(Ptr);
     866    return IRBuilder<>::CreateLoad(Ptr, Name);
     867}
     868
     869LoadInst * CBuilder::CreateLoad(Value * Ptr, const Twine & Name) {
     870    CHECK_ADDRESS(Ptr);
     871    return IRBuilder<>::CreateLoad(Ptr, Name);
     872}
     873
     874LoadInst * CBuilder::CreateLoad(Type *Ty, Value *Ptr, const Twine & Name) {
     875    CHECK_ADDRESS(Ptr);
     876    return IRBuilder<>::CreateLoad(Ty, Ptr, Name);
     877}
     878
     879LoadInst * CBuilder::CreateLoad(Value *Ptr, bool isVolatile, const Twine & Name) {
     880    CHECK_ADDRESS(Ptr);
     881    return IRBuilder<>::CreateLoad(Ptr, isVolatile, Name);
     882}
     883
     884StoreInst * CBuilder::CreateStore(Value * Val, Value * Ptr, bool isVolatile) {
     885    CHECK_ADDRESS(Ptr);
     886    return IRBuilder<>::CreateStore(Val, Ptr, isVolatile);
     887}
     888
     889#undef CHECK_ADDRESS
     890
     891#endif
     892
     893CBuilder::CBuilder(LLVMContext & C, const unsigned GeneralRegisterWidthInBits)
    753894: IRBuilder<>(C)
    754895, mCacheLineAlignment(64)
Note: See TracChangeset for help on using the changeset viewer.