6#include <QLoggingCategory> 
    9#ifdef HAVE_RABBITCOMMON_GUI 
   12#include <QDesktopServices> 
   14#include <QApplication> 
   22#include "StackWalker.h" 
   24#include "CoreDump/MiniDumper.h" 
   25#elif defined(Q_OS_ANDROID) 
   34#include "RabbitCommonTools.h" 
   36#include "StackTrace.h" 
   40const char* g_PattenFileLine = 
"%p [%s] in %s:%lu";
 
   41const char* g_PattenDLL = 
"%p [%s] in %s";
 
   43static Q_LOGGING_CATEGORY(log, 
"RabbitCommon.StackTrace")
 
   45CCallTrace::CCallTrace(QObject *parent)
 
   47    , m_hMainThread(QThread::currentThreadId())
 
   50#ifdef HAVE_RABBITCOMMON_GUI 
   51void CCallTrace::ShowCoreDialog(QString szTitle, QString szContent, QString szDetail, QString szCoreDumpFile)
 
   53    if(QThread::currentThreadId() == m_hMainThread) {
 
   54        qDebug(log) << 
"Main thread:" << m_hMainThread << 
"core";
 
   55        return slotShowCoreDialog(szTitle, szContent, szDetail, szCoreDumpFile);
 
   57    qDebug(log) << 
"Thread:" << QThread::currentThreadId() << 
"core." 
   58                << 
"main thread:" << m_hMainThread;
 
   60    check = connect(
this, SIGNAL(sigShowCoreDialog(QString,QString,QString,QString)),
 
   61                    this, SLOT(slotShowCoreDialog(QString,QString,QString,QString)),
 
   62                    Qt::BlockingQueuedConnection);
 
   64    emit sigShowCoreDialog(szTitle, szContent, szDetail, szCoreDumpFile);
 
   67void CCallTrace::slotShowCoreDialog(QString szTitle, QString szContent,
 
   68                                QString szDetail, QString szCoreDumpFile)
 
   70    qDebug(log) << 
"CCallTrace::slotShowCoreDialog";
 
   71    QMessageBox msg(QMessageBox::Icon::Critical, szTitle, szContent, QMessageBox::StandardButton::Close);
 
   72    QPushButton* pOpenLogFile = msg.addButton(QObject::tr(
"Open log file"), QMessageBox::ActionRole);
 
   73    QPushButton* pOpenCoreDumpFolder = msg.addButton(QObject::tr(
"Open core dump folder"), QMessageBox::ActionRole);
 
   74#ifndef QT_NO_CLIPBOARD 
   75    QPushButton* pCopyClipboard = msg.addButton(tr(
"Copy to clipboard"), QMessageBox::ActionRole);
 
   77    if(!szDetail.isEmpty())
 
   78        msg.setDetailedText(szDetail);
 
   80    if(msg.clickedButton() == pOpenLogFile)
 
   83    } 
else if (msg.clickedButton() == pOpenCoreDumpFolder) {
 
   84        QFileInfo info(szCoreDumpFile);
 
   85        QDesktopServices::openUrl(QUrl::fromLocalFile(info.absolutePath()));
 
   86#ifndef QT_NO_CLIPBOARD 
   87    } 
