abi.cpp 48 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
2
**
3 4
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
7
**
hjk's avatar
hjk committed
8 9 10 11
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
12 13 14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
15
**
16 17 18 19 20 21 22
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23
**
hjk's avatar
hjk committed
24
****************************************************************************/
25 26 27

#include "abi.h"

28 29
#include <utils/fileutils.h>

30 31 32
#include <QDebug>
#include <QtEndian>
#include <QFile>
Samuel Gaist's avatar
Samuel Gaist committed
33
#include <QRegExp>
34 35 36
#include <QString>
#include <QStringList>
#include <QSysInfo>
37

38 39 40
/*!
    \class ProjectExplorer::Abi

41 42
    \brief The Abi class represents the Application Binary Interface (ABI) of
    a target platform.
43 44 45 46

    \sa ProjectExplorer::ToolChain
*/

47 48
namespace ProjectExplorer {

49 50 51 52
// --------------------------------------------------------------------------
// Helpers
// --------------------------------------------------------------------------

Tobias Hunger's avatar
Tobias Hunger committed
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
static quint8 getUint8(const QByteArray &data, int pos)
{
    return static_cast<quint8>(data.at(pos));
}

static quint32 getLEUint32(const QByteArray &ba, int pos)
{
    Q_ASSERT(ba.size() >= pos + 3);
    return (static_cast<quint32>(static_cast<quint8>(ba.at(pos + 3))) << 24)
            + (static_cast<quint32>(static_cast<quint8>(ba.at(pos + 2)) << 16))
            + (static_cast<quint32>(static_cast<quint8>(ba.at(pos + 1))) << 8)
            + static_cast<quint8>(ba.at(pos));
}

static quint32 getBEUint32(const QByteArray &ba, int pos)
{
    Q_ASSERT(ba.size() >= pos + 3);
    return (static_cast<quint32>(static_cast<quint8>(ba.at(pos))) << 24)
            + (static_cast<quint32>(static_cast<quint8>(ba.at(pos + 1))) << 16)
            + (static_cast<quint32>(static_cast<quint8>(ba.at(pos + 2))) << 8)
            + static_cast<quint8>(ba.at(pos + 3));
}

static quint32 getLEUint16(const QByteArray &ba, int pos)
{
    Q_ASSERT(ba.size() >= pos + 1);
    return (static_cast<quint16>(static_cast<quint8>(ba.at(pos + 1))) << 8) + static_cast<quint8>(ba.at(pos));
}

static quint32 getBEUint16(const QByteArray &ba, int pos)
{
    Q_ASSERT(ba.size() >= pos + 1);
    return (static_cast<quint16>(static_cast<quint8>(ba.at(pos))) << 8) + static_cast<quint8>(ba.at(pos + 1));
}

88 89 90
static Abi macAbiForCpu(quint32 type) {
    switch (type) {
    case 7: // CPU_TYPE_X86, CPU_TYPE_I386
91
        return Abi(Abi::X86Architecture, Abi::DarwinOS, Abi::GenericDarwinFlavor, Abi::MachOFormat, 32);
92
    case 0x01000000 +  7: // CPU_TYPE_X86_64
93
        return Abi(Abi::X86Architecture, Abi::DarwinOS, Abi::GenericDarwinFlavor, Abi::MachOFormat, 64);
94
    case 18: // CPU_TYPE_POWERPC
95
        return Abi(Abi::PowerPCArchitecture, Abi::DarwinOS, Abi::GenericDarwinFlavor, Abi::MachOFormat, 32);
96
    case 0x01000000 + 18: // CPU_TYPE_POWERPC64
97
        return Abi(Abi::PowerPCArchitecture, Abi::DarwinOS, Abi::GenericDarwinFlavor, Abi::MachOFormat, 32);
98
    case 12: // CPU_TYPE_ARM
99
        return Abi(Abi::ArmArchitecture, Abi::DarwinOS, Abi::GenericDarwinFlavor, Abi::MachOFormat, 32);
100
    case 0x01000000 + 12: // CPU_TYPE_ARM64
101
        return Abi(Abi::ArmArchitecture, Abi::DarwinOS, Abi::GenericDarwinFlavor, Abi::MachOFormat, 64);
102 103 104 105 106
    default:
        return Abi();
    }
}

Tobias Hunger's avatar
Tobias Hunger committed
107 108 109 110 111 112 113 114 115 116 117
static QList<Abi> parseCoffHeader(const QByteArray &data)
{
    QList<Abi> result;
    if (data.size() < 20)
        return result;

    Abi::Architecture arch = Abi::UnknownArchitecture;
    Abi::OSFlavor flavor = Abi::UnknownFlavor;
    int width = 0;

    // Get machine field from COFF file header
Tobias Hunger's avatar
Tobias Hunger committed
118
    quint16 machine = getLEUint16(data, 0);
Tobias Hunger's avatar
Tobias Hunger committed
119
    switch (machine) {
120 121 122 123 124 125
    case 0x01c0: // ARM LE
    case 0x01c2: // ARM or thumb
    case 0x01c4: // ARMv7 thumb
        arch = Abi::ArmArchitecture;
        width = 32;
        break;
Tobias Hunger's avatar
Tobias Hunger committed
126 127 128 129 130 131 132 133
    case 0x8664: // x86_64
        arch = Abi::X86Architecture;
        width = 64;
        break;
    case 0x014c: // i386
        arch = Abi::X86Architecture;
        width = 32;
        break;
134
    case 0x0166: // MIPS, little endian
Tobias Hunger's avatar
Tobias Hunger committed
135
        arch = Abi::MipsArchitecture;
136 137
        width = 32;
        break;
Tobias Hunger's avatar
Tobias Hunger committed
138 139 140 141 142 143
    case 0x0200: // ia64
        arch = Abi::ItaniumArchitecture;
        width = 64;
        break;
    }

144
    if (data.size() >= 24) {
Tobias Hunger's avatar
Tobias Hunger committed
145
        // Get Major and Minor Image Version from optional header fields
146 147 148 149
        quint8 minorLinker = data.at(23);
        switch (data.at(22)) {
        case 2:
        case 3: // not yet reached:-)
Tobias Hunger's avatar
Tobias Hunger committed
150
            flavor = Abi::WindowsMSysFlavor;
151 152 153 154 155 156 157 158 159 160 161 162 163
            break;
        case 8:
            flavor = Abi::WindowsMsvc2005Flavor;
            break;
        case 9:
            flavor = Abi::WindowsMsvc2008Flavor;
            break;
        case 10:
            flavor = Abi::WindowsMsvc2010Flavor;
            break;
        case 11:
            flavor = Abi::WindowsMsvc2012Flavor;
            break;
Yuchen Deng's avatar
Yuchen Deng committed
164 165 166
        case 12:
            flavor = Abi::WindowsMsvc2013Flavor;
            break;
Joerg Bornemann's avatar
Joerg Bornemann committed
167
        case 14:
168 169 170
            flavor = minorLinker >= quint8(10)
                ? Abi::WindowsMsvc2017Flavor // MSVC2017 RC
                : Abi::WindowsMsvc2015Flavor;
171
            break;
172 173
        case 15:
            flavor = Abi::WindowsMsvc2017Flavor;
Joerg Bornemann's avatar
Joerg Bornemann committed
174
            break;
175 176 177 178
        default: // Keep unknown flavor
            if (minorLinker != 0)
                flavor = Abi::WindowsMSysFlavor; // MSVC seems to avoid using minor numbers
            else
Tobias Hunger's avatar
Tobias Hunger committed
179
                qWarning("%s: Unknown MSVC flavour encountered.", Q_FUNC_INFO);
180
            break;
181
        }
Tobias Hunger's avatar
Tobias Hunger committed
182 183 184 185 186 187 188 189
    }

    if (arch != Abi::UnknownArchitecture && width != 0)
        result.append(Abi(arch, Abi::WindowsOS, flavor, Abi::PEFormat, width));

    return result;
}

190 191 192
static QList<Abi> abiOf(const QByteArray &data)
{
    QList<Abi> result;
Tobias Hunger's avatar
Tobias Hunger committed
193 194
    if (data.size() <= 8)
        return result;
195 196

    if (data.size() >= 20
Tobias Hunger's avatar
Tobias Hunger committed
197 198
            && getUint8(data, 0) == 0x7f && getUint8(data, 1) == 'E' && getUint8(data, 2) == 'L'
            && getUint8(data, 3) == 'F') {
199
        // ELF format:
Tobias Hunger's avatar
Tobias Hunger committed
200 201 202
        bool isLE = (getUint8(data, 5) == 1);
        quint16 machine = isLE ? getLEUint16(data, 18) : getBEUint16(data, 18);
        quint8 osAbi = getUint8(data, 7);
203 204 205 206 207

        Abi::OS os = Abi::UnixOS;
        Abi::OSFlavor flavor = Abi::GenericUnixFlavor;
        // http://www.sco.com/developers/gabi/latest/ch4.eheader.html#elfid
        switch (osAbi) {
208 209
#if defined(Q_OS_NETBSD)
        case 0: // NetBSD: ELFOSABI_NETBSD  2, however, NetBSD uses 0
210 211 212
            os = Abi::BsdOS;
            flavor = Abi::NetBsdFlavor;
            break;
213 214 215 216 217 218
#elif defined(Q_OS_OPENBSD)
        case 0: // OpenBSD: ELFOSABI_OPENBSD 12, however, OpenBSD uses 0
            os = Abi::BsdOS;
            flavor = Abi::OpenBsdFlavor;
            break;
#else
219
        case 0: // no extra info available: Default to Linux:
220 221
#endif
        case 3: // Linux:
222
        case 97: // ARM, also linux most of the time.
223 224 225 226 227 228 229 230 231 232 233 234
            os = Abi::LinuxOS;
            flavor = Abi::GenericLinuxFlavor;
            break;
        case 6: // Solaris:
            os = Abi::UnixOS;
            flavor = Abi::SolarisUnixFlavor;
            break;
        case 9: // FreeBSD:
            os = Abi::BsdOS;
            flavor = Abi::FreeBsdFlavor;
            break;
        }
235

236 237
        switch (machine) {
        case 3: // EM_386
238
            result.append(Abi(Abi::X86Architecture, os, flavor, Abi::ElfFormat, 32));
239 240
            break;
        case 8: // EM_MIPS
Tobias Hunger's avatar
Tobias Hunger committed
241
            result.append(Abi(Abi::MipsArchitecture, os, flavor, Abi::ElfFormat, 32));
242 243
            break;
        case 20: // EM_PPC
244
            result.append(Abi(Abi::PowerPCArchitecture, os, flavor, Abi::ElfFormat, 32));
245 246
            break;
        case 21: // EM_PPC64
247
            result.append(Abi(Abi::PowerPCArchitecture, os, flavor, Abi::ElfFormat, 64));
248
            break;
249
        case 40: // EM_ARM
250
            result.append(Abi(Abi::ArmArchitecture, os, flavor, Abi::ElfFormat, 32));
251
            break;
Daniel Teske's avatar
Daniel Teske committed
252 253 254
        case 183: // EM_AARCH64
            result.append(Abi(Abi::ArmArchitecture, os, flavor, Abi::ElfFormat, 64));
            break;
255
        case 62: // EM_X86_64
256
            result.append(Abi(Abi::X86Architecture, os, flavor, Abi::ElfFormat, 64));
257
            break;
Tobias Hunger's avatar
Tobias Hunger committed
258 259 260
        case 42: // EM_SH
            result.append(Abi(Abi::ShArchitecture, os, flavor, Abi::ElfFormat, 32));
            break;
261
        case 50: // EM_IA_64
262
            result.append(Abi(Abi::ItaniumArchitecture, os, flavor, Abi::ElfFormat, 64));
263 264
            break;
        default:
Nikolai Kosjar's avatar
Nikolai Kosjar committed
265
            ;
266
        }
Tobias Hunger's avatar
Tobias Hunger committed
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
    } else if (((getUint8(data, 0) == 0xce || getUint8(data, 0) == 0xcf)
             && getUint8(data, 1) == 0xfa && getUint8(data, 2) == 0xed && getUint8(data, 3) == 0xfe
            )
            ||
            (getUint8(data, 0) == 0xfe && getUint8(data, 1) == 0xed && getUint8(data, 2) == 0xfa
             && (getUint8(data, 3) == 0xce || getUint8(data, 3) == 0xcf)
            )
           ) {
            // Mach-O format (Mac non-fat binary, 32 and 64bit magic):
            quint32 type = (getUint8(data, 1) ==  0xfa) ? getLEUint32(data, 4) : getBEUint32(data, 4);
            result.append(macAbiForCpu(type));
    } else if ((getUint8(data, 0) == 0xbe && getUint8(data, 1) == 0xba
                && getUint8(data, 2) == 0xfe && getUint8(data, 3) == 0xca)
               ||
               (getUint8(data, 0) == 0xca && getUint8(data, 1) == 0xfe
                && getUint8(data, 2) == 0xba && getUint8(data, 3) == 0xbe)
              ) {
        // Mach-0 format Fat binary header:
        bool isLE = (getUint8(data, 0) == 0xbe);
        quint32 count = isLE ? getLEUint32(data, 4) : getBEUint32(data, 4);
287 288 289 290 291
        int pos = 8;
        for (quint32 i = 0; i < count; ++i) {
            if (data.size() <= pos + 4)
                break;

Tobias Hunger's avatar
Tobias Hunger committed
292
            quint32 type = isLE ? getLEUint32(data, pos) : getBEUint32(data, pos);
293 294 295
            result.append(macAbiForCpu(type));
            pos += 20;
        }
296
    } else if (data.size() >= 64){
Tobias Hunger's avatar
Tobias Hunger committed
297
        // Windows PE: values are LE (except for a few exceptions which we will not use here).
298

Tobias Hunger's avatar
Tobias Hunger committed
299
        // MZ header first (ZM is also allowed, but rarely used)
Robert Loehning's avatar
Robert Loehning committed
300 301 302 303
        const quint8 firstChar = getUint8(data, 0);
        const quint8 secondChar = getUint8(data, 1);
        if ((firstChar != 'M' || secondChar != 'Z') && (firstChar != 'Z' || secondChar != 'M'))
            return result;
304 305

        // Get PE/COFF header position from MZ header:
Tobias Hunger's avatar
Tobias Hunger committed
306
        qint32 pePos = getLEUint32(data, 60);
307 308
        if (pePos <= 0 || data.size() < pePos + 4 + 20) // PE magic bytes plus COFF header
            return result;
Tobias Hunger's avatar
Tobias Hunger committed
309 310
        if (getUint8(data, pePos) == 'P' && getUint8(data, pePos + 1) == 'E'
            && getUint8(data, pePos + 2) == 0 && getUint8(data, pePos + 3) == 0)
Tobias Hunger's avatar
Tobias Hunger committed
311
            result = parseCoffHeader(data.mid(pePos + 4));
312 313 314 315 316 317 318 319
    }
    return result;
}

// --------------------------------------------------------------------------
// Abi
// --------------------------------------------------------------------------

320
Abi::Abi(const Architecture &a, const OS &o,
hjk's avatar
hjk committed
321
         const OSFlavor &of, const BinaryFormat &f, unsigned char w) :
322 323 324
    m_architecture(a), m_os(o), m_osFlavor(of), m_binaryFormat(f), m_wordWidth(w)
{
    switch (m_os) {
325
    case Abi::UnknownOS:
hjk's avatar
hjk committed
326
        m_osFlavor = UnknownFlavor;
327
        break;
328
    case Abi::LinuxOS:
329
        if (m_osFlavor < GenericLinuxFlavor || m_osFlavor > AndroidLinuxFlavor)
hjk's avatar
hjk committed
330
            m_osFlavor = UnknownFlavor;
331
        break;
332
    case Abi::BsdOS:
333 334
        if (m_osFlavor < FreeBsdFlavor || m_osFlavor > OpenBsdFlavor)
            m_osFlavor = UnknownFlavor;
335
        break;
336 337
    case Abi::DarwinOS:
        if (m_osFlavor < GenericDarwinFlavor || m_osFlavor > GenericDarwinFlavor)
hjk's avatar
hjk committed
338
            m_osFlavor = UnknownFlavor;
339
        break;
340
    case Abi::UnixOS:
341
        if (m_osFlavor < GenericUnixFlavor || m_osFlavor > SolarisUnixFlavor)
hjk's avatar
hjk committed
342
            m_osFlavor = UnknownFlavor;
343
        break;
344
    case Abi::WindowsOS:
345
        if (m_osFlavor < WindowsMsvc2005Flavor || m_osFlavor > WindowsCEFlavor)
hjk's avatar
hjk committed
346
            m_osFlavor = UnknownFlavor;
347
        break;
348 349 350
    case Abi::VxWorks:
        if (m_osFlavor != VxWorksFlavor)
            m_osFlavor = VxWorksFlavor;
351
        break;
James McDonnell's avatar
James McDonnell committed
352 353 354
    case Abi::QnxOS:
        if (m_osFlavor != GenericQnxFlavor)
            m_osFlavor = UnknownFlavor;
355
        break;
356 357 358 359
    }
}

Abi::Abi(const QString &abiString) :
hjk's avatar
hjk committed
360 361
    m_architecture(UnknownArchitecture), m_os(UnknownOS),
    m_osFlavor(UnknownFlavor), m_binaryFormat(UnknownFormat), m_wordWidth(0)
362
{
363
    const QVector<QStringRef> abiParts = abiString.splitRef(QLatin1Char('-'));
364 365
    if (abiParts.count() >= 1) {
        if (abiParts.at(0) == QLatin1String("unknown"))
hjk's avatar
hjk committed
366
            m_architecture = UnknownArchitecture;
367
        else if (abiParts.at(0) == QLatin1String("arm"))
hjk's avatar
hjk committed
368
            m_architecture = ArmArchitecture;
369 370
        else if (abiParts.at(0) == QLatin1String("aarch64"))
            m_architecture = ArmArchitecture;
371
        else if (abiParts.at(0) == QLatin1String("x86"))
hjk's avatar
hjk committed
372
            m_architecture = X86Architecture;
373
        else if (abiParts.at(0) == QLatin1String("mips"))
Tobias Hunger's avatar
Tobias Hunger committed
374
            m_architecture = MipsArchitecture;
375
        else if (abiParts.at(0) == QLatin1String("ppc"))
hjk's avatar
hjk committed
376
            m_architecture = PowerPCArchitecture;
377
        else if (abiParts.at(0) == QLatin1String("itanium"))
hjk's avatar
hjk committed
378
            m_architecture = ItaniumArchitecture;
Tobias Hunger's avatar
Tobias Hunger committed
379 380
        else if (abiParts.at(0) == QLatin1String("sh"))
            m_architecture = ShArchitecture;
381 382 383 384 385 386
        else
            return;
    }

    if (abiParts.count() >= 2) {
        if (abiParts.at(1) == QLatin1String("unknown"))
hjk's avatar
hjk committed
387
            m_os = UnknownOS;
388
        else if (abiParts.at(1) == QLatin1String("linux"))
hjk's avatar
hjk committed
389
            m_os = LinuxOS;
390 391
        else if (abiParts.at(1) == QLatin1String("bsd"))
            m_os = BsdOS;
392 393 394
        else if (abiParts.at(1) == QLatin1String("darwin")
                || abiParts.at(1) == QLatin1String("macos"))
            m_os = DarwinOS;
395
        else if (abiParts.at(1) == QLatin1String("unix"))
hjk's avatar
hjk committed
396
            m_os = UnixOS;
397
        else if (abiParts.at(1) == QLatin1String("windows"))
hjk's avatar
hjk committed
398
            m_os = WindowsOS;
399 400
        else if (abiParts.at(1) == QLatin1String("vxworks"))
            m_os = VxWorks;
James McDonnell's avatar
James McDonnell committed
401 402
        else if (abiParts.at(1) == QLatin1String("qnx"))
            m_os = QnxOS;
403 404 405 406 407 408
        else
            return;
    }

    if (abiParts.count() >= 3) {
        if (abiParts.at(2) == QLatin1String("unknown"))
hjk's avatar
hjk committed
409 410 411
            m_osFlavor = UnknownFlavor;
        else if (abiParts.at(2) == QLatin1String("generic") && m_os == LinuxOS)
            m_osFlavor = GenericLinuxFlavor;
BogDan Vatra's avatar
BogDan Vatra committed
412 413
        else if (abiParts.at(2) == QLatin1String("android") && m_os == LinuxOS)
            m_osFlavor = AndroidLinuxFlavor;
James McDonnell's avatar
James McDonnell committed
414 415
        else if (abiParts.at(2) == QLatin1String("generic") && m_os == QnxOS)
            m_osFlavor = GenericQnxFlavor;
416 417 418 419 420 421
        else if (abiParts.at(2) == QLatin1String("freebsd") && m_os == BsdOS)
            m_osFlavor = FreeBsdFlavor;
        else if (abiParts.at(2) == QLatin1String("netbsd") && m_os == BsdOS)
            m_osFlavor = NetBsdFlavor;
        else if (abiParts.at(2) == QLatin1String("openbsd") && m_os == BsdOS)
            m_osFlavor = OpenBsdFlavor;
422 423
        else if (abiParts.at(2) == QLatin1String("generic") && m_os == DarwinOS)
            m_osFlavor = GenericDarwinFlavor;
hjk's avatar
hjk committed
424 425
        else if (abiParts.at(2) == QLatin1String("generic") && m_os == UnixOS)
            m_osFlavor = GenericUnixFlavor;
426 427
        else if (abiParts.at(2) == QLatin1String("solaris") && m_os == UnixOS)
            m_osFlavor = SolarisUnixFlavor;
428 429 430 431 432 433
        else if (abiParts.at(2) == QLatin1String("msvc2005") && m_os == WindowsOS)
            m_osFlavor = WindowsMsvc2005Flavor;
        else if (abiParts.at(2) == QLatin1String("msvc2008") && m_os == WindowsOS)
            m_osFlavor = WindowsMsvc2008Flavor;
        else if (abiParts.at(2) == QLatin1String("msvc2010") && m_os == WindowsOS)
            m_osFlavor = WindowsMsvc2010Flavor;
Tobias Hunger's avatar
Tobias Hunger committed
434 435
        else if (abiParts.at(2) == QLatin1String("msvc2012") && m_os == WindowsOS)
            m_osFlavor = WindowsMsvc2012Flavor;
Yuchen Deng's avatar
Yuchen Deng committed
436 437
        else if (abiParts.at(2) == QLatin1String("msvc2013") && m_os == WindowsOS)
            m_osFlavor = WindowsMsvc2013Flavor;
Joerg Bornemann's avatar
Joerg Bornemann committed
438 439
        else if (abiParts.at(2) == QLatin1String("msvc2015") && m_os == WindowsOS)
            m_osFlavor = WindowsMsvc2015Flavor;
440 441
        else if (abiParts.at(2) == QLatin1String("msvc2017") && m_os == WindowsOS)
            m_osFlavor = WindowsMsvc2017Flavor;
hjk's avatar
hjk committed
442 443 444 445
        else if (abiParts.at(2) == QLatin1String("msys") && m_os == WindowsOS)
            m_osFlavor = WindowsMSysFlavor;
        else if (abiParts.at(2) == QLatin1String("ce") && m_os == WindowsOS)
            m_osFlavor = WindowsCEFlavor;
446 447
        else if (abiParts.at(2) == QLatin1String("vxworks") && m_os == VxWorks)
            m_osFlavor = VxWorksFlavor;
448 449 450 451 452 453
        else
            return;
    }

    if (abiParts.count() >= 4) {
        if (abiParts.at(3) == QLatin1String("unknown"))
hjk's avatar
hjk committed
454
            m_binaryFormat = UnknownFormat;
455
        else if (abiParts.at(3) == QLatin1String("elf"))
hjk's avatar
hjk committed
456
            m_binaryFormat = ElfFormat;
457
        else if (abiParts.at(3) == QLatin1String("pe"))
hjk's avatar
hjk committed
458
            m_binaryFormat = PEFormat;
459
        else if (abiParts.at(3) == QLatin1String("mach_o"))
hjk's avatar
hjk committed
460
            m_binaryFormat = MachOFormat;
461
        else if (abiParts.at(3) == QLatin1String("qml_rt"))
hjk's avatar
hjk committed
462
            m_binaryFormat = RuntimeQmlFormat;
463 464 465 466 467
        else
            return;
    }

    if (abiParts.count() >= 5) {
468
        const QStringRef &bits = abiParts.at(4);
469 470 471 472
        if (!bits.endsWith(QLatin1String("bit")))
            return;

        bool ok = false;
473 474 475
        const QStringRef number =
            bits.string()->midRef(bits.position(), bits.count() - 3);
        const int bitCount = number.toInt(&ok);
476 477 478 479 480 481 482 483
        if (!ok)
            return;
        if (bitCount != 8 && bitCount != 16 && bitCount != 32 && bitCount != 64)
            return;
        m_wordWidth = bitCount;
    }
}

484 485 486 487 488 489
Abi Abi::abiFromTargetTriplet(const QString &triple)
{
    QString machine = triple.toLower();
    if (machine.isEmpty())
        return Abi();

490
    const QVector<QStringRef> parts = machine.splitRef(QRegExp(QLatin1String("[ /-]")));
491 492 493 494 495

    Abi::Architecture arch = Abi::UnknownArchitecture;
    Abi::OS os = Abi::UnknownOS;
    Abi::OSFlavor flavor = Abi::UnknownFlavor;
    Abi::BinaryFormat format = Abi::UnknownFormat;
496
    unsigned char width = 0;
497 498
    int unknownCount = 0;

499
    for (const QStringRef &p : parts) {
500 501 502 503 504 505 506 507
        if (p == QLatin1String("unknown") || p == QLatin1String("pc") || p == QLatin1String("none")
                || p == QLatin1String("gnu") || p == QLatin1String("uclibc")
                || p == QLatin1String("86_64") || p == QLatin1String("redhat")
                || p == QLatin1String("gnueabi") || p == QLatin1String("w64")) {
            continue;
        } else if (p == QLatin1String("i386") || p == QLatin1String("i486") || p == QLatin1String("i586")
                   || p == QLatin1String("i686") || p == QLatin1String("x86")) {
            arch = Abi::X86Architecture;
508
            width = 32;
509 510
        } else if (p.startsWith(QLatin1String("arm"))) {
            arch = Abi::ArmArchitecture;
511
            width = p.contains(QLatin1String("64")) ? 64 : 32;
512 513 514
        } else if (p.startsWith(QLatin1String("aarch64"))) {
            arch = Abi::ArmArchitecture;
            width = 64;
515
        } else if (p.startsWith(QLatin1String("mips"))) {
516
            arch = Abi::MipsArchitecture;
Orgad Shaneh's avatar
Orgad Shaneh committed
517
            width = p.contains(QLatin1String("64")) ? 64 : 32;
518 519 520 521 522 523 524 525 526 527 528 529 530 531
        } else if (p == QLatin1String("x86_64") || p == QLatin1String("amd64")) {
            arch = Abi::X86Architecture;
            width = 64;
        } else if (p == QLatin1String("powerpc64")) {
            arch = Abi::PowerPCArchitecture;
            width = 64;
        } else if (p == QLatin1String("powerpc")) {
            arch = Abi::PowerPCArchitecture;
            width = 32;
        } else if (p == QLatin1String("linux") || p == QLatin1String("linux6e")) {
            os = Abi::LinuxOS;
            if (flavor == Abi::UnknownFlavor)
                flavor = Abi::GenericLinuxFlavor;
            format = Abi::ElfFormat;
532 533 534 535
        } else if (p == QLatin1String("android")) {
            flavor = Abi::AndroidLinuxFlavor;
        } else if (p == QLatin1String("androideabi")) {
            flavor = Abi::AndroidLinuxFlavor;
536 537 538 539 540
        } else if (p.startsWith(QLatin1String("freebsd"))) {
            os = Abi::BsdOS;
            if (flavor == Abi::UnknownFlavor)
                flavor = Abi::FreeBsdFlavor;
            format = Abi::ElfFormat;
Caspar Schutijser's avatar
Caspar Schutijser committed
541 542 543 544 545
        } else if (p.startsWith(QLatin1String("openbsd"))) {
            os = Abi::BsdOS;
            if (flavor == Abi::UnknownFlavor)
                flavor = Abi::OpenBsdFlavor;
            format = Abi::ElfFormat;
546
        } else if (p == QLatin1String("mingw32") || p == QLatin1String("win32")
547 548
                   || p == QLatin1String("mingw32msvc") || p == QLatin1String("msys")
                   || p == QLatin1String("cygwin")) {
549 550 551 552 553
            arch = Abi::X86Architecture;
            os = Abi::WindowsOS;
            flavor = Abi::WindowsMSysFlavor;
            format = Abi::PEFormat;
        } else if (p == QLatin1String("apple")) {
554 555
            os = Abi::DarwinOS;
            flavor = Abi::GenericDarwinFlavor;
556 557 558 559 560 561 562
            format = Abi::MachOFormat;
        } else if (p == QLatin1String("darwin10")) {
            width = 64;
        } else if (p == QLatin1String("darwin9")) {
            width = 32;
        } else if (p == QLatin1String("gnueabi")) {
            format = Abi::ElfFormat;
563 564 565 566 567 568
        } else if (p == QLatin1String("wrs")) {
            continue;
        } else if (p == QLatin1String("vxworks")) {
            os = Abi::VxWorks;
            flavor = Abi::VxWorksFlavor;
            format = Abi::ElfFormat;
James McDonnell's avatar
James McDonnell committed
569 570 571 572
        } else if (p.startsWith(QLatin1String("qnx"))) {
            os = Abi::QnxOS;
            flavor = Abi::GenericQnxFlavor;
            format = Abi::ElfFormat;
573 574 575 576 577 578 579 580
        } else {
            ++unknownCount;
        }
    }

    return Abi(arch, os, flavor, format, width);
}

581 582 583 584 585 586 587 588 589
QString Abi::toString() const
{
    QStringList dn;
    dn << toString(m_architecture);
    dn << toString(m_os);
    dn << toString(m_osFlavor);
    dn << toString(m_binaryFormat);
    dn << toString(m_wordWidth);

hjk's avatar
hjk committed
590
    return dn.join(QLatin1Char('-'));
591 592
}

Tobias Hunger's avatar
Tobias Hunger committed
593 594 595 596 597
bool Abi::operator != (const Abi &other) const
{
    return !operator ==(other);
}

598 599 600 601 602 603 604 605 606 607 608
bool Abi::operator == (const Abi &other) const
{
    return m_architecture == other.m_architecture
            && m_os == other.m_os
            && m_osFlavor == other.m_osFlavor
            && m_binaryFormat == other.m_binaryFormat
            && m_wordWidth == other.m_wordWidth;
}

bool Abi::isCompatibleWith(const Abi &other) const
{
609 610 611 612 613
    bool isCompat = (architecture() == other.architecture() || other.architecture() == Abi::UnknownArchitecture)
                     && (os() == other.os() || other.os() == Abi::UnknownOS)
                     && (osFlavor() == other.osFlavor() || other.osFlavor() == Abi::UnknownFlavor)
                     && (binaryFormat() == other.binaryFormat() || other.binaryFormat() == Abi::UnknownFormat)
                     && ((wordWidth() == other.wordWidth() && wordWidth() != 0) || other.wordWidth() == 0);
614 615 616 617 618 619
    // *-linux-generic-* is compatible with *-linux-* (both ways): This is for the benefit of
    // people building Qt themselves using e.g. a meego toolchain.
    //
    // We leave it to the specific targets to catch filter out the tool chains that do not
    // work for them.
    if (!isCompat && (architecture() == other.architecture() || other.architecture() == Abi::UnknownArchitecture)
Tobias Hunger's avatar
Tobias Hunger committed
620
                  && ((os() == other.os()) && (os() == LinuxOS))
621 622 623
                  && (osFlavor() == GenericLinuxFlavor || other.osFlavor() == GenericLinuxFlavor)
                  && (binaryFormat() == other.binaryFormat() || other.binaryFormat() == Abi::UnknownFormat)
                  && ((wordWidth() == other.wordWidth() && wordWidth() != 0) || other.wordWidth() == 0))
624
        isCompat = true;
BogDan Vatra's avatar
BogDan Vatra committed
625 626
    if (osFlavor() == AndroidLinuxFlavor || other.osFlavor() == AndroidLinuxFlavor)
        isCompat = (osFlavor() == other.osFlavor() && architecture() == other.architecture());
627
    return isCompat;
628 629 630 631
}

bool Abi::isValid() const
{
hjk's avatar
hjk committed
632 633 634 635
    return m_architecture != UnknownArchitecture
            && m_os != UnknownOS
            && m_osFlavor != UnknownFlavor
            && m_binaryFormat != UnknownFormat
636 637 638
            && m_wordWidth != 0;
}

Tobias Hunger's avatar
Tobias Hunger committed
639 640 641 642 643 644 645 646 647
bool Abi::isNull() const
{
    return m_architecture == UnknownArchitecture
            && m_os == UnknownOS
            && m_osFlavor == UnknownFlavor
            && m_binaryFormat == UnknownFormat
            && m_wordWidth == 0;
}

648 649 650
QString Abi::toString(const Architecture &a)
{
    switch (a) {
hjk's avatar
hjk committed
651
    case ArmArchitecture:
652
        return QLatin1String("arm");
hjk's avatar
hjk committed
653
    case X86Architecture:
654
        return QLatin1String("x86");
Tobias Hunger's avatar
Tobias Hunger committed
655
    case MipsArchitecture:
656
        return QLatin1String("mips");
hjk's avatar
hjk committed
657
    case PowerPCArchitecture:
658
        return QLatin1String("ppc");
hjk's avatar
hjk committed
659
    case ItaniumArchitecture:
660
        return QLatin1String("itanium");
Tobias Hunger's avatar
Tobias Hunger committed
661
    case ShArchitecture:
Tobias Hunger's avatar
Tobias Hunger committed
662
        return QLatin1String("sh");
hjk's avatar
hjk committed
663
    case UnknownArchitecture: // fall through!
664 665 666 667 668 669 670 671
    default:
        return QLatin1String("unknown");
    }
}

QString Abi::toString(const OS &o)
{
    switch (o) {
hjk's avatar
hjk committed
672
    case LinuxOS:
673
        return QLatin1String("linux");
674 675
    case BsdOS:
        return QLatin1String("bsd");
676 677
    case DarwinOS:
        return QLatin1String("darwin");
hjk's avatar
hjk committed
678
    case UnixOS:
679
        return QLatin1String("unix");
hjk's avatar
hjk committed
680
    case WindowsOS:
681
        return QLatin1String("windows");
682 683
    case VxWorks:
        return QLatin1String("vxworks");
James McDonnell's avatar
James McDonnell committed
684 685
    case QnxOS:
        return QLatin1String("qnx");
hjk's avatar
hjk committed
686
    case UnknownOS: // fall through!
687 688 689 690 691
    default:
        return QLatin1String("unknown");
    };
}

hjk's avatar
hjk committed
692
QString Abi::toString(const OSFlavor &of)
693 694
{
    switch (of) {
695
    case Abi::GenericLinuxFlavor:
696
        return QLatin1String("generic");
697
    case Abi::AndroidLinuxFlavor:
BogDan Vatra's avatar
BogDan Vatra committed
698
        return QLatin1String("android");
699
    case Abi::FreeBsdFlavor:
700
        return QLatin1String("freebsd");
701
    case Abi::NetBsdFlavor:
702
        return QLatin1String("netbsd");
703
    case Abi::OpenBsdFlavor:
704
        return QLatin1String("openbsd");
705
    case Abi::GenericDarwinFlavor:
706
        return QLatin1String("generic");
707
    case Abi::GenericUnixFlavor:
708
        return QLatin1String("generic");
709
    case Abi::SolarisUnixFlavor:
710
        return QLatin1String("solaris");
711
    case Abi::WindowsMsvc2005Flavor:
712
        return QLatin1String("msvc2005");
713
    case Abi::WindowsMsvc2008Flavor:
714
        return QLatin1String("msvc2008");
715
    case Abi::WindowsMsvc2010Flavor:
716
        return QLatin1String("msvc2010");
717
    case Abi::WindowsMsvc2012Flavor:
Tobias Hunger's avatar
Tobias Hunger committed
718
        return QLatin1String("msvc2012");
719
    case Abi::WindowsMsvc2013Flavor:
Yuchen Deng's avatar
Yuchen Deng committed
720
        return QLatin1String("msvc2013");
Joerg Bornemann's avatar
Joerg Bornemann committed
721 722
    case Abi::WindowsMsvc2015Flavor:
        return QLatin1String("msvc2015");
723 724
    case Abi::WindowsMsvc2017Flavor:
        return QLatin1String("msvc2017");
725
    case Abi::WindowsMSysFlavor:
726
        return QLatin1String("msys");
727
    case Abi::WindowsCEFlavor:
728
        return QLatin1String("ce");
729 730
    case Abi::VxWorksFlavor:
        return QLatin1String("vxworks");
James McDonnell's avatar
James McDonnell committed
731 732
    case Abi::GenericQnxFlavor:
        return QLatin1String("generic");
733
    case Abi::UnknownFlavor: // fall through!
734 735 736 737 738 739 740 741
    default:
        return QLatin1String("unknown");
    }
}

QString Abi::toString(const BinaryFormat &bf)
{
    switch (bf) {
hjk's avatar
hjk committed
742
    case ElfFormat:
743
        return QLatin1String("elf");
hjk's avatar
hjk committed
744
    case PEFormat:
745
        return QLatin1String("pe");
hjk's avatar
hjk committed
746
    case MachOFormat:
747
        return QLatin1String("mach_o");
hjk's avatar
hjk committed
748
    case RuntimeQmlFormat:
749
        return QLatin1String("qml_rt");
hjk's avatar
hjk committed
750
    case UnknownFormat: // fall through!
751 752 753 754 755 756 757 758 759 760 761 762
    default:
        return QLatin1String("unknown");
    }
}

QString Abi::toString(int w)
{
    if (w == 0)
        return QLatin1String("unknown");
    return QString::fromLatin1("%1bit").arg(w);
}

763 764 765 766 767
QList<Abi::OSFlavor> Abi::flavorsForOs(const Abi::OS &o)
{
    QList<OSFlavor> result;
    switch (o) {
    case BsdOS:
768
        return result << FreeBsdFlavor << OpenBsdFlavor << NetBsdFlavor << UnknownFlavor;
769
    case LinuxOS:
770
        return result << GenericLinuxFlavor << AndroidLinuxFlavor << UnknownFlavor;
771 772
    case DarwinOS:
        return result << GenericDarwinFlavor << UnknownFlavor;
773
    case UnixOS:
774
        return result << GenericUnixFlavor << SolarisUnixFlavor << UnknownFlavor;
775 776
    case WindowsOS:
        return result << WindowsMsvc2005Flavor << WindowsMsvc2008Flavor << WindowsMsvc2010Flavor
Joerg Bornemann's avatar
Joerg Bornemann committed
777
                      << WindowsMsvc2012Flavor << WindowsMsvc2013Flavor << WindowsMsvc2015Flavor
778
                      << WindowsMsvc2017Flavor
Joerg Bornemann's avatar
Joerg Bornemann committed
779
                      << WindowsMSysFlavor << WindowsCEFlavor << UnknownFlavor;
780
    case VxWorks:
781
        return result << VxWorksFlavor << UnknownFlavor;
James McDonnell's avatar
James McDonnell committed
782 783
    case QnxOS:
        return result << GenericQnxFlavor << UnknownFlavor;
784 785 786 787 788 789 790
    case UnknownOS:
        return result << UnknownFlavor;
    default:
        break;
    }
    return result;
}
791 792 793 794

Abi Abi::hostAbi()
{
    Architecture arch = QTC_CPU; // define set by qmake
hjk's avatar
hjk committed
795 796 797
    OS os = UnknownOS;
    OSFlavor subos = UnknownFlavor;
    BinaryFormat format = UnknownFormat;
798 799

#if defined (Q_OS_WIN)
hjk's avatar
hjk committed
800
    os = WindowsOS;
801 802 803
#if _MSC_VER >= 1910
    subos = WindowsMsvc2017Flavor;
#elif _MSC_VER == 1900
804 805
    subos = WindowsMsvc2015Flavor;
#elif _MSC_VER == 1800
Yuchen Deng's avatar
Yuchen Deng committed
806 807
    subos = WindowsMsvc2013Flavor;
#elif _MSC_VER == 1700
Tobias Hunger's avatar
Tobias Hunger committed
808 809
    subos = WindowsMsvc2012Flavor;
#elif _MSC_VER == 1600
810 811 812 813 814
    subos = WindowsMsvc2010Flavor;
#elif _MSC_VER == 1500
    subos = WindowsMsvc2008Flavor;
#elif _MSC_VER == 1400
    subos = WindowsMsvc2005Flavor;
815
#elif defined (Q_CC_MINGW)
816 817
    subos = WindowsMSysFlavor;
#endif
hjk's avatar
hjk committed
818
    format = PEFormat;
819
#elif defined (Q_OS_LINUX)
hjk's avatar
hjk committed
820 821 822
    os = LinuxOS;
    subos = GenericLinuxFlavor;
    format = ElfFormat;
823 824 825
#elif defined (Q_OS_DARWIN)
    os = DarwinOS;
    subos = GenericDarwinFlavor;
hjk's avatar
hjk committed
826
    format = MachOFormat;
827 828 829 830 831 832 833 834 835 836
#elif defined (Q_OS_BSD4)
    os = BsdOS;
# if defined (Q_OS_FREEBSD)
    subos = FreeBsdFlavor;
# elif defined (Q_OS_NETBSD)
    subos = NetBsdFlavor;
# elif defined (Q_OS_OPENBSD)
    subos = OpenBsdFlavor;
# endif
    format = ElfFormat;
837 838
#endif

Tobias Hunger's avatar
Tobias Hunger committed
839 840 841 842 843
    const Abi result(arch, os, subos, format, QSysInfo::WordSize);
    if (!result.isValid())
        qWarning("Unable to completely determine the host ABI (%s).",
                 qPrintable(result.toString()));
    return result;
844 845
}

Tobias Hunger's avatar
Tobias Hunger committed
846
QList<Abi> Abi::abisOfBinary(const Utils::FileName &path)
847
{
848
    QList<Abi> tmp;
849
    if (path.isEmpty())
850
        return tmp;
851

Tobias Hunger's avatar
Tobias Hunger committed
852
    QFile f(path.toString());
853
    if (!f.exists())
854
        return tmp;
855

Montel Laurent's avatar
Montel Laurent committed
856 857 858
    if (!f.open(QFile::ReadOnly))
        return tmp;

859
    QByteArray data = f.read(1024);
860
    if (data.size() >= 67
Tobias Hunger's avatar
Tobias Hunger committed
861 862 863
            && getUint8(data, 0) == '!' && getUint8(data, 1) == '<' && getUint8(data, 2) == 'a'
            && getUint8(data, 3) == 'r' && getUint8(data, 4) == 'c' && getUint8(data, 5) == 'h'
            && getUint8(data, 6) == '>' && getUint8(data, 7) == 0x0a) {
864
        // We got an ar file: possibly a static lib for ELF, PE or Mach-O
865 866 867 868 869

        data = data.mid(8); // Cut of ar file magic
        quint64 offset = 8;

        while (!data.isEmpty()) {
Tobias Hunger's avatar
Tobias Hunger committed
870
            if ((getUint8(data, 58) != 0x60 || getUint8(data, 59) != 0x0a)) {
Tobias Hunger's avatar
Tobias Hunger committed
871
                qWarning() << path.toString() << ": Thought it was an ar-file, but it is not!";
872
                break;
873
            }
874

875 876 877
            const QString fileName = QString::fromLocal8Bit(data.mid(0, 16));
            quint64 fileNameOffset = 0;
            if (fileName.startsWith(QLatin1String("#1/")))
878
                fileNameOffset = fileName.midRef(3).toInt();
879
            const QString fileLength = QString::fromLatin1(data.mid(48, 10));
880

Tobias Hunger's avatar
Tobias Hunger committed
881
            int toSkip = 60 + fileNameOffset;
882
            offset += fileLength.toInt() + 60 /* header */;
883 884 885 886 887

            tmp.append(abiOf(data.mid(toSkip)));
            if (tmp.isEmpty() && fileName == QLatin1String("/0              "))
                tmp = parseCoffHeader(data.mid(toSkip, 20)); // This might be windws...

888 889
            if (!tmp.isEmpty()
                    && tmp.at(0).binaryFormat() != Abi::MachOFormat)
890
                break;
891

892
            offset += (offset % 2); // ar is 2 byte aligned
893
            f.seek(offset);
894
            data = f.read(1024);
895
        }
896
    } else {
897
        tmp = abiOf(data);