<commit_before>//===-- ThreadPlanCallFunction.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/Target/ThreadPlanCallFunction.h"

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/lldb-private-log.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"

using namespace lldb;
using namespace lldb_private;

//----------------------------------------------------------------------
// ThreadPlanCallFunction: Plan to call a single function
//----------------------------------------------------------------------

ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
                                                Address &function,
                                                lldb::addr_t arg,
                                                bool stop_other_threads,
                                                bool discard_on_error,
                                                lldb::addr_t *this_arg) :
    ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
    m_valid (false),
    m_stop_other_threads (stop_other_threads),
    m_arg_addr (arg),
    m_args (NULL),
    m_process (thread.GetProcess()),
    m_thread (thread)
{
    SetOkayToDiscard (discard_on_error);

    Process& process = thread.GetProcess();
    Target& target = process.GetTarget();
    const ABI *abi = process.GetABI();

    if (!abi)
        return;

    lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
    
    SymbolContextList contexts;
    SymbolContext context;
    ModuleSP executableModuleSP (target.GetExecutableModule());

    if (!executableModuleSP ||
        !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
        return;
    
    contexts.GetContextAtIndex(0, context);
    
    m_start_addr = context.symbol->GetValue();
    lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);

    if (!thread.SaveFrameZeroState(m_register_backup))
        return;

    m_function_addr = function;
    lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
        
    if (!abi->PrepareTrivialCall(thread, 
                                 spBelowRedZone, 
                                 FunctionLoadAddr, 
                                 StartLoadAddr, 
                                 m_arg_addr,
                                 this_arg))
        return;
    
    m_valid = true;    
}

ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
                                                Address &function,
                                                ValueList &args,
                                                bool stop_other_threads,
                                                bool discard_on_error) :
    ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
    m_valid (false),
    m_stop_other_threads (stop_other_threads),
    m_arg_addr (0),
    m_args (&args),
    m_process (thread.GetProcess()),
    m_thread (thread)
{
    
    SetOkayToDiscard (discard_on_error);
    
    Process& process = thread.GetProcess();
    Target& target = process.GetTarget();
    const ABI *abi = process.GetABI();
    
    if(!abi)
        return;
    
    lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
    
    SymbolContextList contexts;
    SymbolContext context;
    ModuleSP executableModuleSP (target.GetExecutableModule());
    
    if (!executableModuleSP ||
        !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
        return;
    
    contexts.GetContextAtIndex(0, context);
    
    m_start_addr = context.symbol->GetValue();
    lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
    
    if(!thread.SaveFrameZeroState(m_register_backup))
        return;
    
    m_function_addr = function;
    lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
    
    if (!abi->PrepareNormalCall(thread, 
                                spBelowRedZone, 
                                FunctionLoadAddr, 
                                StartLoadAddr, 
                                *m_args))
        return;
    
    m_valid = true;    
}

ThreadPlanCallFunction::~ThreadPlanCallFunction ()
{
}

void
ThreadPlanCallFunction::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
    if (level == lldb::eDescriptionLevelBrief)
    {
        s->Printf("Function call thread plan");
    }
    else
    {
        if (m_args)
            s->Printf("Thread plan to call 0x%llx with parsed arguments", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
        else
            s->Printf("Thread plan to call 0x%llx void * argument at: 0x%llx", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
    }
}

bool
ThreadPlanCallFunction::ValidatePlan (Stream *error)
{
    if (!m_valid)
        return false;

    return true;
}

bool
ThreadPlanCallFunction::PlanExplainsStop ()
{
    if (!m_subplan_sp)
        return false;
    else
        return m_subplan_sp->PlanExplainsStop();
}

bool
ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
{
    if (PlanExplainsStop())
    {
        Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
        
        if (log)
        {
            RegisterContext *reg_ctx = m_thread.GetRegisterContext();

            log->PutCString("Function completed.  Register state was:");

            for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount();
                 register_index < num_registers;
                 ++register_index)
            {
                const char *register_name = reg_ctx->GetRegisterName(register_index);
                uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS);
                <commit_msg>Expressions now claim responsibility for all stops that occur while they run.  This means that they clean up after themselves even when they crash.<commit_after>//===-- ThreadPlanCallFunction.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/Target/ThreadPlanCallFunction.h"

// C Includes
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/lldb-private-log.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlanRunToAddress.h"

using namespace lldb;
using namespace lldb_private;

//----------------------------------------------------------------------
// ThreadPlanCallFunction: Plan to call a single function
//----------------------------------------------------------------------

ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
                                                Address &function,
                                                lldb::addr_t arg,
                                                bool stop_other_threads,
                                                bool discard_on_error,
                                                lldb::addr_t *this_arg) :
    ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
    m_valid (false),
    m_stop_other_threads (stop_other_threads),
    m_arg_addr (arg),
    m_args (NULL),
    m_process (thread.GetProcess()),
    m_thread (thread)
{
    SetOkayToDiscard (discard_on_error);

    Process& process = thread.GetProcess();
    Target& target = process.GetTarget();
    const ABI *abi = process.GetABI();

    if (!abi)
        return;

    lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
    
    SymbolContextList contexts;
    SymbolContext context;
    ModuleSP executableModuleSP (target.GetExecutableModule());

    if (!executableModuleSP ||
        !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
        return;
    
    contexts.GetContextAtIndex(0, context);
    
    m_start_addr = context.symbol->GetValue();
    lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);

    if (!thread.SaveFrameZeroState(m_register_backup))
        return;

    m_function_addr = function;
    lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
        
    if (!abi->PrepareTrivialCall(thread, 
                                 spBelowRedZone, 
                                 FunctionLoadAddr, 
                                 StartLoadAddr, 
                                 m_arg_addr,
                                 this_arg))
        return;
    
    m_valid = true;    
}

ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
                                                Address &function,
                                                ValueList &args,
                                                bool stop_other_threads,
                                                bool discard_on_error) :
    ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion),
    m_valid (false),
    m_stop_other_threads (stop_other_threads),
    m_arg_addr (0),
    m_args (&args),
    m_process (thread.GetProcess()),
    m_thread (thread)
{
    
    SetOkayToDiscard (discard_on_error);
    
    Process& process = thread.GetProcess();
    Target& target = process.GetTarget();
    const ABI *abi = process.GetABI();
    
    if(!abi)
        return;
    
    lldb::addr_t spBelowRedZone = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize();
    
    SymbolContextList contexts;
    SymbolContext context;
    ModuleSP executableModuleSP (target.GetExecutableModule());
    
    if (!executableModuleSP ||
        !executableModuleSP->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
        return;
    
    contexts.GetContextAtIndex(0, context);
    
    m_start_addr = context.symbol->GetValue();
    lldb::addr_t StartLoadAddr = m_start_addr.GetLoadAddress(&target);
    
    if(!thread.SaveFrameZeroState(m_register_backup))
        return;
    
    m_function_addr = function;
    lldb::addr_t FunctionLoadAddr = m_function_addr.GetLoadAddress(&target);
    
    if (!abi->PrepareNormalCall(thread, 
                                spBelowRedZone, 
                                FunctionLoadAddr, 
                                StartLoadAddr, 
                                *m_args))
        return;
    
    m_valid = true;    
}

ThreadPlanCallFunction::~ThreadPlanCallFunction ()
{
}

void
ThreadPlanCallFunction::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
    if (level == lldb::eDescriptionLevelBrief)
    {
        s->Printf("Function call thread plan");
    }
    else
    {
        if (m_args)
            s->Printf("Thread plan to call 0x%llx with parsed arguments", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
        else
            s->Printf("Thread plan to call 0x%llx void * argument at: 0x%llx", m_function_addr.GetLoadAddress(&m_process.GetTarget()), m_arg_addr);
    }
}

bool
ThreadPlanCallFunction::ValidatePlan (Stream *error)
{
    if (!m_valid)
        return false;

    return true;
}

bool
ThreadPlanCallFunction::PlanExplainsStop ()
{
    // If the subplan is running, any crashes are attributable to us.
    
    return (m_subplan_sp.get() != NULL);
    
    if (!m_subplan_sp)
        return false;
    else
        return m_subplan_sp->PlanExplainsStop();
}

bool
ThreadPlanCallFunction::ShouldStop (Event *event_ptr)
{
    if (PlanExplainsStop())
    {
        Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP);
        
        if (log)
        {
            RegisterContext *reg_ctx = m_thread.GetRegisterContext();

            log->PutCString("Function completed.  Register state was:");

            for (uint32_t register_index = 0, num_registers = reg_ctx->GetRegisterCount();
                 register_index < num_registers;
                 ++register_index)
            {
                const char *register_name = reg_ctx->GetRegisterName(register_index);
                uint64_t register_value = reg_ctx->ReadRegisterAsUnsigned(register_index, LLDB_INVALID_ADDRESS);
                
{'fraction_non_alphanumeric': 0.13072483322089798, 'fraction_numerical': 0.0016490517952177498, 'mean_word_length': 1.9801206164842529, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 46, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6122170', 'n_tokens_mistral': 3703, 'n_tokens_neox': 3595, 'n_words': 715}