使用 Carbide.c++ 在 Symbian OS 中调试恐慌

Posted

技术标签:

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

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

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

【问题讨论】:

【参考方案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 指针。这可能会派上用场。 恐慌处理代码没有什么特别之处。我会用我的恐慌处理代码更新答案。 感谢您的更新。单独的线程技巧非常好。我认为你的解决方案在生产环境中是必不可少的,在生产环境中你要确保不会出现严重的错误。

以上是关于使用 Carbide.c++ 在 Symbian OS 中调试恐慌的主要内容,如果未能解决你的问题,请参考以下文章

安装symbian工具Syborg & QEMU

symbian 的所有 Qt ui 组件是啥?

Symbian 的共享内存示例

Symbian^3 设备上的 QtWebKit 4.7.2 问题

symbian c++ 中使用 Carbide 的 tcp 连接

Symbian 获取内容类型?