static ProbeABI abiFromMachO(const uchar* data, qint64 size)
{
  ProbeABI abi;
  const quint32 magic = *reinterpret_cast<const quint32*>(data);

  quint32 offset = 0;
  qint32 ncmds = 0;
  qint32 cmdsize = 0;

  switch (magic) {
    case MH_MAGIC:
      abi.setArchitecture(readMachOHeader<mach_header>(data, size, offset, ncmds, cmdsize));
      break;
    case MH_MAGIC_64:
      abi.setArchitecture(readMachOHeader<mach_header_64>(data, size, offset, ncmds, cmdsize));
      break;
  }

  if (offset >= size || ncmds <= 0 || cmdsize <= 0 || size <= offset + cmdsize)
    return ProbeABI();

  // read load commands
  for (int i = 0; i < ncmds; ++i) {
    const load_command* cmd = reinterpret_cast<const load_command*>(data + offset);
    if (cmd->cmd == LC_ID_DYLIB) {
      const dylib_command* dlcmd = reinterpret_cast<const dylib_command*>(data + offset);
      const int majorVersion = (dlcmd->dylib.current_version & 0x00ff0000) >> 16;
      const int minorVersion = (dlcmd->dylib.current_version & 0x0000ff00) >> 8;
      abi.setQtVersion(majorVersion, minorVersion);
    }
    offset += cmd->cmdsize;
  }

  return abi;
}
 void testDetectProcess()
 {
   ProbeABIDetector detector;
   QVERIFY(!detector.qtCoreForProcess(QCoreApplication::applicationPid()).isEmpty());
   const ProbeABI abi = detector.abiForProcess(QCoreApplication::applicationPid());
   QCOMPARE(abi.id(), QStringLiteral(GAMMARAY_PROBE_ABI));
 }
Beispiel #3
0
    void testDisplayString()
    {
        QFETCH(QString, id);
        QFETCH(QString, display);

        const ProbeABI abi = ProbeABI::fromString(id);
        QCOMPARE(abi.displayString(), display);
    }
Beispiel #4
0
bool ProbeABI::operator==(const ProbeABI& rhs) const
{
  return majorQtVersion() == rhs.majorQtVersion()
    && minorQtVersion() == rhs.minorQtVersion()
    && architecture() == rhs.architecture()
    && compiler() == rhs.compiler()
    && isDebug() == rhs.isDebug();
}
Beispiel #5
0
    void testFromString()
    {
        QFETCH(QString, id);
        QFETCH(bool, valid);
        QFETCH(int, majorVersion);
        QFETCH(int, minorVersion);
        QFETCH(bool, isDebug);
        QFETCH(QString, arch);
        QFETCH(QString, compiler);
#ifdef Q_OS_WIN
        QFETCH(QString, compilerVersion);
#endif
        const ProbeABI abi = ProbeABI::fromString(id);
        QCOMPARE(abi.isValid(), valid);
        if (!valid)
            return;

        QCOMPARE(abi.majorQtVersion(), majorVersion);
        QCOMPARE(abi.minorQtVersion(), minorVersion);
        QCOMPARE(abi.architecture(), arch);
        if (abi.isDebugRelevant()) {
            QCOMPARE(abi.isDebug(), isDebug);
        }
#ifdef Q_OS_WIN
        QCOMPARE(abi.compiler(), compiler);
        QCOMPARE(abi.compilerVersion(), compilerVersion);
#else
        Q_UNUSED(compiler);
#endif
    }
