abi.cpp 18.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 96 97 98 99 100 101 102 103 104 105 106 107
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);
        if (image == 1) // Image is 1 for mingw and higher for MSVC (4.something in some encoding)
            flavor = Abi::WindowsMSysFlavor;
        else
            flavor = Abi::WindowsMsvcFlavor;
    }

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

    return result;
}

108 109 110 111 112 113 114 115 116 117 118 119 120 121 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
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...
163
        int pePos = data.indexOf(QByteArray("PE\0\0", 4));
Tobias Hunger's avatar
Tobias Hunger committed
164 165
        if (pePos >= 0)
            result = parseCoffHeader(data.mid(pePos + 4));
166 167 168 169 170 171 172 173
    }
    return result;
}

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

174
Abi::Abi(const Architecture &a, const OS &o,
hjk's avatar
hjk committed
175
         const OSFlavor &of, const BinaryFormat &f, unsigned char w) :
176 177 178
    m_architecture(a), m_os(o), m_osFlavor(of), m_binaryFormat(f), m_wordWidth(w)
{
    switch (m_os) {
hjk's avatar
hjk committed
179 180
    case ProjectExplorer::Abi::UnknownOS:
        m_osFlavor = UnknownFlavor;
181
        break;
hjk's avatar
hjk committed
182 183 184
    case ProjectExplorer::Abi::LinuxOS:
        if (m_osFlavor < GenericLinuxFlavor || m_osFlavor > MeegoLinuxFlavor)
            m_osFlavor = UnknownFlavor;
185
        break;
hjk's avatar
hjk committed
186 187 188
    case ProjectExplorer::Abi::MacOS:
        if (m_osFlavor < GenericMacFlavor || m_osFlavor > GenericMacFlavor)
            m_osFlavor = UnknownFlavor;
189
        break;
hjk's avatar
hjk committed
190 191 192
    case ProjectExplorer::Abi::SymbianOS:
        if (m_osFlavor < SymbianDeviceFlavor || m_osFlavor > SymbianEmulatorFlavor)
            m_osFlavor = UnknownFlavor;
193
        break;
hjk's avatar
hjk committed
194 195 196
    case ProjectExplorer::Abi::UnixOS:
        if (m_osFlavor < GenericUnixFlavor || m_osFlavor > GenericUnixFlavor)
            m_osFlavor = UnknownFlavor;
197
        break;
hjk's avatar
hjk committed
198 199 200
    case ProjectExplorer::Abi::WindowsOS:
        if (m_osFlavor < WindowsMsvcFlavor || m_osFlavor > WindowsCEFlavor)
            m_osFlavor = UnknownFlavor;
201 202 203 204 205
        break;
    }
}

Abi::Abi(const QString &abiString) :
hjk's avatar
hjk committed
206 207
    m_architecture(UnknownArchitecture), m_os(UnknownOS),
    m_osFlavor(UnknownFlavor), m_binaryFormat(UnknownFormat), m_wordWidth(0)
