我编写了一个 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
同样的问题:-(