else if(msg.clickedButton() == pCopyClipboard) {
 
   88        QClipboard* cb = QGuiApplication::clipboard();
 
   90            qCritical(log) << 
"The application has not clipboard";
 
   93        QMimeData* m = 
new QMimeData();
 
   95            qCritical(log) << 
"new QMimeData fail";
 
   99        lstUrl << CLog::Instance()->GetLogFile() << szCoreDumpFile;
 
  102        qDebug(log) << 
"Clipboard urls" << cb->mimeData()->urls();
 
  105    qDebug(log) << 
"CCallTrace::slotShowCoreDialog end";
 
  109QString CCallTrace::GetStack(uint index)
 
  111    QString szMsg(
"Stack:\n");
 
  112    QStringList szTrace = GetStack(index, 63);
 
  113    for(
int i = 0; i < szTrace.length(); i++) {
 
  114        szMsg += 
"    " + QString::number(i + 1) + 
" " + szTrace[i] + 
"\n";
 
  122#define TRACE_MAX_STACK_FRAMES 62 
  123QStringList CCallTrace::GetStack(uint index, 
unsigned int max_frames)
 
  126    const int nLen = 1024;
 
  127    void *stack[TRACE_MAX_STACK_FRAMES];
 
  128    HANDLE process = GetCurrentProcess();
 
  129    SymInitialize(process, NULL, TRUE);
 
  130    WORD numberOfFrames = CaptureStackBackTrace(index, TRACE_MAX_STACK_FRAMES, stack, NULL);
 
  131    char buf[
sizeof(SYMBOL_INFO) + (nLen - 1) * 
sizeof(TCHAR)];
 
  132    SYMBOL_INFO* symbol = (SYMBOL_INFO*)buf;
 
  133    symbol->MaxNameLen = nLen;
 
  134    symbol->SizeOfStruct = 
sizeof(SYMBOL_INFO);
 
  136    IMAGEHLP_LINE64 line;
 
  137    line.SizeOfStruct = 
sizeof(IMAGEHLP_LINE64);
 
  139    QScopedArrayPointer<char> bufStack(
new char[nLen]);
 
  142        qCritical(log) << 
"new buffer fail";
 
  145    for (
int i = 0; i < numberOfFrames; i++)
 
  147        DWORD64 address = (DWORD64)(stack[i]);
 
  148        SymFromAddr(process, address, NULL, symbol);
 
  149        if (SymGetLineFromAddr64(process, address, &displacement, &line))
 
  151            snprintf(bufStack.data(), nLen, g_PattenFileLine,
 
  152                     (LPVOID)symbol->Address, symbol->Name, line.FileName, line.LineNumber);
 
  157            const int MaxNameLen = 256;
 
  158            QScopedArrayPointer<char> module(
new char[MaxNameLen]);
 
  159            HMODULE hModule = NULL;
 
  160            lstrcpyA(module.data(), 
"");
 
  161            GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
 
  162                                 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
 
  163                              (LPCTSTR) address, &hModule);
 
  167                GetModuleFileNameA(hModule, module.data(), MaxNameLen);
 
  169            snprintf(bufStack.data(), nLen, g_PattenDLL,
 
  170                     (LPVOID)symbol->Address, symbol->Name, module.data());
 
  172        szStack << bufStack.data();
 
  180static void MyStrCpy(
char* szDest, 
size_t nMaxDestSize, 
const char* szSrc)
 
  182    if (nMaxDestSize <= 0)
 
  184    strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE);
 
  187    szDest[nMaxDestSize - 1] = 0;
 
  189class MyStackWalker : 
public StackWalker
 
  192    MyStackWalker(QStringList *lstText,
 
  194                  int options = OptionsAll, 
 
  195                  LPCSTR szSymPath = NULL,
 
  196                  DWORD  dwProcessId = GetCurrentProcessId(),
 
  197                  HANDLE hProcess = GetCurrentProcess())
 
  198        : StackWalker(options, szSymPath, dwProcessId, hProcess)
 
  203    QStringList *m_lstText;
 
  207    virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry) 
override;
 
  208    virtual void OnOutput(LPCSTR szText)
 override 
  212void MyStackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
 
  219    CHAR   buffer[STACKWALK_MAX_NAMELEN];
 
  220    size_t maxLen = STACKWALK_MAX_NAMELEN;
 
  224    if ((eType != lastEntry) && (entry.offset != 0))
 
  226        if (entry.name[0] == 0)
 
  227            MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, 
"(function-name not available)");
 
  228        if (entry.undName[0] != 0)
 
  229            MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName);
 
  230        if (entry.undFullName[0] != 0)
 
  231            MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName);
 
  232        if (entry.moduleName[0] == 0)
 
  233            MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, 