static ProbeABI qtVersionFromFileName(const QString &path)
{
    ProbeABI abi;

    const QStringList parts = path.split('.');
    if (parts.size() < 4 || parts.at(parts.size() - 4) != QLatin1String("so"))
        return abi;

    abi.setQtVersion(parts.at(parts.size() - 3).toInt(), parts.at(parts.size() - 2).toInt());
    return abi;
}
Beispiel #7
0
bool ProbeABI::isCompatible(const ProbeABI& referenceABI) const
{
  return d->majorQtVersion == referenceABI.majorQtVersion()
      && d->minorQtVersion >= referenceABI.minorQtVersion() // we can work with older probes, since the target defines the Qt libraries being used
      && d->architecture == referenceABI.architecture()
#ifdef Q_OS_WIN
      && d->compiler == referenceABI.compiler()
#endif
      && (isDebugRelevant() ?  d->isDebug == referenceABI.isDebug() : true)
      ;
}
AbstractInjector::Ptr defaultInjectorForLaunch(const ProbeABI &abi)
{
#if defined(Q_OS_MAC)
  if (abi.majorQtVersion() >= 5 && abi.minorQtVersion() >= 4)
    return createInjector(QLatin1String("preload"));
  return findFirstWorkingInjector(QStringList() << QLatin1String("lldb") << QLatin1String("gdb"));
#elif defined(Q_OS_UNIX)
  Q_UNUSED(abi);
  return createInjector(QLatin1String("preload"));
#else
  Q_UNUSED(abi);
  return createInjector(QLatin1String("windll"));
#endif
}
ProbeABI ProbeABIDetector::detectAbiForQtCore(const QString &path) const
{
    if (path.isEmpty())
        return ProbeABI();

    // try to find the version
    ProbeABI abi = qtVersionFromFileName(path);
    if (!abi.hasQtVersion())
        abi = qtVersionFromExec(path);

    // TODO: architecture detection fallback without elf.h?
    const QString arch = archFromELF(path);
    abi.setArchitecture(arch);

    return abi;
}
Beispiel #10
0
int ProbeABIModel::indexOfBestMatchingABI(const ProbeABI& targetABI) const
{
  if (!targetABI.isValid())
    return -1;

  const ProbeABI bestMatchingABI = ProbeFinder::findBestMatchingABI(targetABI, m_abis);
  return m_abis.indexOf(bestMatchingABI);
}
Beispiel #11
0
    void testProbeABICompat()
    {
#ifndef Q_OS_WIN
        const ProbeABI targetABI = ProbeABI::fromString(QStringLiteral("qt5_2-x86_64"));
        const ProbeABI probeABI = ProbeABI::fromString(QStringLiteral("qt5_1-x86_64"));
#if defined(Q_OS_MAC)
        const bool debugAbiMatters = true;
#else
        const bool debugAbiMatters = false;
#endif
        const bool compilerAbiMatters = false;
#else
        const ProbeABI targetABI = ProbeABI::fromString(QStringLiteral("qt5_2-MSVC-140-x86_64"));
        const ProbeABI probeABI = ProbeABI::fromString(QStringLiteral("qt5_1-MSVC-140-x86_64"));
        const bool debugAbiMatters = true;
        const bool compilerAbiMatters = true;
#endif

        // full match, or same major version and older probe
        QVERIFY(targetABI.isCompatible(targetABI));
        QVERIFY(targetABI.isCompatible(probeABI));

        // incompatible
        // newer minor version probe
        QVERIFY(!probeABI.isCompatible(targetABI));

        // different major version
        ProbeABI incompatABI(probeABI);
        incompatABI.setQtVersion(4, 8);
        QVERIFY(!targetABI.isCompatible(incompatABI));
        QVERIFY(!incompatABI.isCompatible(targetABI));

        // different architecture
        incompatABI = targetABI;
        incompatABI.setArchitecture(QStringLiteral("i686"));
        QVERIFY(!targetABI.isCompatible(incompatABI));

        // different debug/release mode
        incompatABI = targetABI;
        incompatABI.setIsDebug(true);
        QCOMPARE(targetABI.isCompatible(incompatABI), !debugAbiMatters);

        // different compiler
        incompatABI = targetABI;
        incompatABI.setCompiler(QStringLiteral("Clang"));
        QCOMPARE(targetABI.isCompatible(incompatABI), !compilerAbiMatters);
    }