208 209 210 211
{
    QStringList abiParts = abiString.split(QLatin1Char('-'));
    if (abiParts.count() >= 1) {
        if (abiParts.at(0) == QLatin1String("unknown"))
hjk's avatar
hjk committed
212
            m_architecture = UnknownArchitecture;
213
        else if (abiParts.at(0) == QLatin1String("arm"))
hjk's avatar
hjk committed
214
            m_architecture = ArmArchitecture;
215
        else if (abiParts.at(0) == QLatin1String("x86"))
hjk's avatar
hjk committed
216
            m_architecture = X86Architecture;
217
        else if (abiParts.at(0) == QLatin1String("mips"))
hjk's avatar
hjk committed
218
            m_architecture = MipsArcitecture;
219
        else if (abiParts.at(0) == QLatin1String("ppc"))
hjk's avatar
hjk committed
220
            m_architecture = PowerPCArchitecture;
221
        else if (abiParts.at(0) == QLatin1String("itanium"))
hjk's avatar
hjk committed
222
            m_architecture = ItaniumArchitecture;
223 224 225 226 227 228
        else
            return;
    }

    if (abiParts.count() >= 2) {
        if (abiParts.at(1) == QLatin1String("unknown"))
hjk's avatar
hjk committed
229
            m_os = UnknownOS;
230
        else if (abiParts.at(1) == QLatin1String("linux"))
hjk's avatar
hjk committed
231
            m_os = LinuxOS;
232
        else if (abiParts.at(1) == QLatin1String("macos"))
hjk's avatar
hjk committed
233
            m_os = MacOS;
234
        else if (abiParts.at(1) == QLatin1String("symbian"))
hjk's avatar
hjk committed
235
            m_os = SymbianOS;
236
        else if (abiParts.at(1) == QLatin1String("unix"))
hjk's avatar
hjk committed
237
            m_os = UnixOS;
238
        else if (abiParts.at(1) == QLatin1String("windows"))
hjk's avatar
hjk committed
239
            m_os = WindowsOS;
240 241 242 243 244 245
        else
            return;
    }

    if (abiParts.count() >= 3) {
        if (abiParts.at(2) == QLatin1String("unknown"))
hjk's avatar
hjk committed
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
            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;
        else if (abiParts.at(2) == QLatin1String("msvc") && m_os == WindowsOS)
            m_osFlavor = WindowsMsvcFlavor;
        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;
267 268 269 270 271 272
        else
            return;
    }

    if (abiParts.count() >= 4) {
        if (abiParts.at(3) == QLatin1String("unknown"))
hjk's avatar
hjk committed
273
            m_binaryFormat = UnknownFormat;
274
        else if (abiParts.at(3) == QLatin1String("elf"))
hjk's avatar
hjk committed
275
            m_binaryFormat = ElfFormat;
276
        else if (abiParts.at(3) == QLatin1String("pe"))
hjk's avatar
hjk committed
277
            m_binaryFormat = PEFormat;
278
        else if (abiParts.at(3) == QLatin1String("mach_o"))
hjk's avatar
hjk committed
279
            m_binaryFormat = MachOFormat;
280
        else if (abiParts.at(3) == QLatin1String("qml_rt"))
hjk's avatar
hjk committed
281
            m_binaryFormat = RuntimeQmlFormat;
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
        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
313 314 315 316 317
bool Abi::operator != (const Abi &other) const
{
    return !operator ==(other);
}

318 319 320 321 322 323 324 325 326 327 328
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
329 330 331 332
    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)
333 334 335 336 337
            && ((wordWidth() == other.wordWidth() && wordWidth() != 0) || other.wordWidth() == 0);
}

bool Abi::isValid() const
{
hjk's avatar
hjk committed
338 339 340 341
    return m_architecture != UnknownArchitecture
            && m_os != UnknownOS
            && m_osFlavor != UnknownFlavor
            && m_binaryFormat != UnknownFormat
342 343 344 345 346 347
            && m_wordWidth != 0;
}

QString Abi::toString(const Architecture &a)
{
    switch (a) {
hjk's avatar
hjk committed
348
    case ArmArchitecture:
349
        return QLatin1String("arm");
hjk's avatar
hjk committed
350
    case X86Architecture:
351
        return QLatin1String("x86");
hjk's avatar
hjk committed
352
    case MipsArcitecture:
353
        return QLatin1String("mips");
hjk's avatar
hjk committed
354
    case PowerPCArchitecture:
355
        return QLatin1String("ppc");
hjk's avatar
hjk committed
356
    case ItaniumArchitecture:
357
        return QLatin1String("itanium");
hjk's avatar
hjk committed
358
    case UnknownArchitecture: // fall through!
359 360 361 362 363 364 365 366
    default:
        return QLatin1String("unknown");
    }
}

QString Abi::toString(const OS &o)
{
    switch (o) {
hjk's avatar
hjk committed
367
    case LinuxOS:
368
        return QLatin1String("linux");
hjk's avatar
hjk committed
369
    case MacOS:
370
        return QLatin1String("macos");
hjk's avatar
hjk committed
371
    case SymbianOS:
372
        return QLatin1String("symbian");
hjk's avatar
hjk committed
373
    case UnixOS:
374
        return QLatin1String("unix");
hjk's avatar
hjk committed
375
    case WindowsOS:
376
        return QLatin1String("windows");
hjk's avatar
hjk committed
377
    case UnknownOS: // fall through!
378 379 380 381 382
    default:
        return QLatin1String("unknown");
    };
}

