abi.cpp 19.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/

#include "abi.h"

#include <QtCore/QCoreApplication>
Tobias Hunger's avatar
Tobias Hunger committed
37
#include <QtCore/QDebug>
38 39 40 41 42 43 44
#include <QtCore/QFile>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QSysInfo>

namespace ProjectExplorer {

45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
// --------------------------------------------------------------------------
// Helpers
// --------------------------------------------------------------------------

static Abi macAbiForCpu(quint32 type) {
    switch (type) {
    case 7: // CPU_TYPE_X86, CPU_TYPE_I386
        return Abi(Abi::X86Architecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 32);
    case 0x01000000 +  7: // CPU_TYPE_X86_64
        return Abi(Abi::X86Architecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 64);
    case 18: // CPU_TYPE_POWERPC
        return Abi(Abi::PowerPCArchitecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 32);
    case 0x01000000 + 18: // CPU_TYPE_POWERPC64
        return Abi(Abi::PowerPCArchitecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 32);
    case 12: // CPU_TYPE_ARM
        return Abi(Abi::ArmArchitecture, Abi::MacOS, Abi::GenericMacFlavor, Abi::MachOFormat, 32);
    default:
        return Abi();
    }
}

Tobias Hunger's avatar
Tobias Hunger committed
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
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
    quint16 machine = (data.at(1) << 8) + data.at(0);
    switch (machine) {
    case 0x8664: // x86_64
        arch = Abi::X86Architecture;
        width = 64;
        break;
    case 0x014c: // i386
        arch = Abi::X86Architecture;
        width = 32;
        break;
    case 0x0200: // ia64
        arch = Abi::ItaniumArchitecture;
        width = 64;
        break;
    }

    if (data.size() >= 68) {
        // Get Major and Minor Image Version from optional header fields
        quint32 image = (data.at(67) << 24) + (data.at(66) << 16) + (data.at(65) << 8) + data.at(64);
96
        if (image == 1) { // Image is 1 for mingw and higher for MSVC (4.something in some encoding)
Tobias Hunger's avatar
Tobias Hunger committed
97
            flavor = Abi::WindowsMSysFlavor;
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
        } else {
            switch (data.at(22)) {
            case 8:
                flavor = Abi::WindowsMsvc2005Flavor;
                break;
            case 9:
                flavor = Abi::WindowsMsvc2008Flavor;
                break;
            case 10:
                flavor = Abi::WindowsMsvc2010Flavor;
                break;
            default:
                // Keep unknown flavor
                break;
            }
        }
Tobias Hunger's avatar
Tobias Hunger committed
114 115 116 117 118 119 120 121
    }

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

    return result;
}

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
static QList<Abi> abiOf(const QByteArray &data)
{
    QList<Abi> result;

    if (data.size() >= 20
            && static_cast<unsigned char>(data.at(0)) == 0x7f && static_cast<unsigned char>(data.at(1)) == 'E'
            && static_cast<unsigned char>(data.at(2)) == 'L' && static_cast<unsigned char>(data.at(3)) == 'F') {
        // ELF format:
        quint16 machine = (data.at(19) << 8) + data.at(18);
        switch (machine) {
        case 3: // EM_386
            result.append(Abi(Abi::X86Architecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 32));
            break;
        case 8: // EM_MIPS
            result.append(Abi(Abi::MipsArcitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 32));
            break;
        case 20: // EM_PPC
            result.append(Abi(Abi::PowerPCArchitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 32));
            break;
        case 21: // EM_PPC64
            result.append(Abi(Abi::PowerPCArchitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 64));
            break;
        case 62: // EM_X86_64
            result.append(Abi(Abi::X86Architecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 64));
            break;
        case 50: // EM_IA_64
            result.append(Abi(Abi::ItaniumArchitecture, Abi::LinuxOS, Abi::GenericLinuxFlavor, Abi::ElfFormat, 64));
            break;
        default:
            ;;
        }
    } else if (data.size() >= 8
               && (static_cast<unsigned char>(data.at(0)) == 0xce || static_cast<unsigned char>(data.at(0)) == 0xcf)
               && static_cast<unsigned char>(data.at(1)) == 0xfa
               && static_cast<unsigned char>(data.at(2)) == 0xed && static_cast<unsigned char>(data.at(3)) == 0xfe) {
        // Mach-O format (Mac non-fat binary, 32 and 64bit magic)
        quint32 type = (data.at(7) << 24) + (data.at(6) << 16) + (data.at(5) << 8) + data.at(4);
        result.append(macAbiForCpu(type));
    } else if (data.size() >= 8
               && static_cast<unsigned char>(data.at(0)) == 0xca && static_cast<unsigned char>(data.at(1)) == 0xfe
               && static_cast<unsigned char>(data.at(2)) == 0xba && static_cast<unsigned char>(data.at(3)) == 0xbe) {
        // Mac fat binary:
        quint32 count = (data.at(4) << 24) + (data.at(5) << 16) + (data.at(6) << 8) + data.at(7);
        int pos = 8;
        for (quint32 i = 0; i < count; ++i) {
            if (data.size() <= pos + 4)
                break;

            quint32 type = (data.at(pos) << 24) + (data.at(pos + 1) << 16) + (data.at(pos + 2) << 8) + data.at(pos + 3);
            result.append(macAbiForCpu(type));
            pos += 20;
        }
    } else {
        // Windows PE
        // Windows can have its magic bytes everywhere...
177
        int pePos = data.indexOf(QByteArray("PE\0\0", 4));
Tobias Hunger's avatar
Tobias Hunger committed
178 179
        if (pePos >= 0)
            result = parseCoffHeader(data.mid(pePos + 4));
180 181 182 183 184 185 186 187
    }
    return result;
}

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