static ProbeABI qtVersionFromExec(const QString &path)
{
    ProbeABI abi;

    // yep, you can actually execute QtCore.so...
    QProcess proc;
    proc.setReadChannelMode(QProcess::SeparateChannels);
    proc.setReadChannel(QProcess::StandardOutput);
    proc.start(path);
    proc.waitForFinished();
    const QByteArray line = proc.readLine();
    const int pos = line.lastIndexOf(' ');
    const QList<QByteArray> version = line.mid(pos).split('.');
    if (version.size() < 3)
        return abi;

    abi.setQtVersion(version.at(0).toInt(), version.at(1).toInt());

    return abi;
}
Beispiel #13
0
ProbeABI findBestMatchingABI(const ProbeABI &targetABI, const QVector<ProbeABI> &availableABIs)
{
    QVector<ProbeABI> compatABIs;
    foreach (const ProbeABI &abi, availableABIs) {
        if (targetABI.isCompatible(abi))
            compatABIs.push_back(abi);
    }

    if (compatABIs.isEmpty())
        return ProbeABI();

    std::sort(compatABIs.begin(), compatABIs.end());
    return compatABIs.last();
}
Beispiel #14
0
QVector<ProbeABI> listProbeABIs()
{
    QVector<ProbeABI> abis;
    const QDir dir(Paths::probePath(QString()));
#if defined(GAMMARAY_INSTALL_QT_LAYOUT)
    const QString filter = QStringLiteral("*gammaray_probe*");
    foreach (const QFileInfo &abiId, dir.entryInfoList(QStringList(filter), QDir::Files)) {
        // OSX has broken QLibrary::isLibrary() - QTBUG-50446
        if (!QLibrary::isLibrary(abiId.fileName())
            && !abiId.fileName().endsWith(Paths::libraryExtension(), Qt::CaseInsensitive))
            continue;
        const ProbeABI abi = ProbeABI::fromString(abiId.baseName().section(QStringLiteral("-"), 1));
        if (abi.isValid())
            abis.push_back(abi);
    }
#else
    foreach (const QString &abiId, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
        const ProbeABI abi = ProbeABI::fromString(abiId);
        if (abi.isValid())
            abis.push_back(abi);
    }
#endif
    return abis;
}
Beispiel #15
0
ProbeABI ProbeABI::fromString(const QString &id)
{
    QStringList idParts = id.split('-');
    if (idParts.size() < 2)
        return ProbeABI();

    int index = 0;
    ProbeABI abi;

    // version
    static QRegExp versionRegExp("^qt(\\d+)\\_(\\d+)$");
    if (versionRegExp.indexIn(idParts.value(index++)) != 0)
        return ProbeABI();
    abi.setQtVersion(versionRegExp.cap(1).toInt(), versionRegExp.cap(2).toInt());

    // compiler
#ifdef Q_OS_WIN
    abi.setCompiler(idParts.value(index++));
    if (abi.isVersionRelevant())
        abi.setCompilerVersion(idParts.value(index++));
#endif

    if (idParts.size() != index + 1)
        return ProbeABI();

    // architecture / debug/release
    const QString postfix = QStringLiteral(GAMMARAY_DEBUG_POSTFIX);
    QString arch = idParts.value(index);

    if (!postfix.isEmpty()) {
        if (arch.endsWith(postfix, Qt::CaseInsensitive)) {
            arch.chop(postfix.length());

            if (abi.isDebugRelevant())
                abi.setIsDebug(true);
        }
    }

    abi.setArchitecture(arch);
    return abi;
}
Beispiel #16
0
    void testToString()
    {
        QFETCH(QString, id);
        QFETCH(int, majorVersion);
        QFETCH(int, minorVersion);
        QFETCH(bool, isDebug);
        QFETCH(QString, arch);
        QFETCH(QString, compiler);
        QFETCH(QString, compilerVersion);

        ProbeABI abi;
        abi.setQtVersion(majorVersion, minorVersion);
        abi.setIsDebug(isDebug);
        abi.setArchitecture(arch);
        abi.setCompiler(compiler);
        abi.setCompilerVersion(compilerVersion);

        QCOMPARE(abi.id(), id);
    }
