diff options
Diffstat (limited to 'src/coff/base/coff_object.cpp')
-rw-r--r-- | src/coff/base/coff_object.cpp | 658 |
1 files changed, 658 insertions, 0 deletions
diff --git a/src/coff/base/coff_object.cpp b/src/coff/base/coff_object.cpp new file mode 100644 index 0000000..f4109f9 --- /dev/null +++ b/src/coff/base/coff_object.cpp @@ -0,0 +1,658 @@ +/*************************************************************************** + * Copyright (C) 2006 Nicolas Hadacek <hadacek@kde.org> * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + ***************************************************************************/ +#include "coff_object.h" + +#include "common/common/misc.h" +#include "devices/list/device_list.h" +#include "devices/base/device_group.h" +#include "devices/pic/base/pic_register.h" +#include "coff_data.h" +#include "common/global/pfile.h" + +//---------------------------------------------------------------------------- +bool Coff::getName(const QByteArray &data, uint &offset, uint nbChars, uint stringTableOffset, + Log::Base &log, QString &name) +{ + Q_UINT32 v; + if ( !getULong(data, offset, 4, log, v) ) return false; + if ( v!=0 ) { // name is not in string table + offset -= 4; + return getString(data, offset, nbChars, log, name); + } + if ( !getULong(data, offset, 4, log, v) ) return false; + // ### do a sanity check here + name = QString(data.data()+stringTableOffset+v); + return true; +} + +const Coff::OptHeaderFormat::Data Coff::OptHeaderFormat::DATA[Nb_Types] = { + { 0, I18N_NOOP("Old Microchip") }, + { 0, I18N_NOOP("New Microchip") }, + { 0, I18N_NOOP("PICC Compiler") }, + { 0, I18N_NOOP("CCS Compiler") } +}; + +const Coff::OptHeaderData Coff::OPT_HEADER_DATA[] = { + { 0x5678, OptHeaderFormat::OldMicrochip, true }, + { 0x0000, OptHeaderFormat::NewMicrochip, true }, + { 0x0001, OptHeaderFormat::NewMicrochip, true }, // PIC30 with debug + { 0x1388, OptHeaderFormat::Picc, false }, // PICC + { 0x1B78, OptHeaderFormat::Ccsc, false }, // CCSC + { 0x0000, OptHeaderFormat::Nb_Types, false } +}; + +//---------------------------------------------------------------------------- +const Coff::AuxSymbolType::Data Coff::AuxSymbolType::DATA[Nb_Types] = { + { 0, I18N_NOOP("Direct") }, + { 0, I18N_NOOP("File") }, + { 0, I18N_NOOP("Indentifier") }, + { 0, I18N_NOOP("Section") } +}; + +Coff::AuxSymbol *Coff::AuxSymbol::factory(const Object &object, AuxSymbolType type, const QByteArray &data, uint offset, uint stringTableOffset, Log::Base &log) +{ + switch (type.type()) { + case AuxSymbolType::Direct: return new AuxSymbolDirect(object, data, offset, stringTableOffset, log); + case AuxSymbolType::File: return new AuxSymbolFile(object, data, offset, stringTableOffset, log); + case AuxSymbolType::Identifier: return new AuxSymbolIdentifier(object, data, offset, stringTableOffset, log); + case AuxSymbolType::Section: return new AuxSymbolSection(object, data, offset, stringTableOffset, log); + case AuxSymbolType::Nb_Types: return new AuxSymbolUnknown(object); + } + Q_ASSERT(false); + return 0; +} + +Coff::AuxSymbolDirect::AuxSymbolDirect(const Object &object, const QByteArray &data, uint start, uint stringTableOffset, Log::Base &log) + : AuxSymbol(object) +{ + uint offset = start; + Q_UINT32 v; + if ( !getULong(data, offset, 1, log, v) ) return; + _command = v; + if ( !getULong(data, offset, 4, log, v) ) return; + _string = QString(data.data()+stringTableOffset+v); +} + +Coff::AuxSymbolFile::AuxSymbolFile(const Object &object, const QByteArray &data, uint start, uint stringTableOffset, Log::Base &log) + : AuxSymbol(object) +{ + uint offset = start; + Q_UINT32 v; + if ( object.format()==Format::PIC30 ) { + if ( !getName(data, offset, 14, stringTableOffset, log, _filename) ) return; + _line = 0; + } else { + if ( !getULong(data, offset, 4, log, v) ) return; + _filename = QString(data.data()+stringTableOffset+v); + if ( !getULong(data, offset, 4, log, v) ) return; + _line = v; + } +} + +Coff::AuxSymbolIdentifier::AuxSymbolIdentifier(const Object &object, const QByteArray &data, uint start, uint stringTableOffset, Log::Base &log) + : AuxSymbol(object) +{ + uint offset = start; + Q_UINT32 v; + if ( !getULong(data, offset, 4, log, v) ) return; + _string = QString(data.data()+stringTableOffset+v); +} + +Coff::AuxSymbolSection::AuxSymbolSection(const Object &object, const QByteArray &data, uint start, uint, Log::Base &log) + : AuxSymbol(object) +{ + uint offset = start; + Q_UINT32 v; + if ( !getULong(data, offset, 4, log, v) ) return; + _length = v; + if ( !getULong(data, offset, 2, log, v) ) return; + _nbRelocations = v; + if ( !getULong(data, offset, 2, log, v) ) return; + _nbLineNumbers = v; +} + +//---------------------------------------------------------------------------- +const Coff::SymbolSectionType::Data Coff::SymbolSectionType::DATA[Nb_Types] = { + { 0, I18N_NOOP("Inside Section") }, + { 0, I18N_NOOP("Undefined Section") }, + { 0, I18N_NOOP("Absolute Value") }, + { 0, I18N_NOOP("Debug Symbol") } +}; + +const Coff::SymbolClass::Data Coff::SymbolClass::DATA[Nb_Types] = { + { 0, I18N_NOOP("Automatic Variable"), 1 }, + { 0, I18N_NOOP("External Symbol"), 2 }, + { 0, I18N_NOOP("Static Symbol"), 3 }, + { 0, I18N_NOOP("Register Variable"), 4 }, + { 0, I18N_NOOP("External Definition"), 5 }, + { 0, I18N_NOOP("Label"), 6 }, + { 0, I18N_NOOP("Undefined Label"), 7 }, + { 0, I18N_NOOP("Member of Structure"), 8 }, + { 0, I18N_NOOP("Function Argument"), 9 }, + { 0, I18N_NOOP("Structure Tag"), 10 }, + { 0, I18N_NOOP("Member of Union"), 11 }, + { 0, I18N_NOOP("Union Tag"), 12 }, + { 0, I18N_NOOP("Type Definition"), 13 }, + { 0, I18N_NOOP("Undefined Static"), 14 }, + { 0, I18N_NOOP("Enumeration Tag"), 15 }, + { 0, I18N_NOOP("Member of Enumeration"), 16 }, + { 0, I18N_NOOP("Register Parameter"), 17 }, + { 0, I18N_NOOP("Bit Field"), 18 }, + { 0, I18N_NOOP("Auto Argument"), 19 }, + { 0, I18N_NOOP("Dummy Entry (end of block)"), 20 }, + { 0, I18N_NOOP("Beginning or End of Block"), 100 }, + { 0, I18N_NOOP("Beginning or End of Function"), 101 }, + { 0, I18N_NOOP("End of Structure"), 102 }, + { 0, I18N_NOOP("Filename"), 103 }, + { 0, I18N_NOOP("Line Number"), 104 }, + { 0, I18N_NOOP("Duplicate Tag"), 105 }, + { 0, I18N_NOOP("Section"), 109 } +}; + +const Coff::SymbolType::Data Coff::SymbolType::DATA[Nb_Types] = { + { 0, I18N_NOOP("Void"), 0x0001 }, + { 0, I18N_NOOP("Char"), 0x0010 }, + { 0, I18N_NOOP("Short"), 0x0011 }, + { 0, I18N_NOOP("Int"), 0x0100 }, + { 0, I18N_NOOP("Long"), 0x0101 }, + { 0, I18N_NOOP("Float"), 0x0110 }, + { 0, I18N_NOOP("Double"), 0x0111 }, + { 0, I18N_NOOP("Structure"), 0x1000 }, + { 0, I18N_NOOP("Union"), 0x1001 }, + { 0, I18N_NOOP("Enumeration"), 0x1010 }, + { 0, I18N_NOOP("Member Of Enumeration"), 0x1011 }, + { 0, I18N_NOOP("Unsigned Char"), 0x1100 }, + { 0, I18N_NOOP("Unsigned Short"), 0x1101 }, + { 0, I18N_NOOP("Unsigned Int"), 0x1110 }, + { 0, I18N_NOOP("Unsigned Long"), 0x1111 }, + { 0, I18N_NOOP("Long Double"), 0x10000 } +}; + +const Coff::SymbolDerivedType::Data Coff::SymbolDerivedType::DATA[Nb_Types] = { + { 0, I18N_NOOP("Pointer"), 0x010000 }, + { 0, I18N_NOOP("Function"), 0x100000 }, + { 0, I18N_NOOP("Array"), 0x110000 } +}; + +Coff::Symbol::Symbol(const Object &object, const QByteArray &data, uint start, + uint stringTableOffset, const QString &lastFilename, Log::Base &log) + : BaseSymbol(object) +{ + uint offset = start; + Q_UINT32 v; + if ( !getName(data, offset, 8, stringTableOffset, log, _name) ) return; + if ( !getULong(data, offset, 4, log, v) ) return; + _value = v; + if ( !getULong(data, offset, 2, log, v) ) return; + _section = v; + uint nb = (object.format()==Format::NewMicrochip ? 4 : 2); + if ( !getULong(data, offset, nb, log, v) ) return; + _type = SymbolType::Nb_Types; + FOR_EACH(SymbolType, type) + if ( (v & 0x001111)==type.data().id ) { _type = type; break; } + _dtype = SymbolDerivedType::Nb_Types; + FOR_EACH(SymbolDerivedType, dtype) + if ( (v & 0x110000)==dtype.data().id ) { _dtype = dtype; break; } + if ( !getULong(data, offset, 1, log, v) ) return; + _sclass = SymbolClass::Nb_Types; + FOR_EACH(SymbolClass, sclass) + if ( v==sclass.data().id ) { _sclass = sclass; break; } + if ( !getULong(data, offset, 1, log, v) ) return; + uint nbAux = v; + //qDebug("symbol: %s value=%s type=%i dtype=%i class=%i nbAux=%i section=%i", _name.latin1(), toHexLabel(_value, 4).latin1(), _type, _dtype, _class, nbAux, _section); + + AuxSymbolType auxType = AuxSymbolType::Nb_Types; + if ( _name==".direct" ) auxType = AuxSymbolType::Direct; + else if ( _name==".ident" ) auxType = AuxSymbolType::Identifier; + else if ( _sclass==SymbolClass::Filename ) auxType = AuxSymbolType::File; + else if ( _sclass==SymbolClass::Section ) auxType = AuxSymbolType::Section; + if ( auxType!=AuxSymbolType::Nb_Types && nbAux==0 ) log.log(Log::LineType::Warning, i18n("Symbol without needed auxilliary symbol (type=%1)").arg(auxType.type())); + Q_ASSERT( (offset-start)==object.size(SymbolSize) ); + _aux.resize(nbAux); + for (uint i=0; i<nbAux; i++) { + _aux[i] = AuxSymbol::factory(object, auxType, data, offset, stringTableOffset, log); + offset += object.size(SymbolSize); + if ( log.hasError() ) return; + } + + _filename = lastFilename; + for (uint i=0; i<uint(_aux.count()); i++) + if ( _aux[i]->type()==AuxSymbolType::File ) _filename = static_cast<AuxSymbolFile *>(_aux[i])->filename(); +} + +Coff::SymbolSectionType Coff::Symbol::sectionType() const +{ + switch (_section) { + case 0x0000: return SymbolSectionType::UndefinedSection; + case 0xFFFF: return SymbolSectionType::AbsoluteValue; + case 0xFFFE: return SymbolSectionType::DebugSymbol; + } + return SymbolSectionType::InsideSection; +} + +//---------------------------------------------------------------------------- +Coff::Relocation::Relocation(const Object &object, const Section §ion, + const QByteArray &data, uint start, Log::Base &log) + : Element(object), _symbol(0) +{ + uint offset = start; + Q_UINT32 v; + if ( !getULong(data, offset, 4, log, v) ) return; + _address = v; + if ( _address>section.size() ) log.log(Log::LineType::Warning, i18n("Relocation address beyong section size: %1/%2").arg(v).arg(section.size())); + if ( !getULong(data, offset, 4, log, v) ) return; + if ( v>=object.nbSymbols() ) { + log.log(Log::LineType::Error, i18n("Relocation has unknown symbol: %1").arg(v)); + return; + } + if ( object.symbol(v)->isAuxSymbol() ) { + log.log(Log::LineType::Error, i18n("Relocation is an auxiliary symbol: %1").arg(v)); + return; + } + _symbol = static_cast<const Symbol *>(object.symbol(v)); + if ( object.format()!=Format::PIC30 ) { + if ( !getULong(data, offset, 2, log, v) ) return; + _offset = short(v); + } + if ( !getULong(data, offset, 2, log, v) ) return; + _type = v; + //qDebug("reloc %s: address=%s offset=%i type=%i", _symbol->_name.latin1(), toHexLabel(_address, 4).latin1(), _offset, _type); +} + +//---------------------------------------------------------------------------- +Coff::CodeLine::CodeLine(const Object &object, const Section §ion, + const QByteArray &data, uint start, const QString &lastFilename, Log::Base &log) + : Element(object), _section(section), _symbol(0) +{ + uint offset = start; + Q_UINT32 v; + if ( !getULong(data, offset, 4, log, v) ) return; + uint tmp = v; + if ( object.format()==Format::PIC30 ) { + if ( !getULong(data, offset, 4, log, v) ) return; + _line = v; + if ( _line!=0 ) { + _address = tmp; + _filename = lastFilename; + //qDebug("code line %i: %s", _line, toHexLabel(_address, nbChars(_address)).latin1()); + } else { + if ( tmp>=object.nbSymbols() ) { + log.log(Log::LineType::Error, i18n("Codeline has unknown symbol: %1").arg(tmp)); + return; + } + if ( object.symbol(tmp)->isAuxSymbol() ) { + log.log(Log::LineType::Error, i18n("Codeline is an auxiliary symbol: %1").arg(tmp)); + return; + } + _symbol = static_cast<const Symbol *>(object.symbol(tmp)); + _filename = _symbol->filename(); + //qDebug("code line %i: %s", _line, _symbol->_name.latin1()); + } + } else { + if ( tmp>=object.nbSymbols() ) { + log.log(Log::LineType::Error, i18n("Codeline has unknown symbol: %1").arg(tmp)); + return; + } + if ( object.symbol(tmp)->isAuxSymbol() ) { + log.log(Log::LineType::Error, i18n("Codeline is an auxiliary symbol: %1").arg(tmp)); + return; + } + _symbol = static_cast<const Symbol *>(object.symbol(tmp)); + _filename = _symbol->filename(); + if ( !getULong(data, offset, 2, log, v) ) return; + _line = v; + if ( object.optHeaderFormat()==OptHeaderFormat::Picc && _line>=2 ) _line -= 2; // #### ?? + if ( !getULong(data, offset, 4, log, v) ) return; + _address = v; + if ( !getULong(data, offset, 2, log, v) ) return; + // flags + if ( !getULong(data, offset, 4, log, v) ) return; + // function index + //qDebug("code line %i: %s", _line, toHexLabel(_address, nbChars(_address)).latin1()); + } +// if ( _symbol && _symbol->_class!=Symbol::CFile ) +// log.log(Log::LineType::Warning, i18n("Line without file symbol associated (%1:%2 %3).") +// .arg(_section._name).arg(toHexLabel(_address, nbChars(_address))).arg(_symbol->_class)); +} + +//---------------------------------------------------------------------------- +const Coff::SectionType::Data Coff::SectionType::DATA[Nb_Types] = { + { 0, I18N_NOOP("Config") }, + { 0, I18N_NOOP("Device ID") }, + { 0, I18N_NOOP("User IDs") }, + { 0, I18N_NOOP("Uninitialized Data") }, + { 0, I18N_NOOP("Initialized Data") }, + { 0, I18N_NOOP("Rom Data") }, + { 0, I18N_NOOP("Code") } +}; + +Coff::Section::Section(const Device::Data &device, const Object &object, + const QByteArray &data, uint start, uint stringTableOffset, Log::Base &log) + : Element(object) +{ + uint offset = start; + Q_UINT32 v; + if ( !getName(data, offset, 8, stringTableOffset, log, _name) ) return; + if ( !getULong(data, offset, 4, log, v) ) return; + _address = v; + if ( !getULong(data, offset, 4, log, v) ) return; + //if ( _address!=v ) log.log(Log::LineType::Warning, i18n("Virtual address (%1) does not match physical address (%2) in %3.") + // .arg(toHexLabel(v, 4)).arg(toHexLabel(_address, 4)).arg(_name)); + if ( !getULong(data, offset, 4, log, v) ) return; + _size = v; + if ( !getULong(data, offset, 4, log, v) ) return; + uint dataOffset = v; + if ( !getULong(data, offset, 4, log, v) ) return; + uint relocationOffset = v; + if ( !getULong(data, offset, 4, log, v) ) return; + uint lineNumberOffset = v; + if ( !getULong(data, offset, 2, log, v) ) return; + uint nbRelocations = v; + if ( !getULong(data, offset, 2, log, v) ) return; + uint nbLineNumbers = v; + if ( !getULong(data, offset, 4, log, v) ) return; + _flags = v; + + // read data + Q_ASSERT ( device.group().name()=="pic" ); + const Pic::Data &pdata = static_cast<const Pic::Data &>(device); + //qDebug("section %s: address=%s size=%i flags=%i", _name.data(), toHexLabel(_address, 4).latin1(), _size, int(_flags)); + if ( _size!=0 && dataOffset!=0 ) { + uint inc = 1; + uint nbWords = _size; + uint nbBytesWord = 1; + bool b = ( (_flags & FText) || (_flags & FDataRom) ); + if (b) { + nbBytesWord = pdata.nbBytesWord(Pic::MemoryRangeType::Code); + nbWords /= nbBytesWord; + inc = pdata.addressIncrement(Pic::MemoryRangeType::Code); + } + for (uint i=0; i<nbWords; i++) { + Address address = _address + inc*i; + if ( !getULong(data, dataOffset, nbBytesWord, log, v) ) return; + _instructions[address].value = v; + } + for (uint i=0; i<nbWords; i++) { + Address address = _address + inc*i; + BitValue op = _instructions[address].value; + if ( _flags & FText ) { + char buffer[512]; + buffer[0] = 0; + BitValue op2 = ((i+1)<nbWords ? _instructions[address+inc].value : 0); + uint nbop = disassemble(op.toUInt(), op2.toUInt(), address.toUInt()/inc, pdata.architecture(), buffer, 512); + _instructions[address].disasm = QString(buffer); + _instructions[address].opcode = toHex(op, pdata.nbCharsWord(Pic::MemoryRangeType::Code)); + if ( nbop==2 ) { + _instructions[address+inc].opcode = toHex(op2, pdata.nbCharsWord(Pic::MemoryRangeType::Code)); + i++; + } + //qDebug(" %s: %s (%s %s)", toHex(address, 4).data(), _data[address].disasm.data(), _data[address].opcode.data(), (nbop==2 ? _data[address+inc].opcode.data() : "")); + } else if ( _flags & FDataRom ) _instructions[address].opcode = toHex(op, 4); + else if ( _flags & FData ) _instructions[address].opcode = toHex(op.maskWith(0xFF), 2); + } + } + + // read relocations + if ( relocationOffset!=0 ) { + _relocations.resize(nbRelocations); + for (uint i=0; i<nbRelocations; i++) { + _relocations[i] = new Relocation(object, *this, data, relocationOffset, log); + relocationOffset += object.size(RelocationSize); + if ( log.hasError() ) return; + } + } + + // read line numbers + if ( lineNumberOffset!=0 ) { + QString lastFilename; + _lines.resize(nbLineNumbers); + for (uint i=0; i<nbLineNumbers; i++) { + _lines[i] = new CodeLine(object, *this, data, lineNumberOffset, lastFilename, log); + lastFilename = _lines[i]->filename(); + lineNumberOffset += object.size(LineNumberSize); + if ( log.hasError() ) return; + } + } +} + +Coff::Section::~Section() +{ + for (uint i=0; i<uint(_relocations.count()); i++) delete _relocations[i]; + for (uint i=0; i<uint(_lines.count()); i++) delete _lines[i]; +} + +Coff::SectionType Coff::Section::type() const +{ + if ( _name==".config" ) return SectionType::Config; + if ( _name==".devid" ) return SectionType::DeviceId; + if ( _name==".idlocs" ) return SectionType::UserIds; + if ( _flags & FText ) return SectionType::Code; + if ( _flags & FData ) return SectionType::InitializedData; + if ( _flags & FBSS ) return SectionType::UninitializedData; + if ( _flags & FDataRom ) return SectionType::DataRom; + return SectionType::Nb_Types; +} + +//---------------------------------------------------------------------------- +Coff::Object::Object(const Device::Data *device, const PURL::Url &url) + : Base(url), _device(device) +{} + +bool Coff::Object::parse(Log::Base &log) +{ + // header + QByteArray data; + uint offset = 0; + if ( !initParse(CoffType::Object, data, offset, log) ) return false; + if ( _format==Format::Nb_Types ) { + log.log(Log::LineType::Error, i18n("COFF format not supported: magic number is %1.").arg(toHexLabel(_magic, 4))); + return false; + } + log.log(Log::DebugLevel::Extra, QString("COFF format: %1").arg(toHexLabel(_magic, 4))); + if ( !parseHeader(data, offset, log) ) return false; + + // optionnal header + Q_ASSERT( offset==size(HeaderSize) ); + if ( !getULong(data, offset, 2, log, _optHeaderMagic) ) return false; + log.log(Log::DebugLevel::Extra, QString("COFF optionnal header format: %1").arg(toHexLabel(_optHeaderMagic, 4))); + _optHeaderFormat = OptHeaderFormat::Nb_Types; + uint i = 0; + for (; OPT_HEADER_DATA[i].optHeaderFormat!=OptHeaderFormat::Nb_Types; i++) if ( _optHeaderMagic==OPT_HEADER_DATA[i].magic ) break; + _optHeaderFormat = OPT_HEADER_DATA[i].optHeaderFormat; + if ( _optHeaderFormat==OptHeaderFormat::Nb_Types ) { + log.log(Log::LineType::Warning, i18n("Optional header format not supported: magic number is %1.").arg(toHexLabel(_optHeaderMagic, 4))); + offset += size(OptHeaderSize)-2; + } else if ( !OPT_HEADER_DATA[i].parsed ) { + log.log(Log::DebugLevel::Normal, QString("Optional header not parsed: magic number is %1.").arg(toHexLabel(_optHeaderMagic, 4))); + offset += size(OptHeaderSize)-2; + } else if ( !parseOptionnalHeader(data, offset, log) ) return false; + + // parse symbol table + uint stringTableOffset = _symbolOffset + _nbSymbols*size(SymbolSize); + QString lastFilename; + _symbols.resize(_nbSymbols); + for (uint i=0; i<_nbSymbols; i++) { + Symbol *s = new Symbol(*this, data, _symbolOffset, stringTableOffset, lastFilename, log); + if ( log.hasError() ) return false; + if ( !s->filename().isEmpty() ) lastFilename = s->filename(); + _symbols[i] = s; + _msymbols[s->name()] = s; + _symbolOffset += size(SymbolSize); + for (uint k=0; k<uint(s->auxSymbols().count()); k++) { + i++; + _symbols[i] = s->auxSymbols()[k]; + _symbolOffset += size(SymbolSize); + } + } + + // parse sections + Q_ASSERT( offset==(size(HeaderSize) + size(OptHeaderSize)) ); + _sections.resize(_nbSections); + for (uint i=0; i<_nbSections; i++) { + _sections[i] = new Section(*_device, *this, data, offset, stringTableOffset, log); + offset += size(SectionHeaderSize); + if ( log.hasError() ) return false; + } + + // extract filenames + for (uint i=0; i<_nbSymbols; i++) { + if ( _symbols[i]==0 || _symbols[i]->isAuxSymbol() ) continue; + QString s = static_cast<const Symbol *>(_symbols[i])->filename(); + if ( s.isEmpty() || s=="fake" || _filenames.contains(s) ) continue; + _filenames.append(s); + } + + // extract variables + for (uint i=0; i<nbSymbols(); i++) { + if ( _symbols[i]==0 || _symbols[i]->isAuxSymbol() ) continue; + const Symbol *sym = static_cast<const Symbol *>(_symbols[i]); + if ( sym->symbolClass()!=SymbolClass::Static ) continue; + if ( sym->sectionType()!=SymbolSectionType::InsideSection ) continue; + QString name = sym->name(); + if ( name.startsWith("_$_") || name.startsWith("__") || name.startsWith(".") ) continue; // special variables (?) + _variables[name] = sym->value() & 0xFFF; // #### ?? + } + + return true; +} + +bool Coff::Object::parseHeader(const QByteArray &data, uint &offset, Log::Base &log) +{ + Q_UINT32 v; + if ( !getULong(data, offset, 2, log, v) ) return false; + _nbSections = v; + if ( !getULong(data, offset, 4, log, v) ) return false; +// time_t time = v; + if ( !getULong(data, offset, 4, log, v) ) return false; + _symbolOffset = v; + if ( !getULong(data, offset, 4, log, v) ) return false; + _nbSymbols = v; + if ( !getULong(data, offset, 2, log, v) ) return false; + if ( v!=size(OptHeaderSize) ) { + log.log(Log::LineType::Error, i18n("Optionnal header size is not %1: %2").arg(size(OptHeaderSize)).arg(v)); + return false; + } + if ( !getULong(data, offset, 2, log, v) ) return false; + _flags = Flags(v); + return true; +} + +bool Coff::Object::parseOptionnalHeader(const QByteArray &data, uint &offset, Log::Base &log) +{ + Q_UINT32 v; + int nb = (_format==Format::NewMicrochip ? 4 : 2); + if ( !getULong(data, offset, nb, log, v) ) return false; // version stamp + if ( _format==Format::PIC30 ) { + if ( !getULong(data, offset, 4, log, v) ) return false; // text size in bytes, padded to firmware boundary + if ( !getULong(data, offset, 4, log, v) ) return false; // initialized data " + if ( !getULong(data, offset, 4, log, v) ) return false; // uninitialized data " + if ( !getULong(data, offset, 4, log, v) ) return false; // entry point + if ( !getULong(data, offset, 4, log, v) ) return false; // offset of text + if ( !getULong(data, offset, 4, log, v) ) return false; // offset of data + if ( _device==0 ) _device = Device::lister().data("30F2010"); // for e.g. + } else { + if ( !getULong(data, offset, 4, log, v) ) return false; + // #### at least for C18 compiler, it can be compiled for generic processor: in such case + // the pic type will be 18C452 in non-extended mode and 18F4620 for extended mode... + QString name = Coff::findId(v); + log.log(Log::DebugLevel::Normal, QString("Device name: \"%1\"").arg(name)); + if ( name.isEmpty() ) { + log.log(Log::DebugLevel::Normal, QString("Unknown processor type: %1").arg(toHexLabel(v, 4))); + log.log(Log::LineType::Error, i18n("Could not determine processor (%1).").arg(toHexLabel(v, 4))); + return false; + } else if ( _device==0 ) _device = Device::lister().data(name); + else if ( name!=_device->name() ) log.log(Log::DebugLevel::Normal, QString("Different processor name: %1").arg(name)); + if ( !getULong(data, offset, 4, log, v) ) return false; + const Pic::Data *pdata = static_cast<const Pic::Data *>(_device); + if (pdata) { + uint nbBits = pdata->nbBitsWord(Pic::MemoryRangeType::Code) / pdata->addressIncrement(Pic::MemoryRangeType::Code); + if ( v!=nbBits ) log.log(Log::DebugLevel::Normal, QString("Rom width is not %1: %2").arg(nbBits).arg(v)); + } + if ( !getULong(data, offset, 4, log, v) ) return false; + if (pdata) { + uint nbBits = pdata->registersData().nbBits(); + if ( v!=nbBits ) log.log(Log::DebugLevel::Normal, QString("Ram width is not %1: %2").arg(nbBits).arg(v)); + } + } + return true; +} + +Coff::Object::~Object() +{ + for (uint i=0; i<nbSymbols(); i++) delete _symbols[i]; + for (uint i=0; i<nbSections(); i++) delete _sections[i]; +} + +QString Coff::Object::variableName(Address address) const +{ + QMap<QString, Address>::const_iterator it; + for (it=_variables.begin(); it!=_variables.end(); ++it) + if ( it.data()==address ) return it.key(); + return QString::null; +} + +//---------------------------------------------------------------------------- +QValueVector<Pic::RegisterNameData> Pic::sfrList(const Pic::Data &data) +{ + QValueVector<Pic::RegisterNameData> list; + const Pic::RegistersData &rdata = data.registersData(); + for (uint i=0; i<rdata.nbRegisters(); i++) { + uint address = rdata.nbBytes() * i; + Pic::RegisterType type = rdata.type(address); + Device::RegisterProperties rp = rdata.properties(address); + if ( !(rp & Device::Readable) ) continue; + Register::TypeData rtd(address, rdata.nbChars()); + if ( type==Pic::Sfr ) list.append(Pic::RegisterNameData(rdata.label(address), rtd)); + } + QMap<QString, Pic::CombinedData>::const_iterator it; + for (it=rdata.combined.begin(); it!=rdata.combined.end(); ++it) { + Register::TypeData td(it.key(), it.data().address, it.data().nbChars); + list.append(Pic::RegisterNameData(it.key(), td)); + } + if ( data.architecture()==Pic::Architecture::P16X ) + list.append(Pic::RegisterNameData("WREG", Register::TypeData("WREG", rdata.nbChars()))); + qHeapSort(list); + return list; +} + +QValueVector<Pic::RegisterNameData> Pic::gprList(const Pic::Data &data, const Coff::Object *coff) +{ + QValueVector<Pic::RegisterNameData> list; + const Pic::RegistersData &rdata = data.registersData(); + for (uint i=0; i<rdata.nbRegisters(); i++) { + uint address = rdata.nbBytes() * i; + Pic::RegisterType type = rdata.type(address); + Device::RegisterProperties rp = rdata.properties(address); + if ( !(rp & Device::Readable) ) continue; + if (type==Pic::Gpr ) { + QString s = toHexLabel(address, rdata.nbCharsAddress()); + if (coff) { + QString name = coff->variableName(address); + if ( !name.isEmpty() ) s += " (" + name + ")"; + } + Register::TypeData rtd(address, rdata.nbChars()); + list.append(Pic::RegisterNameData(s, rtd)); + } + } + return list; +} + +QValueVector<Pic::RegisterNameData> Pic::variableList(const Pic::Data &data, const Coff::Object &coff) +{ + QValueVector<Pic::RegisterNameData> list; + const Pic::RegistersData &rdata = data.registersData(); + QMap<QString, Address> variables = coff.variables(); + QMap<QString, Address>::const_iterator vit; + for (vit=variables.begin(); vit!=variables.end(); ++vit) { + Register::TypeData rtd(vit.data(), rdata.nbChars()); + list.append(Pic::RegisterNameData(vit.key() + " (" + toHexLabel(vit.data(), rdata.nbCharsAddress()) + ")", rtd)); + } + qHeapSort(list); + return list; +} |