188
Abi::Abi(const Architecture &a, const OS &o,
hjk's avatar
hjk committed
189
         const OSFlavor &of, const BinaryFormat &f, unsigned char w) :
190 191 192
    m_architecture(a), m_os(o), m_osFlavor(of), m_binaryFormat(f), m_wordWidth(w)
{
    switch (m_os) {
hjk's avatar
hjk committed
193 194
    case ProjectExplorer::Abi::UnknownOS:
        m_osFlavor = UnknownFlavor;
195
        break;
hjk's avatar
hjk committed
196 197 198
    case ProjectExplorer::Abi::LinuxOS:
        if (m_osFlavor < GenericLinuxFlavor || m_osFlavor > MeegoLinuxFlavor)
            m_osFlavor = UnknownFlavor;
199
        break;
hjk's avatar
hjk committed
200 201 202
    case ProjectExplorer::Abi::MacOS:
        if (m_osFlavor < GenericMacFlavor || m_osFlavor > GenericMacFlavor)
            m_osFlavor = UnknownFlavor;
203
        break;
hjk's avatar
hjk committed
204 205 206
    case ProjectExplorer::Abi::SymbianOS:
        if (m_osFlavor < SymbianDeviceFlavor || m_osFlavor > SymbianEmulatorFlavor)
            m_osFlavor = UnknownFlavor;
207
        break;
hjk's avatar
hjk committed
208 209 210
    case ProjectExplorer::Abi::UnixOS:
        if (m_osFlavor < GenericUnixFlavor || m_osFlavor > GenericUnixFlavor)
            m_osFlavor = UnknownFlavor;
211
        break;
hjk's avatar
hjk committed
212
    case ProjectExplorer::Abi::WindowsOS:
213
        if (m_osFlavor < WindowsMsvc2005Flavor || m_osFlavor > WindowsCEFlavor)
hjk's avatar
hjk committed
214
            m_osFlavor = UnknownFlavor;
215 216 217 218 219
        break;
    }
}

Abi::Abi(const QString &abiString) :
hjk's avatar
hjk committed
220 221
    m_architecture(UnknownArchitecture), m_os(UnknownOS),
    m_osFlavor(UnknownFlavor), m_binaryFormat(UnknownFormat), m_wordWidth(0)
