File indexing completed on 2024-05-05 05:51:19

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 2008-2014 Dominik Haumann <dhaumann kde org>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #include "btparser.h"
0008 
0009 #include <QDebug>
0010 #include <QRegularExpression>
0011 #include <QStringList>
0012 
0013 static QString eolDelimiter(const QString &str)
0014 {
0015     // find the split character
0016     QString separator(QLatin1Char('\n'));
0017     if (str.indexOf(QLatin1String("\r\n")) != -1) {
0018         separator = QStringLiteral("\r\n");
0019     } else if (str.indexOf(QLatin1Char('\r')) != -1) {
0020         separator = QLatin1Char('\r');
0021     }
0022     return separator;
0023 }
0024 
0025 static bool lineNoLessThan(const QString &lhs, const QString &rhs)
0026 {
0027     const QRegularExpression rx(QStringLiteral("^#(\\d+)"));
0028     QRegularExpressionMatch match = rx.match(lhs);
0029     int ilhs = match.capturedStart(0);
0030     int lhsLn = match.captured(1).toInt();
0031     match = rx.match(rhs);
0032     int irhs = match.capturedStart(0);
0033     int rhsLn = match.captured(1).toInt();
0034     if (ilhs != -1 && irhs != -1) {
0035         return lhsLn < rhsLn;
0036     } else {
0037         return lhs < rhs;
0038     }
0039 }
0040 
0041 static QStringList normalizeBt(const QStringList &l)
0042 {
0043     QStringList normalized;
0044 
0045     bool append = false;
0046 
0047     for (int i = 0; i < l.size(); ++i) {
0048         QString str = l[i].trimmed();
0049         if (str.length()) {
0050             if (str[0] == QLatin1Char('#')) {
0051                 normalized << str;
0052                 append = true;
0053             } else if (append) {
0054                 normalized.last() += QLatin1Char(' ') + str;
0055             }
0056         } else {
0057             append = false;
0058         }
0059     }
0060 
0061     std::sort(normalized.begin(), normalized.end(), lineNoLessThan);
0062 
0063     // now every single line contains a whole backtrace info
0064     return normalized;
0065 }
0066 
0067 static BtInfo parseBtLine(const QString &line)
0068 {
0069     // the syntax types we support are
0070     // a) #24 0xb688ff8e in QApplication::notify (this=0xbf997e8c, receiver=0x82607e8, e=0xbf997074) at kernel/qapplication.cpp:3115
0071     // b) #39 0xb634211c in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
0072     // c) #41 0x0805e690 in ?? ()
0073     // d) #5  0xffffe410 in __kernel_vsyscall ()
0074 
0075     // try a) cap #number(1), address(2), function(3), filename(4), linenumber(5)
0076     static const QRegularExpression rxa(QStringLiteral("^#(\\d+)\\s+(0x\\w+)\\s+in\\s+(.+)\\s+at\\s+(.+):(\\d+)$"));
0077     QRegularExpressionMatch match = rxa.match(line);
0078     if (match.hasMatch()) {
0079         BtInfo info;
0080         info.original = line;
0081         info.filename = match.captured(4);
0082         info.function = match.captured(3);
0083         info.address = match.captured(2);
0084         info.line = match.captured(5).toInt();
0085         info.step = match.captured(1).toInt();
0086         info.type = BtInfo::Source;
0087         return info;
0088     }
0089 
0090     // try b) cap #number(1), address(2), function(3), lib(4)
0091     static const QRegularExpression rxb(QStringLiteral("^#(\\d+)\\s+(0x\\w+)\\s+in\\s+(.+)\\s+from\\s+(.+)$"));
0092     match = rxb.match(line);
0093     if (match.hasMatch()) {
0094         BtInfo info;
0095         info.original = line;
0096         info.filename = match.captured(4);
0097         info.function = match.captured(3);
0098         info.address = match.captured(2);
0099         info.line = -1;
0100         info.step = match.captured(1).toInt();
0101         info.type = BtInfo::Lib;
0102         return info;
0103     }
0104 
0105     // try c) #41 0x0805e690 in ?? ()
0106     static const QRegularExpression rxc(QStringLiteral("^#(\\d+)\\s+(0x\\w+)\\s+in\\s+\\?\\?\\s+\\(\\)$"));
0107     match = rxc.match(line);
0108     if (match.hasMatch()) {
0109         BtInfo info;
0110         info.original = line;
0111         info.filename = QString();
0112         info.function = QString();
0113         info.address = match.captured(2);
0114         info.line = -1;
0115         info.step = match.captured(1).toInt();
0116         info.type = BtInfo::Unknown;
0117         return info;
0118     }
0119 
0120     // try d) #5  0xffffe410 in __kernel_vsyscall ()
0121     static const QRegularExpression rxd(QStringLiteral("^#(\\d+)\\s+(0x\\w+)\\s+in\\s+(.+)$"));
0122     match = rxd.match(line);
0123     if (match.hasMatch()) {
0124         BtInfo info;
0125         info.original = line;
0126         info.filename = QString();
0127         info.function = match.captured(3);
0128         info.address = match.captured(2);
0129         info.line = -1;
0130         info.step = match.captured(1).toInt();
0131         info.type = BtInfo::Unknown;
0132         return info;
0133     }
0134 
0135     qDebug() << "Unknown backtrace line:" << line;
0136 
0137     BtInfo info;
0138     info.type = BtInfo::Invalid;
0139     return info;
0140 }
0141 
0142 QList<BtInfo> KateBtParser::parseBacktrace(const QString &bt)
0143 {
0144     QStringList l = bt.split(eolDelimiter(bt), Qt::SkipEmptyParts);
0145 
0146     l = normalizeBt(l);
0147 
0148     QList<BtInfo> btList;
0149     for (int i = 0; i < l.size(); ++i) {
0150         BtInfo info = parseBtLine(l[i]);
0151         if (info.type != BtInfo::Invalid) {
0152             btList.append(parseBtLine(l[i]));
0153         }
0154     }
0155 
0156     return btList;
0157 }
0158 
0159 // kate: space-indent on; indent-width 4; replace-tabs on;