2

我编写了一个 C++ 应用程序(守护程序),它存在一些由于分段错误导致应用程序崩溃的问题。

要获取有关发生崩溃的代码的信息,我使用 libunwind。这在 x86_x64 linux 系统上运行良好。我得到了一个很好的堆栈跟踪。但是在 ARM 架构上,堆栈跟踪仅包含堆栈到“守护程序代码”本身,而不是我使用的共享库

我正在使用 gcc 4.9(用于 arm arm-linux-gnueabihf-g++4.9)我正在使用以下参数在调试模式(-g)下构建库和守护程序以获取堆栈跟踪表

-funwind-tables -fasynchronous-unwind-tables -mapcs-frame -g

对于我用于共享库的链接器

-shared -pthread -static-libgcc -static-libstdc++ -rdynamic

这是 x86 的示例堆栈跟踪

1  0x0000000000403f68 sp=0x00007f0c2be8d630 crit_err_hdlr(int, siginfo_t*, void*) + 0x28
2  0x00007f0c2dfa33d0 sp=0x00007f0c2be8d680 __restore_rt + 0x0
3  0x00007f0c2dfa32a9 sp=0x00007f0c2be8dc18 raise + 0x29
4  0x00007f0c2e958bab sp=0x00007f0c2be8dc20 Raumserver::Request::RequestAction_Crash::crashLevel4() + 0x2b
5  0x00007f0c2e958d9c sp=0x00007f0c2be8dc60 Raumserver::Request::RequestAction_Crash::executeAction() + 0x12c
6  0x00007f0c2e96f045 sp=0x00007f0c2be8dce0 Raumserver::Request::RequestAction::execute() + 0x55
7  0x00007f0c2e940c83 sp=0x00007f0c2be8de00 Raumserver::Manager::RequestActionManager::requestProcessingWorkerThread()
+ 0x113
8  0x00007f0c2ee86380 sp=0x00007f0c2be8df00 execute_native_thread_routine + 0x20
9  0x00007f0c2df996fa sp=0x00007f0c2be8df20 start_thread + 0xca
10 0x00007f0c2dccfb5d sp=0x00007f0c2be8dfc0 clone + 0x6d
11 0x0000000000000000 sp=0x00007f0c2be8dfc8  + 0x6d

这里是来自手臂设备的痕迹。共享库的堆栈信息似乎不存在?!

1  0x0000000000013403 sp=0x00000000b49fe930 crit_err_hdlr(int, siginfo_t*, void*) + 0x1a
2  0x00000000b6a3b6a0 sp=0x00000000b49fe960 __default_rt_sa_restorer_v2 + 0x0
3  0x00000000b6b5774c sp=0x00000000b49fecd4 raise + 0x24

以下是用于构建从信号处理程序调用的堆栈跟踪的代码摘要:

#ifdef __arm__
  #include <libunwind.h>
  #include <libunwind-arm.h>
#else
  #include <libunwind.h>
  #include <libunwind-x86_64.h>
#endif

...

void backtrace()
{
  unw_cursor_t cursor;
  unw_context_t context;
  unw_getcontext(&context);
  unw_init_local(&cursor, &context);

  int n=0;
  int err = unw_step(&cursor);
  while ( err ) 
  {
    unw_word_t ip, sp, off;

    unw_get_reg(&cursor, UNW_REG_IP, &ip);
    unw_get_reg(&cursor, UNW_REG_SP, &sp);

    char symbol[256] = {"<unknown>"};
    char buffer[256];
    char *name = symbol;

    if ( !unw_get_proc_name(&cursor, symbol, sizeof(symbol), &off) ) 
    {
      int status;
      if ( (name = abi::__cxa_demangle(symbol, NULL, NULL, &status)) == 0 )
        name = symbol;
    }

    sprintf(buffer, "#%-2d 0x%016" PRIxPTR " sp=0x%016" PRIxPTR " %s + 0x%" PRIxPTR "\n",
        ++n,
        static_cast<uintptr_t>(ip),
        static_cast<uintptr_t>(sp),
        name,
        static_cast<uintptr_t>(off));

    if ( name != symbol )
        free(name);

    ...

    err = unw_step(&cursor);
  }
}

这里是守护进程本身的摘要:

int main(int argc, char *argv[])
{
    Raumserver::Raumserver  raumserverObject;

    //Set our Logging Mask and open the Log
    setlogmask(LOG_UPTO(LOG_NOTICE));
    openlog(DAEMON_NAME, LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);

    pid_t pid, sid;

    //Fork the Parent Process
    pid = fork();
    if (pid < 0) {  syslog (LOG_NOTICE, "Error forking the parent process"); exit(EXIT_FAILURE); }
    //We got a good pid, Close the Parent Process
    if (pid > 0) {  syslog (LOG_NOTICE, "Got pid, closing parent process"); exit(EXIT_SUCCESS); }

    //Change File Mask
    umask(0);

    //Create a new Signature Id for our child
    sid = setsid();
    if (sid < 0) {  syslog (LOG_NOTICE, "Signature ID for child process could not be created!"); exit(EXIT_FAILURE); }
    // get the working directory of the executable
    std::string workingDirectory = getWorkingDirectory();

    //Change Directory
    //If we cant find the directory we exit with failure.
    if ((chdir("/")) < 0) { exit(EXIT_FAILURE); }

    //Close Standard File Descriptors
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);

    // Add some system signal handlers for crash reporting
    //raumserverObject.addSystemSignalHandlers();
    AddSignalHandlers();

    // set the log adapters we want to use (because we do not want to use the standard ones which includes console output)
    std::vector<std::shared_ptr<Raumkernel::Log::LogAdapter>> adapters;
    auto logAdapterFile = std::shared_ptr<Raumkernel::Log::LogAdapter_File>(new Raumkernel::Log::LogAdapter_File());
    logAdapterFile->setLogFilePath(workingDirectory + "logs/");
    adapters.push_back(logAdapterFile);

    // create raumserver object and do init 
    raumserverObject.setSettingsFile(workingDirectory + "settings.xml");
    raumserverObject.initLogObject(Raumkernel::Log::LogType::LOGTYPE_ERROR, workingDirectory + "logs/", adapters);
    raumserverObject.init();

    // go into an endless loop and wait until daemon is killed by the syste,
    while(true)
    {
        sleep(60);    //Sleep for 60 seconds
    }

    //Close the log
    closelog ();
}

如果我错过了一些编译器标志,有人知道吗?有什么遗漏吗?我发现了很多帖子,并且都提到了提到的编译器标志或 libunwind。我已经尝试了我发现的其他几个代码,但它们只给了我 1 的堆栈深度谢谢!

编辑 11.11.2016:
为了测试,我构建了静态库而不是共享库并将它们添加到应用程序中,因此不再有动态链接。不幸的是,堆栈跟踪是同样糟糕的。

我什至尝试用拇指模式编译整个东西,并将 arm 编译器更改为 gcc5/g++5

-mthumb -mtpcs-frame -mtpcs-leaf-frame

同样的问题:-(

4

0 回答 0