222 223 224 225
{
    QStringList abiParts = abiString.split(QLatin1Char('-'));
    if (abiParts.count() >= 1) {
        if (abiParts.at(0) == QLatin1String("unknown"))
hjk's avatar
hjk committed
226
            m_architecture = UnknownArchitecture;
227
        else if (abiParts.at(0) == QLatin1String("arm"))
hjk's avatar
hjk committed
228
            m_architecture = ArmArchitecture;
229
        else if (abiParts.at(0) == QLatin1String("x86"))
hjk's avatar
hjk committed
230
            m_architecture = X86Architecture;
231
        else if (abiParts.at(0) == QLatin1String("mips"))
hjk's avatar
hjk committed
232
            m_architecture = MipsArcitecture;
233
        else if (abiParts.at(0) == QLatin1String("ppc"))
hjk's avatar
hjk committed
234
            m_architecture = PowerPCArchitecture;
235
        else if (abiParts.at(0) == QLatin1String("itanium"))
hjk's avatar
hjk committed
236
            m_architecture = ItaniumArchitecture;
237 238 239 240 241 242
        else
            return;
    }

    if (abiParts.count() >= 2) {
        if (abiParts.at(1) == QLatin1String("unknown"))
hjk's avatar
hjk committed
243
            m_os = UnknownOS;
244
        else if (abiParts.at(1) == QLatin1String("linux"))
hjk's avatar
hjk committed
245
            m_os = LinuxOS;
246
        else if (abiParts.at(1) == QLatin1String("macos"))
hjk's avatar
hjk committed
247
            m_os = MacOS;
248
        else if (abiParts.at(1) == QLatin1String("symbian"))
hjk's avatar
hjk committed
249
            m_os = SymbianOS;
250
        else if (abiParts.at(1) == QLatin1String("unix"))
hjk's avatar
hjk committed
251
            m_os = UnixOS;
252
        else if (abiParts.at(1) == QLatin1String("windows"))
hjk's avatar
hjk committed
253
            m_os = WindowsOS;
254 255 256 257 258 259
        else
            return;
    }

    if (abiParts.count() >= 3) {
        if (abiParts.at(2) == QLatin1String("unknown"))
hjk's avatar
hjk committed
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
            m_osFlavor = UnknownFlavor;
        else if (abiParts.at(2) == QLatin1String("generic") && m_os == LinuxOS)
            m_osFlavor = GenericLinuxFlavor;
        else if (abiParts.at(2) == QLatin1String("maemo") && m_os == LinuxOS)
            m_osFlavor = MaemoLinuxFlavor;
        else if (abiParts.at(2) == QLatin1String("meego") && m_os == LinuxOS)
            m_osFlavor = MeegoLinuxFlavor;
        else if (abiParts.at(2) == QLatin1String("generic") && m_os == MacOS)
            m_osFlavor = GenericMacFlavor;
        else if (abiParts.at(2) == QLatin1String("device") && m_os == SymbianOS)
            m_osFlavor = SymbianDeviceFlavor;
        else if (abiParts.at(2) == QLatin1String("emulator") && m_os == SymbianOS)
            m_osFlavor = SymbianEmulatorFlavor;
        else if (abiParts.at(2) == QLatin1String("generic") && m_os == UnixOS)
            m_osFlavor = GenericUnixFlavor;
275 276 277 278 279 280
        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;
hjk's avatar
hjk committed
281 282 283 284
        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;
285 286 287 288 289 290
        else
            return;
    }

    if (abiParts.count() >= 4) {
        if (abiParts.at(3) == QLatin1String("unknown"))
hjk's avatar
hjk committed
291
            m_binaryFormat = UnknownFormat;
292
        else if (abiParts.at(3) == QLatin1String("elf"))
hjk's avatar
hjk committed
293
            m_binaryFormat = ElfFormat;
294
        else if (abiParts.at(3) == QLatin1String("pe"))
hjk's avatar
hjk committed
295
            m_binaryFormat = PEFormat;
296
        else if (abiParts.at(3) == QLatin1String("mach_o"))
hjk's avatar
hjk committed
297
            m_binaryFormat = MachOFormat;
298
        else if (abiParts.at(3) == QLatin1String("qml_rt"))
hjk's avatar
hjk committed
299
            m_binaryFormat = RuntimeQmlFormat;
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
        else
            return;
    }

    if (abiParts.count() >= 5) {
        const QString &bits = abiParts.at(4);
        if (!bits.endsWith(QLatin1String("bit")))
            return;

        bool ok = false;
        int bitCount = bits.left(bits.count() - 3).toInt(&ok);
        if (!ok)
            return;
        if (bitCount != 8 && bitCount != 16 && bitCount != 32 && bitCount != 64)
            return;
        m_wordWidth = bitCount;
    }
}

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);

    return dn.join(QLatin1String("-"));
}

Tobias Hunger's avatar
Tobias Hunger committed
331 332 333 334 335
bool Abi::operator != (const Abi &other) const
{
    return !operator ==(other);
}

336 337 338 339 340 341 342 343 344 345 346
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
{
hjk's avatar
hjk committed
347 348 349 350
    return (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)
351 352 353 354 355
            && ((wordWidth() == other.wordWidth() && wordWidth() != 0) || other.wordWidth() == 0);
}

