182 lines
4.4 KiB
C++
182 lines
4.4 KiB
C++
#include "signaldumper.h"
|
|
|
|
#include <QList>
|
|
#include <QMetaObject>
|
|
#include <QMetaType>
|
|
#include <QMetaMethod>
|
|
#include <QObject>
|
|
#include <QVariant>
|
|
|
|
#include <QCoreApplication>
|
|
#include <QProcess>
|
|
#include <QDebug>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
static const uint32_t IndentSpacesCount = 4;
|
|
static int iLevel = 0;
|
|
|
|
SignalDumper* SignalDumper::Dumper = nullptr;
|
|
|
|
static void signalDumperCallback(QObject* caller, int signal_index, void** argv)
|
|
{
|
|
Q_ASSERT(caller); Q_ASSERT(argv); Q_UNUSED(argv);
|
|
const QMetaObject *mo = caller->metaObject();
|
|
Q_ASSERT(mo);
|
|
QMetaMethod member = QMetaObjectPrivate::signal(mo, signal_index);
|
|
Q_ASSERT(member.isValid());
|
|
|
|
QByteArray str;
|
|
str.fill(' ', iLevel++ * IndentSpacesCount);
|
|
str += "Signal: ";
|
|
str += mo->className();
|
|
str += '(';
|
|
|
|
QString objname = caller->objectName();
|
|
str += objname.toLocal8Bit();
|
|
if (!objname.isEmpty())
|
|
str += ' ';
|
|
str += QByteArray::number(quintptr(caller), 16);
|
|
|
|
str += ") ";
|
|
str += member.name();
|
|
str += " (";
|
|
|
|
QList<QByteArray> args = member.parameterTypes();
|
|
for (int i = 0; i < args.count(); ++i) {
|
|
const QByteArray &arg = args.at(i);
|
|
int typeId = QMetaType::type(args.at(i).constData());
|
|
if (arg.endsWith('*') || arg.endsWith('&')) {
|
|
str += '(';
|
|
str += arg;
|
|
str += ')';
|
|
if (arg.endsWith('&'))
|
|
str += '@';
|
|
|
|
quintptr addr = quintptr(*reinterpret_cast<void **>(argv[i + 1]));
|
|
str.append(QByteArray::number(addr, 16));
|
|
} else if (typeId != QMetaType::UnknownType) {
|
|
Q_ASSERT(typeId != QMetaType::Void); // void parameter => metaobject is corrupt
|
|
str.append(arg)
|
|
.append('(')
|
|
.append(QVariant(typeId, argv[i + 1]).toString().toLocal8Bit())
|
|
.append(')');
|
|
}
|
|
str.append(", ");
|
|
}
|
|
if (str.endsWith(", "))
|
|
str.chop(2);
|
|
str.append(')');
|
|
|
|
SignalDumper::dumpStr(str);
|
|
}
|
|
|
|
static void signalDumperCallbackSlot(QObject* caller, int method_index, void** argv)
|
|
{
|
|
Q_ASSERT(caller); Q_ASSERT(argv); Q_UNUSED(argv);
|
|
const QMetaObject *mo = caller->metaObject();
|
|
Q_ASSERT(mo);
|
|
QMetaMethod member = mo->method(method_index);
|
|
if (!member.isValid())
|
|
return;
|
|
|
|
QByteArray str;
|
|
str.fill(' ', iLevel * IndentSpacesCount);
|
|
str += "Slot: ";
|
|
str += mo->className();
|
|
str += '(';
|
|
|
|
QString objname = caller->objectName();
|
|
str += objname.toLocal8Bit();
|
|
if (!objname.isEmpty())
|
|
str += ' ';
|
|
str += QByteArray::number(quintptr(caller), 16);
|
|
|
|
str += ") ";
|
|
str += member.methodSignature();
|
|
|
|
SignalDumper::dumpStr(str);
|
|
}
|
|
|
|
static void signalDumperCallbackEndSignal(QObject* caller, int /*signal_index*/)
|
|
{
|
|
Q_ASSERT(caller); Q_ASSERT(caller->metaObject());
|
|
--iLevel;
|
|
Q_ASSERT(iLevel >= 0);
|
|
}
|
|
|
|
void SignalDumper::dumpStr(QString str) {
|
|
if(Dumper) {
|
|
Dumper->dump(str);
|
|
}
|
|
}
|
|
|
|
SignalDumper::SignalDumper(QObject* parent) : QObject(parent) {}
|
|
|
|
SignalDumper::~SignalDumper() {
|
|
if(Dumper == this) {
|
|
endDump();
|
|
}
|
|
}
|
|
|
|
void SignalDumper::startDump()
|
|
{
|
|
if(Dumper) {
|
|
return;
|
|
}
|
|
Dumper = this;
|
|
|
|
// mkfifo
|
|
QString fifoName = "/tmp/signalLogger." + QString::number(QCoreApplication::applicationPid());
|
|
QByteArray fifoNameArr = fifoName.toLocal8Bit();
|
|
if(::mkfifo(fifoNameArr.data(), 0700)) {
|
|
qCritical() << "could not create fifo" << errno;
|
|
}
|
|
|
|
// make process
|
|
displayProc = new QProcess(this);
|
|
displayProc->start("gnome-terminal", { "--", "cat", fifoName });
|
|
|
|
if(fifo) {
|
|
fifo->deleteLater();
|
|
}
|
|
|
|
fifo = new QFile(fifoName);
|
|
fifo->open(QIODevice::WriteOnly);
|
|
|
|
iLevel = 0;
|
|
|
|
// start listening
|
|
static QSignalSpyCallbackSet set = { signalDumperCallback,
|
|
signalDumperCallbackSlot, signalDumperCallbackEndSignal, 0 };
|
|
registerCall(set);
|
|
}
|
|
|
|
void SignalDumper::endDump()
|
|
{
|
|
if(Dumper != this) {
|
|
return;
|
|
}
|
|
|
|
// stop listening
|
|
static QSignalSpyCallbackSet nset = { 0, 0, 0 ,0 };
|
|
registerCall(nset);
|
|
|
|
// kill process
|
|
displayProc->terminate();
|
|
displayProc->deleteLater();
|
|
|
|
// del fifo
|
|
fifo->remove();
|
|
|
|
Dumper = nullptr;
|
|
}
|
|
|
|
void SignalDumper::dump(QString str) {
|
|
str += '\n';
|
|
QByteArray arr = str.toLocal8Bit();
|
|
fifo->write(arr);
|
|
fifo->flush();
|
|
}
|