[Debugger] Determine a breakpoint line is valid

Started by
8 comments, last by WitchLord 7 years, 1 month ago

Hi guys,

I would like to know if a breakpoint set on certain line is valid before it actually being hit.

I'm currently do some debugging implementation. e.g. user set the breakpoints and after launching the script, some of the invalid breakpoints shown as invalid in the GUI (i.e. they are not inside of any functions).

I have studied the official debugger add-on and it has CheckBreakPoint function which checks the breakpoints when the code runs to the line, however, I really want to know if this line is valid or should be moved to some near line BEFORE it gets hit.

Do you have any ideas?

Cheers!

Advertisement

To do that you can enumerate all the functions and class methods in the module and look for the one that contains the wanted break point and then, just as the CDebugger add-on does, use FindNextLineWithCode to find the valid line for the breakpoint.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Is FindNextLineWithCode of a function still avaible even the code is not running inside this function?

Yes, it can be used even when the VM is not running.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thank you Andreas! I will have a try! :D

Hi Andreas,

I've tried the approach, and it works well for functions.

However, it's not working for ObjectType methods or global variables.

(e.g. Test::method() or string g_str = getDefaultString(); of script.as from asrun sample)

If there is answer, please let me know.

Thank you very much! :ph34r:

For global variables there is currently no interface for obtaining the position where the variable has been declared. I'll see if I can add this for the upcoming release (2.32.0). If you don't want to wait until I can provide code changes, you ought to be able to do it yourself with a bit of customization of the library (look for the class asCGlobalProperty and then in the member initFunc (type asCScriptFunction) you'll find the declaredAt and scriptSectionIdx that hold the location where the code was declared)

As for class methods it should be working already. You'll need to enumerate the types to find each of the declared classes, and then for each of the classes you enumerate the methods and factories.

If you're still having trouble, please show me what you've done and the error you're getting so I can investigate it in more detail.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Hi Andreas,

It's encouraging to see your reply.

I'm tring the member methods and factories but they failed.

I put my test code into the function body of


void CDebugger::LineCallback(asIScriptContext *ctx)

since I don't know if the running context is dependent.

You can test line 38 of script.as, this is the method() function of class Test. In this test, the FindNextLineWithCode function will always fail due to the condition failure


scriptData == 0

in FindNextLineWithCode function.

Here is my testing code


    int currentLine = ctx->GetLineNumber(0, 0, &file);
    if (currentLine == 38)
    {
        int i = 0; // put a breakpoint here test, line 38 is "void Test::method()"
    }

    std::cout << "current line: " << currentLine << std::endl;

    asIScriptModule* module = engine_->GetModule("script");
    if (!module)
        return;

    // all functions from the object types
    std::vector<asIScriptFunction*> allFunctions;

    // for each object type
    for (size_t i = 0, objectTypeCount = module->GetObjectTypeCount(); i < objectTypeCount; ++i)
    {
        asITypeInfo* objectType = module->GetObjectTypeByIndex(i);
        assert(objectType);
        if (!objectType)
            continue;

        // member methods
        for (size_t j = 0, methodCount = objectType->GetMethodCount(); j < methodCount; ++j)
        {
            asIScriptFunction* func = objectType->GetMethodByIndex(j);
            assert(func);
            if (func)
            {
                std::cout << objectType->GetName() << "::" << func->GetName() << std::endl;
                allFunctions.push_back(func);
            }
        }

        // factories
        for (size_t j = 0, factoryCount = objectType->GetFactoryCount(); j < factoryCount; ++j)
        {
            asIScriptFunction* func = objectType->GetFactoryByIndex(j);
            if (func)
            {
                std::cout << objectType->GetName() << "::" << func->GetName() << std::endl;
                allFunctions.push_back(func);
            }
        }
    }

    // check every functions
    for (size_t i = 0; i < allFunctions.size(); ++i)
    {
        asIScriptFunction* func = allFunctions[i];
        assert(func);

        std::cout << func->GetName();
        
        static int lineNum = 38;
        int actualLine = func->FindNextLineWithCode(lineNum);

        std::cout << ", line=" << actualLine << std::endl;  // *** in my test, actualLine is always -1 ***
    }

Cheers!

For global variables there is currently no interface for obtaining the position where the variable has been declared. I'll see if I can add this for the upcoming release (2.32.0). If you don't want to wait until I can provide code changes, you ought to be able to do it yourself with a bit of customization of the library (look for the class asCGlobalProperty and then in the member initFunc (type asCScriptFunction) you'll find the declaredAt and scriptSectionIdx that hold the location where the code was declared)

I had a quick test for the way you suggested, it works!

Please have a look at class methods and factories and my testing code as my previous reply.

As for class methods it should be working already. You'll need to enumerate the types to find each of the declared classes, and then for each of the classes you enumerate the methods and factories.

Thank you very much!

For GetMethodByIndex you need to tell angelscript that you want the non-virtual function so you get the actual implementation: "GetMethodByIndex(j, false)"

The factory will be a bit trickier, just as for global variables there is currently no interface available to do what you want. The function that you get with GetFactory is a stub function that allocate the memory for the object and then internally calls the real constructor that performs the actual initialization. You need to get to the actual constructor so you can check the valid lines for breakpoints.

I can think of two possible ways at the moment:

1. find the matching constructor in the asCObjectType::beh::constructors array. The index for the constructor in the array will be the same index where the factory is stored in asCObjectType::beh::factories array.

2. use the JIT interface to enumerate the bytecode for the factory until you find the asBC_ALLOC instruction that will hold the function id of the constructor.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This topic is closed to new replies.

Advertisement