bool Abi::isValid() const
{
hjk's avatar
hjk committed
356 357 358 359
    return m_architecture != UnknownArchitecture
            && m_os != UnknownOS
            && m_osFlavor != UnknownFlavor
            && m_binaryFormat != UnknownFormat
360 361 362 363 364 365
            && m_wordWidth != 0;
}

QString Abi::toString(const Architecture &a)
{
    switch (a) {
hjk's avatar
hjk committed
366
    case ArmArchitecture:
367
        return QLatin1String("arm");
hjk's avatar
hjk committed
368
    case X86Architecture:
369
        return QLatin1String("x86");
hjk's avatar
hjk committed
370
    case MipsArcitecture:
371
        return QLatin1String("mips");
hjk's avatar
hjk committed
372
    case PowerPCArchitecture:
373
        return QLatin1String("ppc");
hjk's avatar
hjk committed
374
    case ItaniumArchitecture:
375
        return QLatin1String("itanium");
hjk's avatar
hjk committed
376
    case UnknownArchitecture: // fall through!
377 378 379 380 381 382 383 384
    default:
        return QLatin1String("unknown");
    }
}

QString Abi::toString(const OS &o)
{
    switch (o) {
hjk's avatar
hjk committed
385
    case LinuxOS:
386
        return QLatin1String("linux");
hjk's avatar
hjk committed
387
    case MacOS:
388
        return QLatin1String("macos");
hjk's avatar
hjk committed
389
    case SymbianOS:
390
        return QLatin1String("symbian");
hjk's avatar
hjk committed
391
    case UnixOS:
392
        return QLatin1String("unix");
hjk's avatar
hjk committed
393
    case WindowsOS:
394
        return QLatin1String("windows");
hjk's avatar
hjk committed
395
    case UnknownOS: // fall through!
396 397 398 399 400
    default:
        return QLatin1String("unknown");
    };
}

hjk's avatar
hjk committed
401
QString Abi::toString(const OSFlavor &of)
402 403
{
    switch (of) {
hjk's avatar
hjk committed
404
    case ProjectExplorer::Abi::GenericLinuxFlavor:
405
        return QLatin1String("generic");
hjk's avatar
hjk committed
406
    case ProjectExplorer::Abi::MaemoLinuxFlavor:
407
        return QLatin1String("maemo");
hjk's avatar
hjk committed
408
    case ProjectExplorer::Abi::HarmattanLinuxFlavor:
409
        return QLatin1String("harmattan");
hjk's avatar
hjk committed
410
    case ProjectExplorer::Abi::MeegoLinuxFlavor:
411
        return QLatin1String("meego");
hjk's avatar
hjk committed
412
    case ProjectExplorer::Abi::GenericMacFlavor:
413
        return QLatin1String("generic");
hjk's avatar
hjk committed
414
    case ProjectExplorer::Abi::SymbianDeviceFlavor:
415
        return QLatin1String("device");
hjk's avatar
hjk committed
416
    case ProjectExplorer::Abi::SymbianEmulatorFlavor:
417
        return QLatin1String("emulator");
hjk's avatar
hjk committed
418
    case ProjectExplorer::Abi::GenericUnixFlavor:
419
        return QLatin1String("generic");
420 421 422 423 424 425
    case ProjectExplorer::Abi::WindowsMsvc2005Flavor:
        return QLatin1String("msvc2005");
    case ProjectExplorer::Abi::WindowsMsvc2008Flavor:
        return QLatin1String("msvc2008");
    case ProjectExplorer::Abi::WindowsMsvc2010Flavor:
        return QLatin1String("msvc2010");
hjk's avatar
hjk committed
426
    case ProjectExplorer::Abi::WindowsMSysFlavor:
427
        return QLatin1String("msys");
hjk's avatar
hjk committed
428
    case ProjectExplorer::Abi::WindowsCEFlavor:
429
        return QLatin1String("ce");
430
    case ProjectExplorer::Abi::UnknownFlavor: // fall through!
431 432 433 434 435 436 437 438
    default:
        return QLatin1String("unknown");
    }
}