hjk's avatar
hjk committed
383
QString Abi::toString(const OSFlavor &of)
384 385
{
    switch (of) {
hjk's avatar
hjk committed
386
    case ProjectExplorer::Abi::GenericLinuxFlavor:
387
        return QLatin1String("generic");
hjk's avatar
hjk committed
388
    case ProjectExplorer::Abi::MaemoLinuxFlavor:
389
        return QLatin1String("maemo");
hjk's avatar
hjk committed
390
    case ProjectExplorer::Abi::HarmattanLinuxFlavor:
391
        return QLatin1String("harmattan");
hjk's avatar
hjk committed
392
    case ProjectExplorer::Abi::MeegoLinuxFlavor:
393
        return QLatin1String("meego");
hjk's avatar
hjk committed
394
    case ProjectExplorer::Abi::GenericMacFlavor:
395
        return QLatin1String("generic");
hjk's avatar
hjk committed
396
    case ProjectExplorer::Abi::SymbianDeviceFlavor:
397
        return QLatin1String("device");
hjk's avatar
hjk committed
398
    case ProjectExplorer::Abi::SymbianEmulatorFlavor:
399
        return QLatin1String("emulator");
hjk's avatar
hjk committed
400
    case ProjectExplorer::Abi::GenericUnixFlavor:
401
        return QLatin1String("generic");
hjk's avatar
hjk committed
402
    case ProjectExplorer::Abi::WindowsMsvcFlavor:
403
        return QLatin1String("msvc");
hjk's avatar
hjk committed
404
    case ProjectExplorer::Abi::WindowsMSysFlavor:
405
        return QLatin1String("msys");
hjk's avatar
hjk committed
406
    case ProjectExplorer::Abi::WindowsCEFlavor:
407
        return QLatin1String("ce");
408
    case ProjectExplorer::Abi::UnknownFlavor: // fall through!
409 410 411 412 413 414 415 416
    default:
        return QLatin1String("unknown");
    }
}

QString Abi::toString(const BinaryFormat &bf)
{
    switch (bf) {
hjk's avatar
hjk committed
417
    case ElfFormat:
418
        return QLatin1String("elf");
hjk's avatar
hjk committed
419
    case PEFormat:
420
        return QLatin1String("pe");
hjk's avatar
hjk committed
421
    case MachOFormat:
422
        return QLatin1String("mach_o");
hjk's avatar
hjk committed
423
    case RuntimeQmlFormat:
424
        return QLatin1String("qml_rt");
hjk's avatar
hjk committed
425
    case UnknownFormat: // fall through!
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
    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
442 443 444
    OS os = UnknownOS;
    OSFlavor subos = UnknownFlavor;
    BinaryFormat format = UnknownFormat;
445 446

#if defined (Q_OS_WIN)
hjk's avatar
hjk committed
447 448 449
    os = WindowsOS;
    subos = WindowsMsvcFlavor;
    format = PEFormat;
450
#elif defined (Q_OS_LINUX)
hjk's avatar
hjk committed
451 452 453
    os = LinuxOS;
    subos = GenericLinuxFlavor;
    format = ElfFormat;
454
#elif defined (Q_OS_MAC)
hjk's avatar
hjk committed
455 456 457
    os = MacOS;
    subos = GenericMacFlavor;
    format = MachOFormat;
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
#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
473 474
    bool windowsStatic = path.endsWith(QLatin1String(".lib"));

475 476
    f.open(QFile::ReadOnly);
    QByteArray data = f.read(1024);
477 478 479 480 481 482 483 484 485 486 487
    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
488
            if ((data.at(58) != 0x60 || data.at(59) != 0x0a)) {
489
                qWarning() << path << ": Thought it was an ar-file, but it is not!";
490
                break;
491
            }
492

493 494 495 496 497
            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));
498

Tobias Hunger's avatar
Tobias Hunger committed
499
            int toSkip = 60 + fileNameOffset;
500
            offset += fileLength.toInt() + 60 /* header */;
Tobias Hunger's avatar
Tobias Hunger committed
501 502 503 504 505 506
            if (windowsStatic) {
                if (fileName == QLatin1String("/0              "))
                    result = parseCoffHeader(data.mid(toSkip, 20));
            } else {
                result = abiOf(data.mid(toSkip));
            }
507
            if (!result.isEmpty())
508
                break;
509

Tobias Hunger's avatar
Tobias Hunger committed
510
            f.seek(offset + (offset % 2)); // ar is 2 byte alligned
511
            data = f.read(1024);
512
        }
513 514
    } else {
        result = abiOf(data);
515
    }
516 517
    f.close();

518 519 520 521
    return result;
}

} // namespace ProjectExplorer