Skip to content
IRInterpreter.cpp 95.3 KiB
Newer Older
//===-- IRInterpreter.cpp ---------------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/Core/DataEncoder.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Expression/ClangExpressionDeclMap.h"
#include "lldb/Expression/ClangExpressionVariable.h"
#include "lldb/Expression/IRForTarget.h"
#include "lldb/Expression/IRInterpreter.h"

#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/raw_ostream.h"

#include <map>

using namespace llvm;

static std::string 
PrintValue(const Value *value, bool truncate = false)
{
    std::string s;
    raw_string_ostream rso(s);
    value->print(rso);
    rso.flush();
    if (truncate)
        s.resize(s.length() - 1);
    
    size_t offset;
    while ((offset = s.find('\n')) != s.npos)
        s.erase(offset, 1);
    while (s[0] == ' ' || s[0] == '\t')
        s.erase(0, 1);
        
    return s;
}

static std::string
PrintType(const Type *type, bool truncate = false)
{
    std::string s;
    raw_string_ostream rso(s);
    type->print(rso);
    rso.flush();
    if (truncate)
        s.resize(s.length() - 1);
    return s;
}

class InterpreterStackFrame
    typedef std::map <const Value*, lldb::addr_t> ValueMap;
    struct PlacedValue
        lldb_private::Value     lldb_value;
        lldb::addr_t            process_address;
        size_t                  size;
        
        PlacedValue (lldb_private::Value &_lldb_value,
                     lldb::addr_t _process_address,
                     size_t _size) :
            lldb_value(_lldb_value),
            process_address(_process_address),
            size(_size)
    typedef std::vector <PlacedValue> PlacedValueVector;
    PlacedValueVector                       m_placed_values;
    DataLayout                             &m_target_data;
    lldb_private::ClangExpressionDeclMap   *m_decl_map;
    lldb_private::IRMemoryMap              &m_memory_map;
    const BasicBlock                       *m_bb;
    BasicBlock::const_iterator              m_ii;
    BasicBlock::const_iterator              m_ie;
    
    lldb::ByteOrder                         m_byte_order;
    size_t                                  m_addr_byte_size;
    
    InterpreterStackFrame (DataLayout &target_data,
                           lldb_private::ClangExpressionDeclMap *decl_map,
                           lldb_private::IRMemoryMap &memory_map) :
        m_target_data (target_data),
        m_decl_map (decl_map),
        m_memory_map (memory_map)
    {
        m_byte_order = (target_data.isLittleEndian() ? lldb::eByteOrderLittle : lldb::eByteOrderBig);
        m_addr_byte_size = (target_data.getPointerSize(0));
    }
    
    void Jump (const BasicBlock *bb)
    {
        m_bb = bb;
        m_ii = m_bb->begin();
        m_ie = m_bb->end();
    }
    
    std::string SummarizeValue (const Value *value)
    {
        lldb_private::StreamString ss;

        ss.Printf("%s", PrintValue(value).c_str());
        
        ValueMap::iterator i = m_values.find(value);

        if (i != m_values.end())
        {
            lldb::addr_t addr = i->second;
            ss.Printf(" 0x%llx", (unsigned long long)addr);
        }
        
        return ss.GetString();
    }
    
    bool AssignToMatchType (lldb_private::Scalar &scalar, uint64_t u64value, Type *type)
    {
        size_t type_size = m_target_data.getTypeStoreSize(type);

        switch (type_size)
        {
        case 1:
            scalar = (uint8_t)u64value;
            break;
        case 2:
            scalar = (uint16_t)u64value;
            break;
        case 4:
            scalar = (uint32_t)u64value;
            break;
        case 8:
            scalar = (uint64_t)u64value;
            break;
        default:
            return false;
        }
        
        return true;
    }
    
    bool EvaluateValue (lldb_private::Scalar &scalar, const Value *value, Module &module)
    {
        const Constant *constant = dyn_cast<Constant>(value);
        
        if (constant)
        {
            if (const ConstantInt *constant_int = dyn_cast<ConstantInt>(constant))
            {                
                return AssignToMatchType(scalar, constant_int->getLimitedValue(), value->getType());
            }
        }
        else
        {
            lldb::addr_t process_address = ResolveValue(value, module);
            size_t value_size = m_target_data.getTypeStoreSize(value->getType());
        
            lldb_private::DataExtractor value_extractor;
            lldb_private::Error extract_error;
            m_memory_map.GetMemoryData(value_extractor, process_address, value_size, extract_error);
            
            if (!extract_error.Success())
Greg Clayton's avatar
Greg Clayton committed
            lldb::offset_t offset = 0;
            uint64_t u64value = value_extractor.GetMaxU64(&offset, value_size);
                    
            return AssignToMatchType(scalar, u64value, value->getType());
        }
        
        return false;
    }
    
    bool AssignValue (const Value *value, lldb_private::Scalar &scalar, Module &module)
    {
        lldb::addr_t process_address = ResolveValue (value, module);
        
        if (process_address == LLDB_INVALID_ADDRESS)
            return false;
    
        lldb_private::Scalar cast_scalar;
        
        if (!AssignToMatchType(cast_scalar, scalar.GetRawBits64(0), value->getType()))
            return false;
                
        size_t value_byte_size = m_target_data.getTypeStoreSize(value->getType());
        lldb_private::DataBufferHeap buf(value_byte_size, 0);
        lldb_private::Error get_data_error;
        if (!cast_scalar.GetAsMemoryData(buf.GetBytes(), buf.GetByteSize(), m_byte_order, get_data_error))
        lldb_private::Error write_error;
        m_memory_map.WriteMemory(process_address, buf.GetBytes(), buf.GetByteSize(), write_error);
        return write_error.Success();
    bool ResolveConstantValue (APInt &value, const Constant *constant)
    {
        if (const ConstantInt *constant_int = dyn_cast<ConstantInt>(constant))
        {
            value = constant_int->getValue();
            return true;
        else if (const ConstantFP *constant_fp = dyn_cast<ConstantFP>(constant))
            value = constant_fp->getValueAPF().bitcastToAPInt();
            return true;
        else if (const ConstantExpr *constant_expr = dyn_cast<ConstantExpr>(constant))
        {
            switch (constant_expr->getOpcode())
            {
                default:
                    return false;
                case Instruction::IntToPtr:
                case Instruction::PtrToInt:
                case Instruction::BitCast:
                    return ResolveConstantValue(value, constant_expr->getOperand(0));
                case Instruction::GetElementPtr:
                {
                    ConstantExpr::const_op_iterator op_cursor = constant_expr->op_begin();
                    ConstantExpr::const_op_iterator op_end = constant_expr->op_end();
                                    
                    Constant *base = dyn_cast<Constant>(*op_cursor);
                    
                    if (!base)
                        return false;
                    
                    if (!ResolveConstantValue(value, base))
                        return false;
                    
                    op_cursor++;
                    
                    if (op_cursor == op_end)
                        return true; // no offset to apply!
                    
                    SmallVector <Value *, 8> indices (op_cursor, op_end);
                    
                    uint64_t offset = m_target_data.getIndexedOffset(base->getType(), indices);
                    
                    const bool is_signed = true;
                    value += APInt(value.getBitWidth(), offset, is_signed);
                    
                    return true;
                }
    bool ResolveConstant (lldb::addr_t process_address, const Constant *constant)
    {
        APInt resolved_value;
        
        if (!ResolveConstantValue(resolved_value, constant))
            return false;
        
        const uint64_t *raw_data = resolved_value.getRawData();
            
        size_t constant_size = m_target_data.getTypeStoreSize(constant->getType());
        
        lldb_private::Error write_error;
        
        m_memory_map.WriteMemory(process_address, (uint8_t*)raw_data, constant_size, write_error);
        
        return write_error.Success();
    
    lldb::addr_t MallocPointer ()
    {
        lldb_private::Error alloc_error;

        lldb::addr_t ret = m_memory_map.Malloc(m_target_data.getPointerSize(), m_target_data.getPointerPrefAlignment(), lldb::ePermissionsReadable | lldb::ePermissionsWritable, lldb_private::IRMemoryMap::eAllocationPolicyMirror, alloc_error);
        if (alloc_error.Success())
            return ret;
        else
            return LLDB_INVALID_ADDRESS;
    }
    
    lldb::addr_t Malloc (llvm::Type *type, size_t override_byte_size = 0)
    {
        lldb_private::Error alloc_error;
        
        if (!override_byte_size)
            override_byte_size = m_target_data.getTypeStoreSize(type);
        
        lldb::addr_t ret = m_memory_map.Malloc(override_byte_size, m_target_data.getPrefTypeAlignment(type), lldb::ePermissionsReadable | lldb::ePermissionsWritable, lldb_private::IRMemoryMap::eAllocationPolicyMirror, alloc_error);
        
        if (alloc_error.Success())
            return ret;
        else
            return LLDB_INVALID_ADDRESS;
    }
    
    lldb::addr_t PlaceLLDBValue (const llvm::Value *value, lldb_private::Value lldb_value)
    {
        if (!m_decl_map)
            return false;
        
        lldb_private::Error alloc_error;
        lldb_private::RegisterInfo *reg_info = lldb_value.GetRegisterInfo();
                
        lldb::addr_t ret;
        
        size_t value_size = m_target_data.getTypeStoreSize(value->getType());
        
        if (reg_info && (reg_info->encoding == lldb::eEncodingVector))
            value_size = reg_info->byte_size;
        
        if (!reg_info && (lldb_value.GetValueType() == lldb_private::Value::eValueTypeLoadAddress))
            return lldb_value.GetScalar().ULongLong();
        
        ret = Malloc(value->getType(), value_size);
        
        if (ret == LLDB_INVALID_ADDRESS)
            return LLDB_INVALID_ADDRESS;
        
        lldb_private::DataBufferHeap buf(value_size, 0);
        
        m_decl_map->ReadTarget(m_memory_map, buf.GetBytes(), lldb_value, value_size);
        
        lldb_private::Error write_error;
        
        m_memory_map.WriteMemory(ret, buf.GetBytes(), buf.GetByteSize(), write_error);
        
        if (!write_error.Success())
        {
            lldb_private::Error free_error;
            m_memory_map.Free(ret, free_error);
            return LLDB_INVALID_ADDRESS;
        }
        
        m_placed_values.push_back(PlacedValue(lldb_value, ret, value_size));
        
        return ret;
    }
    
    void RestoreLLDBValues ()
    {
        for (PlacedValue &placed_value : m_placed_values)
        {
            lldb_private::DataBufferHeap buf(placed_value.size, 0);
            
            lldb_private::Error read_error;
            
            m_memory_map.ReadMemory(buf.GetBytes(), placed_value.process_address, buf.GetByteSize(), read_error);
            
            if (read_error.Success())
                m_decl_map->WriteTarget(m_memory_map, placed_value.lldb_value, buf.GetBytes(), buf.GetByteSize());
        }
    }
    
    std::string PrintData (lldb::addr_t addr, llvm::Type *type)
    {
        size_t length = m_target_data.getTypeStoreSize(type);
        
        lldb_private::DataBufferHeap buf(length, 0);
        
        lldb_private::Error read_error;
        
        m_memory_map.ReadMemory(buf.GetBytes(), addr, length, read_error);
        
        if (!read_error.Success())
            return std::string("<couldn't read data>");
        
        lldb_private::StreamString ss;
        
        for (size_t i = 0; i < length; i++)
        {
            if ((!(i & 0xf)) && i)
                ss.Printf("%02hhx - ", buf.GetBytes()[i]);
            else
                ss.Printf("%02hhx ", buf.GetBytes()[i]);
        }
        
        return ss.GetString();
    }
    
    lldb::addr_t ResolveValue (const Value *value, Module &module)
        if (!m_decl_map)
            return LLDB_INVALID_ADDRESS;
        
        ValueMap::iterator i = m_values.find(value);
        
        if (i != m_values.end())
            return i->second;
        
        const GlobalValue *global_value = dyn_cast<GlobalValue>(value);
        
        // If the variable is indirected through the argument
        // array then we need to build an extra level of indirection
        // for it.  This is the default; only magic arguments like
        // "this", "self", and "_cmd" are direct.
        bool variable_is_this = false;
        // If the variable is a function pointer, we do not need to
        // build an extra layer of indirection for it because it is
        // accessed directly.
        bool variable_is_function_address = false;
        
        // Attempt to resolve the value using the program's data.
        // If it is, the values to be created are:
        //
        // data_region - a region of memory in which the variable's data resides.
        // ref_region - a region of memory in which its address (i.e., &var) resides.
        //   In the JIT case, this region would be a member of the struct passed in.
        // pointer_region - a region of memory in which the address of the pointer
        //   resides.  This is an IR-level variable.
        do
        {
Greg Clayton's avatar
Greg Clayton committed
            lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));

            lldb_private::Value resolved_value;
            lldb_private::ClangExpressionVariable::FlagType flags = 0;
            if (global_value)
            {            
                clang::NamedDecl *decl = IRForTarget::DeclForGlobal(global_value, &module);

                if (!decl)
                    break;
                
                if (isa<clang::FunctionDecl>(decl))
                    variable_is_function_address = true;
                resolved_value = m_decl_map->LookupDecl(decl, flags);
            }
            else
            {
                // Special-case "this", "self", and "_cmd"
                
                std::string name_str = value->getName().str();
                
                if (name_str == "this" ||
                    name_str == "self" ||
                    name_str == "_cmd")
                    resolved_value = m_decl_map->GetSpecialValue(lldb_private::ConstString(name_str.c_str()));
                    variable_is_this = true;
                }
            
            if (resolved_value.GetScalar().GetType() != lldb_private::Scalar::e_void)
            {
                if (resolved_value.GetContextType() == lldb_private::Value::eContextTypeRegisterInfo)
                {
                    if (variable_is_this)
                    {                                                
                        lldb_private::Error alloc_error;
                        lldb::addr_t ref_addr = Malloc(value->getType());
                        if (ref_addr == LLDB_INVALID_ADDRESS)
                            return LLDB_INVALID_ADDRESS;
                        lldb_private::Error write_error;
                        m_memory_map.WritePointerToMemory(ref_addr, resolved_value.GetScalar().ULongLong(), write_error);
                        if (!write_error.Success())
                            return LLDB_INVALID_ADDRESS;
                        
                        if (log)
                        {
                            log->Printf("Made an allocation for \"this\" register variable %s", PrintValue(value).c_str());
                            log->Printf("  Data region    : %llx", (unsigned long long)resolved_value.GetScalar().ULongLong());
                            log->Printf("  Ref region     : %llx", (unsigned long long)ref_addr);
                        m_values[value] = ref_addr;
                        return ref_addr;
                    }
                    else if (flags & lldb_private::ClangExpressionVariable::EVBareRegister)
                    {                                                
                        lldb::addr_t data_address = PlaceLLDBValue(value, resolved_value);
                        if (!data_address)
                            return LLDB_INVALID_ADDRESS;
                        lldb::addr_t ref_address = MallocPointer();
                        if (ref_address == LLDB_INVALID_ADDRESS)
                        {
                            lldb_private::Error free_error;
                            m_memory_map.Free(data_address, free_error);
                            return LLDB_INVALID_ADDRESS;
                        }
                        lldb_private::Error write_error;

                        m_memory_map.WritePointerToMemory(ref_address, data_address, write_error);
                        if (!write_error.Success())
                        {
                            lldb_private::Error free_error;
                            m_memory_map.Free(data_address, free_error);
                            m_memory_map.Free(ref_address, free_error);
                            return LLDB_INVALID_ADDRESS;
                        }
                        
                        if (log)
                        {
                            log->Printf("Made an allocation for bare register variable %s", PrintValue(value).c_str());
                            log->Printf("  Data contents  : %s", PrintData(data_address, value->getType()).c_str());
                            log->Printf("  Data region    : 0x%llx", (unsigned long long)data_address);
                            log->Printf("  Ref region     : 0x%llx", (unsigned long long)ref_address);
                        m_values[value] = ref_address;
                        return ref_address;
                    {                                               
                        lldb::addr_t data_address = PlaceLLDBValue(value, resolved_value);
                        
                        if (data_address == LLDB_INVALID_ADDRESS)
                            return LLDB_INVALID_ADDRESS;
                        lldb::addr_t ref_address = MallocPointer();
                        if (ref_address == LLDB_INVALID_ADDRESS)
                        {
                            lldb_private::Error free_error;
                            m_memory_map.Free(data_address, free_error);
                            return LLDB_INVALID_ADDRESS;
                        }
                        
                        lldb::addr_t pointer_address = MallocPointer();
                        
                        if (pointer_address == LLDB_INVALID_ADDRESS)
                        {
                            lldb_private::Error free_error;
                            m_memory_map.Free(data_address, free_error);
                            m_memory_map.Free(ref_address, free_error);
                            return LLDB_INVALID_ADDRESS;
                        }
                                                
                        lldb_private::Error write_error;
                        m_memory_map.WritePointerToMemory(ref_address, data_address, write_error);
                        if (!write_error.Success())
                        {
                            lldb_private::Error free_error;
                            m_memory_map.Free(data_address, free_error);
                            m_memory_map.Free(ref_address, free_error);
                            m_memory_map.Free(pointer_address, free_error);
                            return LLDB_INVALID_ADDRESS;
                        }
                        write_error.Clear();
                        m_memory_map.WritePointerToMemory(pointer_address, ref_address, write_error);
                        if (!write_error.Success())
                        {
                            lldb_private::Error free_error;
                            m_memory_map.Free(data_address, free_error);
                            m_memory_map.Free(ref_address, free_error);
                            m_memory_map.Free(pointer_address, free_error);
                            return LLDB_INVALID_ADDRESS;
                        }
                        
                        if (log)
                        {
                            log->Printf("Made an allocation for ordinary register variable %s", PrintValue(value).c_str());
                            log->Printf("  Data contents  : %s", PrintData(data_address, value->getType()).c_str());
                            log->Printf("  Data region    : 0x%llx", (unsigned long long)data_address);
                            log->Printf("  Ref region     : 0x%llx", (unsigned long long)ref_address);
                            log->Printf("  Pointer region : 0x%llx", (unsigned long long)pointer_address);
                        m_values[value] = pointer_address;
                        return pointer_address;
                    bool no_extra_redirect = (variable_is_this || variable_is_function_address);
                    
                    lldb::addr_t data_address = PlaceLLDBValue(value, resolved_value);
                    if (data_address == LLDB_INVALID_ADDRESS)
                        return LLDB_INVALID_ADDRESS;
                    lldb::addr_t ref_address = MallocPointer();
                    if (ref_address == LLDB_INVALID_ADDRESS)
                    {
                        lldb_private::Error free_error;
                        m_memory_map.Free(data_address, free_error);
                        return LLDB_INVALID_ADDRESS;
                    }

                    lldb::addr_t pointer_address = LLDB_INVALID_ADDRESS;
                    if (!no_extra_redirect)
                        pointer_address = MallocPointer();
                        
                        if (pointer_address == LLDB_INVALID_ADDRESS)
                        {
                            lldb_private::Error free_error;
                            m_memory_map.Free(data_address, free_error);
                            m_memory_map.Free(ref_address, free_error);
                            return LLDB_INVALID_ADDRESS;
                        }
                    }
                    
                    lldb_private::Error write_error;
                    m_memory_map.WritePointerToMemory(ref_address, data_address, write_error);
                    
                    if (!write_error.Success())
                    {
                        lldb_private::Error free_error;
                        m_memory_map.Free(data_address, free_error);
                        m_memory_map.Free(ref_address, free_error);
                        if (pointer_address != LLDB_INVALID_ADDRESS)
                            m_memory_map.Free(pointer_address, free_error);
                        return LLDB_INVALID_ADDRESS;
                    }
                                        
                    if (!no_extra_redirect)
                    {
                        write_error.Clear();
                        m_memory_map.WritePointerToMemory(pointer_address, ref_address, write_error);
                        
                        if (!write_error.Success())
                        {
                            lldb_private::Error free_error;
                            m_memory_map.Free(data_address, free_error);
                            m_memory_map.Free(ref_address, free_error);
                            if (pointer_address != LLDB_INVALID_ADDRESS)
                                m_memory_map.Free(pointer_address, free_error);
                            return LLDB_INVALID_ADDRESS;
                        }
                        log->Printf("Made an allocation for %s", PrintValue(value).c_str());
                        log->Printf("  Data contents  : %s", PrintData(data_address, value->getType()).c_str());
                        log->Printf("  Data region    : %llx", (unsigned long long)data_address);
                        log->Printf("  Ref region     : %llx", (unsigned long long)ref_address);
                        if (!variable_is_this)
                            log->Printf("  Pointer region : %llx", (unsigned long long)pointer_address);
                    if (no_extra_redirect)
                    {
                        m_values[value] = ref_address;
                        return ref_address;
                    }
                    {
                        m_values[value] = pointer_address;
                        return pointer_address;
                    }
                }
            }
        }
        while(0);
        
        // Fall back and allocate space [allocation type Alloca]
        
        lldb::addr_t data_address = Malloc(value->getType());
                
        if (const Constant *constant = dyn_cast<Constant>(value))
            if (!ResolveConstant (data_address, constant))
            {
                lldb_private::Error free_error;
                m_memory_map.Free(data_address, free_error);
                return LLDB_INVALID_ADDRESS;
            }
        m_values[value] = data_address;
        return data_address;
    }
    
    bool ConstructResult (lldb::ClangExpressionVariableSP &result,
                          const GlobalValue *result_value,
                          const lldb_private::ConstString &result_name,
                          lldb_private::TypeFromParser result_type,
                          Module &module)
    {
        if (!m_decl_map)
            return false;
        
        // The result_value resolves to P, a pointer to a region R containing the result data.
        // If the result variable is a reference, the region R contains a pointer to the result R_final in the original process.
        
        if (!result_value)
            return true; // There was no slot for a result – the expression doesn't return one.
        
        ValueMap::iterator i = m_values.find(result_value);

        if (i == m_values.end())
            return false; // There was a slot for the result, but we didn't write into it.
        
        lldb::addr_t P = i->second;
        
        Type *pointer_ty = result_value->getType();
        PointerType *pointer_ptr_ty = dyn_cast<PointerType>(pointer_ty);
        if (!pointer_ptr_ty)
            return false;
        Type *R_ty = pointer_ptr_ty->getElementType();
                
        lldb_private::Error read_error;
        lldb::addr_t R;
        m_memory_map.ReadPointerFromMemory(&R, P, read_error);
        if (!read_error.Success())
            return false;
        
        lldb_private::Value base;
        
        bool transient = false;
        bool maybe_make_load = false;
        if (m_decl_map->ResultIsReference(result_name))
        {
            PointerType *R_ptr_ty = dyn_cast<PointerType>(R_ty);           
            if (!R_ptr_ty)
                return false;
            
            read_error.Clear();
            lldb::addr_t R_pointer;
            m_memory_map.ReadPointerFromMemory(&R_pointer, R, read_error);
            if (!read_error.Success())
            // We got a bare pointer.  We are going to treat it as a load address
            // or a file address, letting decl_map make the choice based on whether
            // or not a process exists.
            bool was_placed = false;
            for (PlacedValue &value : m_placed_values)
            {
                if (value.process_address == R_pointer)
                {
                    base = value.lldb_value;
                    was_placed = true;
                    break;
                }
            {
                base.SetContext(lldb_private::Value::eContextTypeInvalid, NULL);
                base.SetValueType(lldb_private::Value::eValueTypeFileAddress);
                base.GetScalar() = (unsigned long long)R_pointer;
                maybe_make_load = true;
            }
        }
        else
        {
            base.SetContext(lldb_private::Value::eContextTypeInvalid, NULL);
            base.SetValueType(lldb_private::Value::eValueTypeLoadAddress);
            base.GetScalar() = (unsigned long long)R;
        return m_decl_map->CompleteResultVariable (result, m_memory_map, base, result_name, result_type, transient, maybe_make_load);
IRInterpreter::maybeRunOnFunction (lldb_private::ClangExpressionDeclMap *decl_map,
                                   lldb_private::IRMemoryMap &memory_map,
                                   lldb_private::Stream *error_stream,
                                   lldb::ClangExpressionVariableSP &result,
                                   const lldb_private::ConstString &result_name,
                                   lldb_private::TypeFromParser result_type,
                                   Function &llvm_function,
                                   Module &llvm_module,
                                   lldb_private::Error &err)
    if (supportsFunction (llvm_function, err))
        return runOnFunction(decl_map,
                             memory_map,
                             error_stream,
                             result,
                             result_name, 
                             result_type, 
                             llvm_function,
static const char *unsupported_opcode_error         = "Interpreter doesn't handle one of the expression's opcodes";
static const char *interpreter_initialization_error = "Interpreter couldn't be initialized";
static const char *interpreter_internal_error       = "Interpreter encountered an internal error";
static const char *bad_value_error                  = "Interpreter couldn't resolve a value during execution";
static const char *memory_allocation_error          = "Interpreter couldn't allocate memory";
static const char *memory_write_error               = "Interpreter couldn't write to memory";
static const char *memory_read_error                = "Interpreter couldn't read from memory";
static const char *infinite_loop_error              = "Interpreter ran for too many cycles";
static const char *bad_result_error                 = "Result of expression is in bad memory";
IRInterpreter::supportsFunction (Function &llvm_function, 
                                 lldb_private::Error &err)
Greg Clayton's avatar
Greg Clayton committed
    lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
    
    for (Function::iterator bbi = llvm_function.begin(), bbe = llvm_function.end();
         bbi != bbe;
         ++bbi)
    {
        for (BasicBlock::iterator ii = bbi->begin(), ie = bbi->end();
             ii != ie;
             ++ii)
        {
            switch (ii->getOpcode())
            {
            default:
                {
                    if (log)
                        log->Printf("Unsupported instruction: %s", PrintValue(ii).c_str());
                    err.SetErrorToGenericError();
                    err.SetErrorString(unsupported_opcode_error);
                    return false;
                }
            case Instruction::Add:
            case Instruction::Alloca:
            case Instruction::BitCast:
            case Instruction::Br:
            case Instruction::GetElementPtr:
                break;
            case Instruction::ICmp:
                {
                    ICmpInst *icmp_inst = dyn_cast<ICmpInst>(ii);
                    
                    if (!icmp_inst)
                    {
                        err.SetErrorToGenericError();
                        err.SetErrorString(interpreter_internal_error);
                    
                    switch (icmp_inst->getPredicate())
                    {
                    default:
                        {
                            if (log)
                                log->Printf("Unsupported ICmp predicate: %s", PrintValue(ii).c_str());
                            
                            err.SetErrorToGenericError();
                            err.SetErrorString(unsupported_opcode_error);
                            return false;
                        }
                    case CmpInst::ICMP_EQ:
                    case CmpInst::ICMP_NE:
                    case CmpInst::ICMP_UGT:
                    case CmpInst::ICMP_UGE:
                    case CmpInst::ICMP_ULT:
                    case CmpInst::ICMP_ULE:
                    case CmpInst::ICMP_SGT:
                    case CmpInst::ICMP_SGE:
                    case CmpInst::ICMP_SLT:
                    case CmpInst::ICMP_SLE:
                        break;
                    }
                }
                break;
            case Instruction::And:
            case Instruction::AShr:
            case Instruction::IntToPtr:
            case Instruction::PtrToInt:
            case Instruction::Load:
            case Instruction::LShr:
            case Instruction::Mul:
            case Instruction::Or:
            case Instruction::Ret:
            case Instruction::SDiv:
            case Instruction::Shl:
            case Instruction::SRem:
            case Instruction::Store:
            case Instruction::Sub:
            case Instruction::UDiv:
            case Instruction::URem:
            case Instruction::Xor:
            case Instruction::ZExt:
IRInterpreter::runOnFunction (lldb_private::ClangExpressionDeclMap *decl_map,
                              lldb_private::IRMemoryMap &memory_map,
                              lldb_private::Stream *error_stream,
                              lldb::ClangExpressionVariableSP &result,
                              const lldb_private::ConstString &result_name,
                              lldb_private::TypeFromParser result_type,
                              Function &llvm_function,
                              Module &llvm_module,
                              lldb_private::Error &err)
Greg Clayton's avatar
Greg Clayton committed
    lldb_private::Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
    DataLayout target_data(&llvm_module);
    InterpreterStackFrame frame(target_data, decl_map, memory_map);

    uint32_t num_insts = 0;
    
    frame.Jump(llvm_function.begin());
    
    while (frame.m_ii != frame.m_ie && (++num_insts < 4096))
    {
        const Instruction *inst = frame.m_ii;
        
        if (log)
            log->Printf("Interpreting %s", PrintValue(inst).c_str());
        
        switch (inst->getOpcode())
        {
        default:
            break;
        case Instruction::Add:
        case Instruction::Sub:
        case Instruction::Mul:
        case Instruction::SDiv:
        case Instruction::UDiv:
        case Instruction::SRem:
        case Instruction::URem:
        case Instruction::Shl:
        case Instruction::LShr:
        case Instruction::AShr:
        case Instruction::And:
        case Instruction::Or:
        case Instruction::Xor:
            {
                const BinaryOperator *bin_op = dyn_cast<BinaryOperator>(inst);
                
                if (!bin_op)
                {
                    if (log)
                        log->Printf("getOpcode() returns %s, but instruction is not a BinaryOperator", inst->getOpcodeName());
                    err.SetErrorToGenericError();
                    err.SetErrorString(interpreter_internal_error);
                    return false;                
                }
                
                Value *lhs = inst->getOperand(0);
                Value *rhs = inst->getOperand(1);
                
                lldb_private::Scalar L;
                lldb_private::Scalar R;
                
                if (!frame.EvaluateValue(L, lhs, llvm_module))
                {
                    if (log)
                        log->Printf("Couldn't evaluate %s", PrintValue(lhs).c_str());
                    err.SetErrorToGenericError();
                    err.SetErrorString(bad_value_error);
                    return false;
                }
                
                if (!frame.EvaluateValue(R, rhs, llvm_module))
                {
                    if (log)
                        log->Printf("Couldn't evaluate %s", PrintValue(rhs).c_str());
                    err.SetErrorToGenericError();
                    err.SetErrorString(bad_value_error);