"(module-name not available)");
 
  234        if (entry.lineFileName[0] == 0)
 
  236            MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, 
"(filename not available)");
 
  238        _snprintf_s(buffer, maxLen, 
"%s in [%s] (%s:%d) address: %p",
 
  239                    entry.name, entry.moduleName,
 
  240                    entry.lineFileName, entry.lineNumber,
 
  241                    (LPVOID)entry.offset);
 
  242        buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
 
  243        *m_lstText << buffer;
 
  247QStringList PrintStackTrace1(uint index, 
unsigned int max_frames)
 
  249    QStringList lstStack;
 
  250    MyStackWalker sw(&lstStack, index, StackWalker::RetrieveSymbol);
 
  256#elif defined(Q_OS_ANDROID) 
  259static _Unwind_Reason_Code unwindCallback(
struct _Unwind_Context* context, 
void* arg)
 
  261    std::vector<_Unwind_Word> &stack = *(std::vector<_Unwind_Word>*)arg;
 
  262    stack.push_back(_Unwind_GetIP(context));
 
  263    return _URC_NO_REASON;
 
  266QStringList CCallTrace::GetStack(uint index, 
unsigned int max_frames)
 
  268    QStringList lstStack;
 
  270    std::vector<_Unwind_Word> stack;
 
  271    _Unwind_Backtrace(unwindCallback, (
void*)&stack);
 
  273    int nBufferSize = 1024;
 
  274    QScopedArrayPointer<char> buffer(
new char[nBufferSize]);
 
  277        qCritical(log) << 
"new buffer fail";
 
  280    for (
int i = index; i < stack.size(); i++) {
 
  282        if (!dladdr((
void*)stack[i], &info)) {
 
  285        int addr = (
char*)stack[i] - (
char*)info.dli_fbase - 1;
 
  286        if (info.dli_sname == NULL || strlen(info.dli_sname) == 0) {
 
  287            sprintf(buffer.data(), 
"%p [%s]", addr, info.dli_fname);
 
  289            sprintf(buffer.data(), 
"%p [%s] in %s",
 
  290                    addr, info.dli_sname, info.dli_fname);
 
  292        lstStack << buffer.data();
 
  301QStringList CCallTrace::GetStack(uint index, 
unsigned int max_frames)
 
  305    int nBufferSize = 1024;
 
  306    QScopedArrayPointer<char> buffer(
new char[nBufferSize]);
 
  309        qCritical(log) << 
"new buffer fail";
 
  314    void* addrlist[max_frames + 1];
 
  317    int addrlen = backtrace(addrlist, 
sizeof(addrlist) / 
sizeof(
void*));
 
  319        qCritical(log) << 
"Get backtrace is empty, possibly corrupt";
 
  332    char** symbollist = backtrace_symbols(addrlist, addrlen);
 
  335    size_t funcnamesize = 256;
 
  336    char* funcname = (
char*)malloc(funcnamesize);
 
  340    for (
int i = index; i < addrlen; i++)
 
  342        char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
 
  346        for (
char *p = symbollist[i]; *p; ++p)
 
  352            else if (*p == 
')' && begin_offset) {
 
  358        if (begin_name && begin_offset && end_offset
 
  359            && begin_name < begin_offset)
 
  361            *begin_name++ = 
'\0';
 
  362            *begin_offset++ = 
'\0';
 
  370            char* ret = abi::__cxa_demangle(begin_name,
 
  371                                            funcname, &funcnamesize, &status);
 
  375                snprintf(buffer.data(), nBufferSize, 
"%p [%s] in %s",
 
  376                          begin_offset, funcname, symbollist[i]);
 
  380                snprintf(buffer.data(), nBufferSize, 
"%p [%s] in %s",
 
  381                         begin_offset, begin_name, symbollist[i]);
 
  387            snprintf(buffer.data(), nBufferSize, 
"%s", symbollist[i]);
 
  389        szMsg << buffer.data();