Beispiel #17
0
ProbeABI ProbeABI::fromString(const QString& id)
{
  QStringList idParts = id.split('-');
  if (idParts.size() < 2)
    return ProbeABI();

  int index = 0;
  ProbeABI abi;

  // version
  static QRegExp versionRegExp("^qt(\\d+)\\.(\\d+)$");
  if (versionRegExp.indexIn(idParts.value(index++)) != 0)
    return ProbeABI();
  abi.setQtVersion(versionRegExp.cap(1).toInt(), versionRegExp.cap(2).toInt());

  // compiler
#ifdef Q_OS_WIN
  abi.setCompiler(idParts.value(index++));
#endif

  // debug/release
  if (abi.isDebugRelevant()) {
    if (idParts.size() <= index)
      return ProbeABI();
    const QString s = idParts.value(index++);
    if (s != "release" && s != "debug")
      return ProbeABI();
    abi.setIsDebug(s == "debug");
  }

  // architecture
  if (idParts.size() != index + 1)
    return ProbeABI();
  abi.setArchitecture(idParts.value(index));
  return abi;
}
Beispiel #18
0
int main(int argc, char **argv)
{
  QCoreApplication::setOrganizationName(QStringLiteral("KDAB"));
  QCoreApplication::setOrganizationDomain(QStringLiteral("kdab.com"));
  QCoreApplication::setApplicationName(QStringLiteral("GammaRay"));

  installSignalHandler();

  QStringList args;
  args.reserve(argc);
  for (int i = 1; i < argc; ++i) {
    args.push_back(QString::fromLocal8Bit(argv[i]));
  }
#ifdef HAVE_QT_WIDGETS
  QApplication app(argc, argv); // for style inspector
#else
  QCoreApplication app(argc, argv);
#endif
  Paths::setRelativeRootPath(GAMMARAY_INVERSE_BIN_DIR);

  QStringList builtInArgs = QStringList() << QStringLiteral("-style")
                                          << QStringLiteral("-stylesheet")
                                          << QStringLiteral("-graphicssystem");

  LaunchOptions options;
  while (!args.isEmpty() && args.first().startsWith('-')) {
    const QString arg = args.takeFirst();
    if ((arg == QLatin1String("-i") || arg == QLatin1String("--injector")) && !args.isEmpty()) {
      options.setInjectorType(args.takeFirst());
      continue;
    }
    if ((arg == QLatin1String("-p") || arg == QLatin1String("--pid")) && !args.isEmpty()) {
      options.setPid( args.takeFirst().toInt() );
      continue;
    }
    if (arg == QLatin1String("-h") || arg == QLatin1String("--help")) {
      usage(argv[0]);
      return 0;
    }
    if (arg == QLatin1String("-v") || arg == QLatin1String("--version")) {
      out << "GammaRay version " << GAMMARAY_VERSION_STRING << endl;
      out << "Copyright (C) 2010-2016 Klaralvdalens Datakonsult AB, "
          << "a KDAB Group company, [email protected]" << endl;
      return 0;
    }
    if (arg == QLatin1String("--inprocess")) {
      options.setUiMode(LaunchOptions::InProcessUi);
    }
    if (arg == QLatin1String("--inject-only")) {
      options.setUiMode(LaunchOptions::NoUi);
    }
    if (arg == QLatin1String("--listen") && !args.isEmpty()) {
      options.setProbeSetting(QStringLiteral("ServerAddress"), urlFromUserInput(args.takeFirst()).toString());
    }
    if ( arg == QLatin1String("--no-listen")) {
      options.setProbeSetting(QStringLiteral("RemoteAccessEnabled"), false);
      options.setUiMode(LaunchOptions::InProcessUi);
    }
    if ( arg == QLatin1String("--list-probes")) {
      foreach( const ProbeABI &abi, ProbeFinder::listProbeABIs())
        out << abi.id() << " (" << abi.displayString() << ")" << endl;
      return 0;
    }
    if ( arg == QLatin1String("--probe") && !args.isEmpty()) {
      const ProbeABI abi = ProbeABI::fromString(args.takeFirst());
      if (!abi.isValid()) {
        out << "Invalid probe ABI specified, see --list-probes for valid ones." << endl;
        return 1;
      }
      if (ProbeFinder::findProbe(QStringLiteral(GAMMARAY_PROBE_BASENAME), abi).isEmpty()) {
        out << abi.id() << "is not a known probe, see --list-probes." << endl;
        return 1;
      }
      options.setProbeABI(abi);
    }
    if ( arg == QLatin1String("--connect") && !args.isEmpty()) {
      const QUrl url = urlFromUserInput(args.takeFirst());
      ClientLauncher client;
      client.launch(url);
      client.waitForFinished();
      return 0;
    }

    // debug/test options
    if (arg == QLatin1String("-filtertest")) {
      qputenv("GAMMARAY_TEST_FILTER", "1");
    }
    if (arg == QLatin1String("-unittest")) {
      qputenv("GAMMARAY_UNITTEST", "1");
    }
    if (arg == QLatin1String("-modeltest")) {
      qputenv("GAMMARAY_MODELTEST", "1");
    }
    // built-in arguments of QApp, could be meant for us if we are showing the launcher window
    foreach (const QString &builtInArg, builtInArgs) {
      if (arg == builtInArg && !args.isEmpty()) {
        args.takeFirst();
      }
    }
  }
Beispiel #19
0
bool ProbeABI::operator<(const ProbeABI& rhs) const
{
  if (majorQtVersion() == rhs.majorQtVersion())
    return minorQtVersion() < rhs.minorQtVersion();
  return majorQtVersion() < rhs.majorQtVersion();
}
Beispiel #20
0
int main(int argc, char **argv)
{
    QCoreApplication::setOrganizationName(QStringLiteral("KDAB"));
    QCoreApplication::setOrganizationDomain(QStringLiteral("kdab.com"));
    QCoreApplication::setApplicationName(QStringLiteral("GammaRay"));

    installSignalHandler();

    QStringList args;
    args.reserve(argc);
    for (int i = 1; i < argc; ++i)
        args.push_back(QString::fromLocal8Bit(argv[i]));

#ifndef GAMMARAY_CORE_ONLY_LAUNCHER
    QApplication app(argc, argv); // for style inspector
#else
    QCoreApplication app(argc, argv);
#endif
    Paths::setRelativeRootPath(GAMMARAY_INVERSE_BIN_DIR);

    QStringList builtInArgs = QStringList() << QStringLiteral("-style")
                                            << QStringLiteral("-stylesheet")
                                            << QStringLiteral("-graphicssystem");

    LaunchOptions options;
    while (!args.isEmpty() && args.first().startsWith('-')) {
        const QString arg = args.takeFirst();
        if ((arg == QLatin1String("-i") || arg == QLatin1String("--injector")) && !args.isEmpty()) {
            options.setInjectorType(args.takeFirst());
            continue;
        }
        if ((arg == QLatin1String("-o") || arg == QLatin1String("--injector-override"))
            && !args.isEmpty()) {
            options.setInjectorTypeExecutableOverride(args.takeFirst());
            continue;
        }
        if ((arg == QLatin1String("-p") || arg == QLatin1String("--pid")) && !args.isEmpty()) {
            options.setPid(args.takeFirst().toInt());
            continue;
        }
        if (arg == QLatin1String("-h") || arg == QLatin1String("--help")) {
            usage(argv[0]);
            return 0;
        }
        if (arg == QLatin1String("-v") || arg == QLatin1String("--version")) {
            out << "GammaRay version " << GAMMARAY_VERSION_STRING << endl;
            out << "Copyright (C) 2010-2016 Klaralvdalens Datakonsult AB, "
                << "a KDAB Group company, [email protected]" << endl;
            out << "Protocol version " << Protocol::version() << endl;
            out << "Broadcast version " << Protocol::broadcastFormatVersion() << endl;
            return 0;
        }
        if (arg == QLatin1String("--inprocess"))
            options.setUiMode(LaunchOptions::InProcessUi);
        if (arg == QLatin1String("--inject-only"))
            options.setUiMode(LaunchOptions::NoUi);
        if (arg == QLatin1String("--listen") && !args.isEmpty())
            options.setProbeSetting(QStringLiteral("ServerAddress"),
                                    urlFromUserInput(args.takeFirst()).toString());
        if (arg == QLatin1String("--no-listen")) {
            options.setProbeSetting(QStringLiteral("RemoteAccessEnabled"), false);
            options.setUiMode(LaunchOptions::InProcessUi);
        }
        if (arg == QLatin1String("--list-probes")) {
            foreach (const ProbeABI &abi, ProbeFinder::listProbeABIs())
                out << abi.id() << " (" << abi.displayString() << ")" << endl;
            return 0;
        }
        if (arg == QLatin1String("--probe") && !args.isEmpty()) {
            const ProbeABI abi = ProbeABI::fromString(args.takeFirst());
            if (!abi.isValid()) {
                out << "Invalid probe ABI specified, see --list-probes for valid ones." << endl;
                return 1;
            }
            if (ProbeFinder::findProbe(abi).isEmpty()) {
                out << abi.id() << "is not a known probe, see --list-probes." << endl;
                return 1;
            }
            options.setProbeABI(abi);
        }
        if (arg == QLatin1String("--connect") && !args.isEmpty()) {
            const QUrl url = urlFromUserInput(args.takeFirst());
            ClientLauncher client;
            client.launch(url);
            client.waitForFinished();
            return 0;
        }
        if (arg == QLatin1String("--self-test")) {
            SelfTest selfTest;
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
            QObject::connect(&selfTest, &SelfTest::information, [](const QString &msg) {
                out << msg << endl;
            });
            QObject::connect(&selfTest, &SelfTest::error, [](const QString &msg) {
                err << "Error: " << msg << endl;
            });
#endif
            if (args.isEmpty() || args.first().startsWith('-'))
                return selfTest.checkEverything() ? 0 : 1;
            const auto injectorType = args.takeFirst();
            return selfTest.checkInjector(injectorType) ? 0 : 1;
        }

        // debug/test options
        if (arg == QLatin1String("-filtertest"))
            qputenv("GAMMARAY_TEST_FILTER", "1");
        if (arg == QLatin1String("-unittest"))
            qputenv("GAMMARAY_UNITTEST", "1");
        // built-in arguments of QApp, could be meant for us if we are showing the launcher window
        foreach (const QString &builtInArg, builtInArgs) {
            if (arg == builtInArg && !args.isEmpty())
                args.takeFirst();
        }
    }