abi.cpp 47.7 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) {
Orgad Shaneh's avatar
Orgad Shaneh committed
325
    case UnknownOS:
hjk's avatar
hjk committed
326
        m_osFlavor = UnknownFlavor;
327
        break;
Orgad Shaneh's avatar
Orgad Shaneh committed
328
    case LinuxOS:
329
        if (m_osFlavor < GenericLinuxFlavor || m_osFlavor > AndroidLinuxFlavor)
hjk's avatar
hjk committed
330
            m_osFlavor = UnknownFlavor;
331
        break;
Orgad Shaneh's avatar
Orgad Shaneh committed
332
    case BsdOS:
333 334
        if (m_osFlavor < FreeBsdFlavor || m_osFlavor > OpenBsdFlavor)
            m_osFlavor = UnknownFlavor;
335
        break;
Orgad Shaneh's avatar
Orgad Shaneh committed
336
    case DarwinOS:
337
        if (m_osFlavor < GenericDarwinFlavor || m_osFlavor > GenericDarwinFlavor)
hjk's avatar
hjk committed
338
            m_osFlavor = UnknownFlavor;
339
        break;
Orgad Shaneh's avatar
Orgad Shaneh committed
340
    case UnixOS:
341
        if (m_osFlavor < GenericUnixFlavor || m_osFlavor > SolarisUnixFlavor)
hjk's avatar
hjk committed
342
            m_osFlavor = UnknownFlavor;
343
        break;
Orgad Shaneh's avatar
Orgad Shaneh committed
344
    case WindowsOS:
345
        if (m_osFlavor < WindowsMsvc2005Flavor || m_osFlavor > WindowsCEFlavor)
hjk's avatar
hjk committed
346
            m_osFlavor = UnknownFlavor;
347
        break;
Orgad Shaneh's avatar
Orgad Shaneh committed
348
    case VxWorks:
349 350
        if (m_osFlavor != VxWorksFlavor)
            m_osFlavor = VxWorksFlavor;
351
        break;
Orgad Shaneh's avatar
Orgad Shaneh committed
352
    case QnxOS:
James McDonnell's avatar
James McDonnell committed
353 354
        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
{
Orgad Shaneh's avatar
Orgad Shaneh committed
363
    const QVector<QStringRef> abiParts = abiString.splitRef('-');
364
    if (abiParts.count() >= 1) {
Orgad Shaneh's avatar
Orgad Shaneh committed
365
        if (abiParts.at(0) == "unknown")
hjk's avatar
hjk committed
366
            m_architecture = UnknownArchitecture;
Orgad Shaneh's avatar
Orgad Shaneh committed
367
        else if (abiParts.at(0) == "arm")
hjk's avatar
hjk committed
368
            m_architecture = ArmArchitecture;
Orgad Shaneh's avatar
Orgad Shaneh committed
369
        else if (abiParts.at(0) == "aarch64")
370
            m_architecture = ArmArchitecture;
Orgad Shaneh's avatar
Orgad Shaneh committed
371
        else if (abiParts.at(0) == "x86")
hjk's avatar
hjk committed
372
            m_architecture = X86Architecture;
Orgad Shaneh's avatar
Orgad Shaneh committed
373
        else if (abiParts.at(0) == "mips")
Tobias Hunger's avatar
Tobias Hunger committed
374
            m_architecture = MipsArchitecture;
Orgad Shaneh's avatar
Orgad Shaneh committed
375
        else if (abiParts.at(0) == "ppc")
hjk's avatar
hjk committed
376
            m_architecture = PowerPCArchitecture;
Orgad Shaneh's avatar
Orgad Shaneh committed
377
        else if (abiParts.at(0) == "itanium")
hjk's avatar
hjk committed
378
            m_architecture = ItaniumArchitecture;
Orgad Shaneh's avatar
Orgad Shaneh committed
379
        else if (abiParts.at(0) == "sh")
Tobias Hunger's avatar
Tobias Hunger committed
380
            m_architecture = ShArchitecture;
381 382 383 384 385
        else
            return;
    }

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

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

    if (abiParts.count() >= 4) {
Orgad Shaneh's avatar
Orgad Shaneh committed
453
        if (abiParts.at(3) == "unknown")
hjk's avatar
hjk committed
454
            m_binaryFormat = UnknownFormat;
Orgad Shaneh's avatar
Orgad Shaneh committed
455
        else if (abiParts.at(3) == "elf")
hjk's avatar
hjk committed
456
            m_binaryFormat = ElfFormat;
Orgad Shaneh's avatar
Orgad Shaneh committed
457
        else if (abiParts.at(3) == "pe")
hjk's avatar
hjk committed
458
            m_binaryFormat = PEFormat;
Orgad Shaneh's avatar
Orgad Shaneh committed
459
        else if (abiParts.at(3) == "mach_o")
hjk's avatar
hjk committed
460
            m_binaryFormat = MachOFormat;
Orgad Shaneh's avatar
Orgad Shaneh committed
461
        else if (abiParts.at(3) == "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);
Orgad Shaneh's avatar
Orgad Shaneh committed
469
        if (!bits.endsWith("bit"))
470 471 472
            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();

Orgad Shaneh's avatar
Orgad Shaneh committed
490
    const QVector<QStringRef> parts = machine.splitRef(QRegExp("[ /-]"));
491

Orgad Shaneh's avatar
Orgad Shaneh committed
492 493 494 495
    Architecture arch = UnknownArchitecture;
    OS os = UnknownOS;
    OSFlavor flavor = UnknownFlavor;
    BinaryFormat format = UnknownFormat;
496
    unsigned char width = 0;
497 498
    int unknownCount = 0;

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

Orgad Shaneh's avatar
Orgad Shaneh committed
590
    return dn.join('-');
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
    // Generic match: If stuff is identical or the other side is unknown, then this is a match.
    bool isCompat = (architecture() == other.architecture() || other.architecture() == UnknownArchitecture)
                     && (os() == other.os() || other.os() == UnknownOS)
                     && (osFlavor() == other.osFlavor() || other.osFlavor() == UnknownFlavor)
                     && (binaryFormat() == other.binaryFormat() || other.binaryFormat() == UnknownFormat)
614
                     && ((wordWidth() == other.wordWidth() && wordWidth() != 0) || other.wordWidth() == 0);
615

616 617 618
    // *-linux-generic-* is compatible with *-linux-* (both ways): This is for the benefit of
    // people building Qt themselves using e.g. a meego toolchain.
    //
619
    // We leave it to the specific targets to filter out the tool chains that do not
620
    // work for them.
621
    if (!isCompat && (architecture() == other.architecture() || other.architecture() == UnknownArchitecture)
Tobias Hunger's avatar
Tobias Hunger committed
622
                  && ((os() == other.os()) && (os() == LinuxOS))
623
                  && (osFlavor() == GenericLinuxFlavor || other.osFlavor() == GenericLinuxFlavor)
624 625 626 627 628 629 630 631 632 633 634 635 636
                  && (binaryFormat() == other.binaryFormat() || other.binaryFormat() == UnknownFormat)
                  && ((wordWidth() == other.wordWidth() && wordWidth() != 0) || other.wordWidth() == 0)) {
        isCompat = true;
    }

    // Make Android matching more strict than the generic Linux matches so far:
    if (isCompat && (osFlavor() == AndroidLinuxFlavor || other.osFlavor() == AndroidLinuxFlavor))
        isCompat = (architecture() == other.architecture()) &&  (osFlavor() == other.osFlavor());

    // MSVC2017 is compatible with MSVC2015
    if (!isCompat
            && ((osFlavor() == WindowsMsvc2015Flavor && other.osFlavor() == WindowsMsvc2017Flavor)
                || (osFlavor() == WindowsMsvc2017Flavor && other.osFlavor() == WindowsMsvc2015Flavor))) {
637
        isCompat = true;
638
    }
639
    return isCompat;
640 641 642 643
}

bool Abi::isValid() const
{
hjk's avatar
hjk committed
644 645 646 647
    return m_architecture != UnknownArchitecture
            && m_os != UnknownOS
            && m_osFlavor != UnknownFlavor
            && m_binaryFormat != UnknownFormat
648 649 650
            && m_wordWidth != 0;
}

Tobias Hunger's avatar
Tobias Hunger committed
651 652 653 654 655 656 657 658 659
bool Abi::isNull() const
{
    return m_architecture == UnknownArchitecture
            && m_os == UnknownOS
            && m_osFlavor == UnknownFlavor
            && m_binaryFormat == UnknownFormat
            && m_wordWidth == 0;
}

660 661 662
QString Abi::toString(const Architecture &a)
{
    switch (a) {
hjk's avatar
hjk committed
663
    case ArmArchitecture:
664
        return QLatin1String("arm");
hjk's avatar
hjk committed
665
    case X86Architecture:
666
        return QLatin1String("x86");
Tobias Hunger's avatar
Tobias Hunger committed
667
    case MipsArchitecture:
668
        return QLatin1String("mips");
hjk's avatar
hjk committed
669
    case PowerPCArchitecture:
670
        return QLatin1String("ppc");
hjk's avatar
hjk committed
671
    case ItaniumArchitecture:
672
        return QLatin1String("itanium");
Tobias Hunger's avatar
Tobias Hunger committed
673
    case ShArchitecture:
Tobias Hunger's avatar
Tobias Hunger committed
674
        return QLatin1String("sh");
hjk's avatar
hjk committed
675
    case UnknownArchitecture: // fall through!
676 677 678 679 680 681 682 683
    default:
        return QLatin1String("unknown");
    }
}

QString Abi::toString(const OS &o)
{
    switch (o) {
hjk's avatar
hjk committed
684
    case LinuxOS:
685
        return QLatin1String("linux");
686 687
    case BsdOS:
        return QLatin1String("bsd");
688 689
    case DarwinOS:
        return QLatin1String("darwin");
hjk's avatar
hjk committed
690
    case UnixOS:
691
        return QLatin1String("unix");
hjk's avatar
hjk committed
692
    case WindowsOS:
693
        return QLatin1String("windows");
694 695
    case VxWorks:
        return QLatin1String("vxworks");
James McDonnell's avatar
James McDonnell committed
696 697
    case QnxOS:
        return QLatin1String("qnx");
hjk's avatar
hjk committed
698
    case UnknownOS: // fall through!
699 700 701 702 703
    default:
        return QLatin1String("unknown");
    };
}

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

QString Abi::toString(const BinaryFormat &bf)
{
    switch (bf) {
hjk's avatar
hjk committed
754
    case ElfFormat:
755
        return QLatin1String("elf");
hjk's avatar
hjk committed
756
    case PEFormat:
757
        return QLatin1String("pe");
hjk's avatar
hjk committed
758
    case MachOFormat:
759
        return QLatin1String("mach_o");
hjk's avatar
hjk committed
760
    case RuntimeQmlFormat:
761
        return QLatin1String("qml_rt");
hjk's avatar
hjk committed
762
    case UnknownFormat: // fall through!
763 764 765 766 767 768 769 770 771 772 773 774
    default:
        return QLatin1String("unknown");
    }
}

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

775 776 777 778 779
QList<Abi::OSFlavor> Abi::flavorsForOs(const Abi::OS &o)
{
    QList<OSFlavor> result;
    switch (o) {
    case BsdOS:
780
        return result << FreeBsdFlavor << OpenBsdFlavor << NetBsdFlavor << UnknownFlavor;
781
    case LinuxOS:
782
        return result << GenericLinuxFlavor << AndroidLinuxFlavor << UnknownFlavor;
783 784
    case DarwinOS:
        return result << GenericDarwinFlavor << UnknownFlavor;
785
    case UnixOS:
786
        return result << GenericUnixFlavor << SolarisUnixFlavor << UnknownFlavor;
787 788
    case WindowsOS:
        return result << WindowsMsvc2005Flavor << WindowsMsvc2008Flavor << WindowsMsvc2010Flavor
Joerg Bornemann's avatar
Joerg Bornemann committed
789
                      << WindowsMsvc2012Flavor << WindowsMsvc2013Flavor << WindowsMsvc2015Flavor
790
                      << WindowsMsvc2017Flavor
Joerg Bornemann's avatar
Joerg Bornemann committed
791
                      << WindowsMSysFlavor << WindowsCEFlavor << UnknownFlavor;
792
    case VxWorks:
793
        return result << VxWorksFlavor << UnknownFlavor;
James McDonnell's avatar
James McDonnell committed
794 795
    case QnxOS:
        return result << GenericQnxFlavor << UnknownFlavor;
796 797 798 799 800 801 802
    case UnknownOS:
        return result << UnknownFlavor;
    default:
        break;
    }
    return result;
}
803

804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825
Abi::OSFlavor Abi::flavorForMsvcVersion(int version)
{
    if (version >= 1910)
        return WindowsMsvc2017Flavor;
    switch (version) {
    case 1900:
        return WindowsMsvc2015Flavor;
    case 1800:
        return WindowsMsvc2013Flavor;
    case 1700:
        return WindowsMsvc2012Flavor;
    case 1600:
        return WindowsMsvc2010Flavor;
    case 1500:
        return WindowsMsvc2008Flavor;
    case 1400:
        return WindowsMsvc2005Flavor;
    default:
        return WindowsMSysFlavor;
    }
}

826 827 828
Abi Abi::hostAbi()
{
    Architecture arch = QTC_CPU; // define set by qmake
hjk's avatar
hjk committed
829 830 831
    OS os = UnknownOS;
    OSFlavor subos = UnknownFlavor;
    BinaryFormat format = UnknownFormat;
832 833

#if defined (Q_OS_WIN)
hjk's avatar
hjk committed
834
    os = WindowsOS;
835 836
#ifdef _MSC_VER
    subos = flavorForMsvcVersion(_MSC_VER);
837
#elif defined (Q_CC_MINGW)
838 839
    subos = WindowsMSysFlavor;
#endif
hjk's avatar
hjk committed
840
    format = PEFormat;
841
#elif defined (Q_OS_LINUX)
hjk's avatar
hjk committed
842 843 844
    os = LinuxOS;
    subos = GenericLinuxFlavor;
    format = ElfFormat;
845 846 847
#elif defined (Q_OS_DARWIN)
    os = DarwinOS;
    subos = GenericDarwinFlavor;
hjk's avatar
hjk committed
848
    format = MachOFormat;
849 850 851 852 853 854 855 856 857 858
#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;
859 860
#endif

Tobias Hunger's avatar
Tobias Hunger committed
861 862 863 864 865
    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;
866 867
}

Tobias Hunger's avatar
Tobias Hunger committed
868
QList<Abi> Abi::abisOfBinary(const Utils::FileName &path)
869
{
870
    QList<Abi> tmp;
871
    if (path.isEmpty())
872
        return tmp;
873

Tobias Hunger's avatar
Tobias Hunger committed
874
    QFile f(path.toString());
875
    if (!f.exists())