You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
piklab/src/coff/base/coff_object.cpp

659 lines
27 KiB

/***************************************************************************
* 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 TQByteArray &data, uint &offset, uint nbChars, uint stringTableOffset,
Log::Base &log, TQString &name)
{
TQ_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 = TQString(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 TQByteArray &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 TQByteArray &data, uint start, uint stringTableOffset, Log::Base &log)
: AuxSymbol(object)
{
uint offset = start;
TQ_UINT32 v;
if ( !getULong(data, offset, 1, log, v) ) return;
_command = v;
if ( !getULong(data, offset, 4, log, v) ) return;
_string = TQString(data.data()+stringTableOffset+v);
}
Coff::AuxSymbolFile::AuxSymbolFile(const Object &object, const TQByteArray &data, uint start, uint stringTableOffset, Log::Base &log)
: AuxSymbol(object)
{
uint offset = start;
TQ_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 = TQString(data.data()+stringTableOffset+v);
if ( !getULong(data, offset, 4, log, v) ) return;
_line = v;
}
}
Coff::AuxSymbolIdentifier::AuxSymbolIdentifier(const Object &object, const TQByteArray &data, uint start, uint stringTableOffset, Log::Base &log)
: AuxSymbol(object)
{
uint offset = start;
TQ_UINT32 v;
if ( !getULong(data, offset, 4, log, v) ) return;
_string = TQString(data.data()+stringTableOffset+v);
}
Coff::AuxSymbolSection::AuxSymbolSection(const Object &object, const TQByteArray &data, uint start, uint, Log::Base &log)
: AuxSymbol(object)
{
uint offset = start;
TQ_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 TQByteArray &data, uint start,
uint stringTableOffset, const TQString &lastFilename, Log::Base &log)
: BaseSymbol(object)
{
uint offset = start;
TQ_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)").tqarg(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 &section,
const TQByteArray &data, uint start, Log::Base &log)
: Element(object), _symbol(0)
{
uint offset = start;
TQ_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").tqarg(v).tqarg(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").tqarg(v));
return;
}
if ( object.symbol(v)->isAuxSymbol() ) {
log.log(Log::LineType::Error, i18n("Relocation is an auxiliary symbol: %1").tqarg(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 &section,
const TQByteArray &data, uint start, const TQString &lastFilename, Log::Base &log)
: Element(object), _section(section), _symbol(0)
{
uint offset = start;
TQ_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").tqarg(tmp));
return;
}
if ( object.symbol(tmp)->isAuxSymbol() ) {
log.log(Log::LineType::Error, i18n("Codeline is an auxiliary symbol: %1").tqarg(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").tqarg(tmp));
return;
}
if ( object.symbol(tmp)->isAuxSymbol() ) {
log.log(Log::LineType::Error, i18n("Codeline is an auxiliary symbol: %1").tqarg(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).")
// .tqarg(_section._name).tqarg(toHexLabel(_address, nbChars(_address))).tqarg(_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 TQByteArray &data, uint start, uint stringTableOffset, Log::Base &log)
: Element(object)
{
uint offset = start;
TQ_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.")
// .tqarg(toHexLabel(v, 4)).tqarg(toHexLabel(_address, 4)).tqarg(_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 = TQString(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 ) {
TQString 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
TQByteArray 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.").tqarg(toHexLabel(_magic, 4)));
return false;
}
log.log(Log::DebugLevel::Extra, TQString("COFF format: %1").tqarg(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, TQString("COFF optionnal header format: %1").tqarg(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.").tqarg(toHexLabel(_optHeaderMagic, 4)));
offset += size(OptHeaderSize)-2;
} else if ( !OPT_HEADER_DATA[i].parsed ) {
log.log(Log::DebugLevel::Normal, TQString("Optional header not parsed: magic number is %1.").tqarg(toHexLabel(_optHeaderMagic, 4)));
offset += size(OptHeaderSize)-2;
} else if ( !parseOptionnalHeader(data, offset, log) ) return false;
// parse symbol table
uint stringTableOffset = _symbolOffset + _nbSymbols*size(SymbolSize);
TQString 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;
TQString 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;
TQString 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 TQByteArray &data, uint &offset, Log::Base &log)
{
TQ_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").tqarg(size(OptHeaderSize)).tqarg(v));
return false;
}
if ( !getULong(data, offset, 2, log, v) ) return false;
_flags = Flags(v);
return true;
}
bool Coff::Object::parseOptionnalHeader(const TQByteArray &data, uint &offset, Log::Base &log)
{
TQ_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...
TQString name = Coff::findId(v);
log.log(Log::DebugLevel::Normal, TQString("Device name: \"%1\"").tqarg(name));
if ( name.isEmpty() ) {
log.log(Log::DebugLevel::Normal, TQString("Unknown processor type: %1").tqarg(toHexLabel(v, 4)));
log.log(Log::LineType::Error, i18n("Could not determine processor (%1).").tqarg(toHexLabel(v, 4)));
return false;
} else if ( _device==0 ) _device = Device::lister().data(name);
else if ( name!=_device->name() ) log.log(Log::DebugLevel::Normal, TQString("Different processor name: %1").tqarg(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, TQString("Rom width is not %1: %2").tqarg(nbBits).tqarg(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, TQString("Ram width is not %1: %2").tqarg(nbBits).tqarg(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];
}
TQString Coff::Object::variableName(Address address) const
{
TQMap<TQString, Address>::const_iterator it;
for (it=_variables.begin(); it!=_variables.end(); ++it)
if ( it.data()==address ) return it.key();
return TQString();
}
//----------------------------------------------------------------------------
TQValueVector<Pic::RegisterNameData> Pic::sfrList(const Pic::Data &data)
{
TQValueVector<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));
}
TQMap<TQString, 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;
}
TQValueVector<Pic::RegisterNameData> Pic::gprList(const Pic::Data &data, const Coff::Object *coff)
{
TQValueVector<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 ) {
TQString s = toHexLabel(address, rdata.nbCharsAddress());
if (coff) {
TQString name = coff->variableName(address);
if ( !name.isEmpty() ) s += " (" + name + ")";
}
Register::TypeData rtd(address, rdata.nbChars());
list.append(Pic::RegisterNameData(s, rtd));
}
}
return list;
}
TQValueVector<Pic::RegisterNameData> Pic::variableList(const Pic::Data &data, const Coff::Object &coff)
{
TQValueVector<Pic::RegisterNameData> list;
const Pic::RegistersData &rdata = data.registersData();
TQMap<TQString, Address> variables = coff.variables();
TQMap<TQString, 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;
}