QString Abi::toString(const BinaryFormat &bf)
{
    switch (bf) {
hjk's avatar
hjk committed
439
    case ElfFormat:
440
        return QLatin1String("elf");
hjk's avatar
hjk committed
441
    case PEFormat:
442
        return QLatin1String("pe");
hjk's avatar
hjk committed
443
    case MachOFormat:
444
        return QLatin1String("mach_o");
hjk's avatar
hjk committed
445
    case RuntimeQmlFormat:
446
        return QLatin1String("qml_rt");
hjk's avatar
hjk committed
447
    case UnknownFormat: // fall through!
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
    default:
        return QLatin1String("unknown");
    }
}

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


Abi Abi::hostAbi()
{
    Architecture arch = QTC_CPU; // define set by qmake
hjk's avatar
hjk committed
464 465 466
    OS os = UnknownOS;
    OSFlavor subos = UnknownFlavor;
    BinaryFormat format = UnknownFormat;
467 468

#if defined (Q_OS_WIN)
hjk's avatar
hjk committed
469
    os = WindowsOS;
470 471 472 473 474 475 476 477 478
#if _MSC_VER == 1600
    subos = WindowsMsvc2010Flavor;
#elif _MSC_VER == 1500
    subos = WindowsMsvc2008Flavor;
#elif _MSC_VER == 1400
    subos = WindowsMsvc2005Flavor;
#elif defined (mingw32)
    subos = WindowsMSysFlavor;
#endif
hjk's avatar
hjk committed
479
    format = PEFormat;
480
#elif defined (Q_OS_LINUX)
hjk's avatar
hjk committed
481 482 483
    os = LinuxOS;
    subos = GenericLinuxFlavor;
    format = ElfFormat;
484
#elif defined (Q_OS_MAC)
hjk's avatar
hjk committed
485 486 487
    os = MacOS;
    subos = GenericMacFlavor;
    format = MachOFormat;
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
#endif

    return Abi(arch, os, subos, format, QSysInfo::WordSize);
}

QList<Abi> Abi::abisOfBinary(const QString &path)
{
    QList<Abi> result;
    if (path.isEmpty())
        return result;

    QFile f(path);
    if (!f.exists())
        return result;

Tobias Hunger's avatar
Tobias Hunger committed
503 504
    bool windowsStatic = path.endsWith(QLatin1String(".lib"));

505 506
    f.open(QFile::ReadOnly);
    QByteArray data = f.read(1024);
507 508 509 510 511 512 513 514 515 516 517
    if (data.size() >= 67
            && static_cast<unsigned char>(data.at(0)) == '!' && static_cast<unsigned char>(data.at(1)) == '<'
            && static_cast<unsigned char>(data.at(2)) == 'a' && static_cast<unsigned char>(data.at(3)) == 'r'
            && static_cast<unsigned char>(data.at(4)) == 'c' && static_cast<unsigned char>(data.at(5)) == 'h'
            && static_cast<unsigned char>(data.at(6)) == '>' && static_cast<unsigned char>(data.at(7)) == 0x0a) {
        // We got an ar file: possibly a static lib for ELF or Mach-O

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

        while (!data.isEmpty()) {
Tobias Hunger's avatar
Tobias Hunger committed
518
            if ((data.at(58) != 0x60 || data.at(59) != 0x0a)) {
519
                qWarning() << path << ": Thought it was an ar-file, but it is not!";
520
                break;
521
            }
522

523 524 525 526 527
            const QString fileName = QString::fromLocal8Bit(data.mid(0, 16));
            quint64 fileNameOffset = 0;
            if (fileName.startsWith(QLatin1String("#1/")))
                fileNameOffset = fileName.mid(3).toInt();
            const QString fileLength = QString::fromAscii(data.mid(48, 10));
528

Tobias Hunger's avatar
Tobias Hunger committed
529
            int toSkip = 60 + fileNameOffset;
530
            offset += fileLength.toInt() + 60 /* header */;
Tobias Hunger's avatar
Tobias Hunger committed
531 532 533 534 535 536
            if (windowsStatic) {
                if (fileName == QLatin1String("/0              "))
                    result = parseCoffHeader(data.mid(toSkip, 20));
            } else {
                result = abiOf(data.mid(toSkip));
            }
537
            if (!result.isEmpty())
538
                break;
539

Tobias Hunger's avatar
Tobias Hunger committed
540
            f.seek(offset + (offset % 2)); // ar is 2 byte alligned
541
            data = f.read(1024);
542
        }
543 544
    } else {
        result = abiOf(data);
545
    }
546 547
    f.close();

548 549 550 551
    return result;
}

} // namespace ProjectExplorer