【问题标题】:Debugging panics in Symbian OS using Carbide.c++使用 Carbide.c++ 在 Symbian OS 中调试恐慌
【发布时间】:2010-08-26 13:13:17
【问题描述】:

任何恐慌发生时,有没有办法进入调试器,就像有断点一样?

我正在使用 Carbide.c++ 2.3.0。我知道 Debug Configurations > x86 Exceptions,但它只涵盖了实际应用程序中实际发生的一小部分。例如,当应用程序因内存泄漏而退出时,它不会捕获用户恐慌或 ALLOC 恐慌。

【问题讨论】:

    标签: debugging symbian carbide panic


    【解决方案1】:

    如果您使用的是模拟器,您可以通过启用“即时调试”来调试恐慌。这是通过将以下行添加到epoc32\data\epoc.ini 来完成的:

    JustInTime debug
    

    更多详情,请参阅epoc.ini reference in the SDK documentation

    【讨论】:

    • 太棒了,它真的有效!我一直想知道 Symbian 工具和文档有多么晦涩难懂。确定恐慌发生在哪里是一项至关重要的任务,但没有人知道如何去做!即使现在当你指给我看文档时,也没有迹象表明 JustInTime 选项与恐慌陷阱有关。非常感谢!
    • @SnakE:是的,那个 epoc.ini 关键字的文档不是很清楚。那些实际上被JustInTime debugUser::SetJustInTime(TBool)调用的用户库函数要好一些。
    【解决方案2】:

    据我所知,这是不可能的。

    我所做的是使用简单的函数跟踪逻辑,因此当发生恐慌时,我的恐慌处理代码(我注销)中的恐慌点有一个堆栈跟踪。这很好用,只是您必须记住在每个函数的开头添加宏。

    例如

    #ifndef NDEBUG
    class __FTrace
    {
        __FTrace(const char* function)
        {
            TraceManager::GetInstance().EnterFunction(function);
        }
        ~__FTrace()
        {
            TraceManager::GetInstance().LeaveFunction(function);
        }
    };    
    
    #define FTRACE() __FTrace(__PRETTY_FUNCTION__)
    #else
    #define FTRACE()
    #endif
    
    void Func()
    {
        FTRACE();
        ...
    }
    

    对于ALLOC,我在模拟器下使用Hook Logger 取得了很大的成功。设置和使用确实很痛苦,但它会让追踪 ALLOC 内存泄漏变得非常容易。

    更新:根据要求,这是我的恐慌处理代码的样子。请注意,我的应用程序必须一直在后台运行,因此设置为在发生不良情况时重新启动应用程序。此代码也适用于第 3 版 SDK,我还没有在更高版本的 SDK 上尝试过。

    关键是在另一个线程中运行主应用程序,然后等待它退出。然后检查线程退出的原因,线程由于未知原因退出,记录我自己的堆栈跟踪等内容并重新启动应用程序。

    TInt StartMainThread(TAny*)
        {
        FTRACE();
        __LOGSTR_TOFILE("Main Thread Start");
        TInt result(KErrNone);
    
        TRAPD(err, result = EikStart::RunApplication(NewApplication));
    
        if(KErrNone != err || KErrNone != result )
            {
            __LOGSTR_TOFILE("EikStart::RunApplication error: trap(%d), %d", err, result);
            }
    
        __LOGSTR_TOFILE("Main Thread End");
        return result;
        }
    
    const TInt KMainThreadToLiveInSeconds = 10;
    
    } // namespace *unnamed*
    
    LOCAL_C CApaApplication* NewApplication()
        {
        FTRACE();
        return new CMainApplication;
        }
    
    
    GLDEF_C TInt E32Main()
        {
    #ifdef NDEBUG
        __LOGSTR_TOFILE("Application Start (release)");
    #else   
        __LOGSTR_TOFILE("Application Start (debug)");
    #endif  
    
    #ifndef NO_TRACING
        __TraceManager::NewL();
    #endif // !NO_TRACING
    
        RHeap& heap(User::Heap());
        TInt heapsize=heap.MaxLength();
    
        TInt exitReason(KErrNone);
    
        TTime timeToLive;
        timeToLive.UniversalTime();
        timeToLive += TTimeIntervalSeconds(KMainThreadToLiveInSeconds);
    
        LManagedHandle<RThread> mainThread;
        TInt err = mainThread->Create(_L("Main Thread"), StartMainThread, KDefaultStackSize, KMinHeapSize, heapsize, NULL);
        if (KErrNone != err) 
            {
            __LOGSTR_TOFILE("MainThread failed : %d", err);
            return err;
            }
    
        mainThread->SetPriority(EPriorityNormal);
        TRequestStatus status; 
        mainThread->Logon(status);
    
        mainThread->Resume();
    
        User::WaitForRequest(status);
    
        exitReason = mainThread->ExitReason();
    TExitCategoryName category(mainThread->ExitCategory());
    
    switch(mainThread->ExitType())
        {
        case EExitKill:
            __LOGSTR_TOFILE("ExitKill : (%S) : %d", &category, exitReason);
            break;
    
        case EExitTerminate:
            __LOGSTR_TOFILE("ExitTerminate : (%S) : %d", &category, exitReason);
            break;
    
        case EExitPanic:
            __LOGSTR_TOFILE("ExitPanic : (%S) : %d", &category, exitReason);
            break;
    
        default:
            __LOGSTR_TOFILE("ExitUnknown : (%S) : %d", &category, exitReason);
            break;
        }
    
    #ifndef NO_TRACING
        __TraceManager::GetInstance().LogStackTrace();
    #endif // NO_TRACING
    
    
        if( KErrNone != status.Int() )
            {
            TTime now;
            now.UniversalTime();
    
            if (timeToLive > now)
                {
                TTimeIntervalMicroSeconds diff = timeToLive.MicroSecondsFrom(now);
                __LOGSTR_TOFILE("Exiting due to TTL : (%Lu)", diff.Int64());
                }
            else
                {
                RProcess current;
                RProcess restart;
                err = restart.Create(current.FileName(), _L(""));
                if( KErrNone == err )
                    {
                    __LOGSTR_TOFILE("Restarting...");
                    restart.Resume();
                    return KErrNone;
                    }
                else
                    {
                    __LOGSTR_TOFILE("Failed to start app: %d", err);
                    }
                }
            }
    
        __LOGSTR_TOFILE("Application End");
        return exitReason;
        }
    

    【讨论】:

    • 这里最有趣的部分是您似乎忽略的“紧急处理代码”。 ;) 那就是当你的代码发生任何恐慌时它真的可以做一些有用的事情。并感谢 Hook Logger 指针。这可能会派上用场。
    • 恐慌处理代码没有什么特别之处。我会用我的恐慌处理代码更新答案。
    • 感谢您的更新。单独的线程技巧非常好。我认为你的解决方案在生产环境中是必不可少的,在生产环境中你要确保不会出现严重的错误。
    猜你喜欢
    • 2020-01-28
    • 2018-10-01
    • 1970-01-01
    • 2021-08-28
    • 1970-01-01
    • 1970-01-01
    • 2015-10-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多