diff options
Diffstat (limited to 'src/coff/base')
-rw-r--r-- | src/coff/base/Makefile.am | 13 | ||||
-rw-r--r-- | src/coff/base/base.pro | 6 | ||||
-rw-r--r-- | src/coff/base/cdb_parser.cpp | 417 | ||||
-rw-r--r-- | src/coff/base/cdb_parser.h | 166 | ||||
-rw-r--r-- | src/coff/base/coff.cpp | 97 | ||||
-rw-r--r-- | src/coff/base/coff.h | 64 | ||||
-rw-r--r-- | src/coff/base/coff.xml | 342 | ||||
-rw-r--r-- | src/coff/base/coff_archive.cpp | 129 | ||||
-rw-r--r-- | src/coff/base/coff_archive.h | 53 | ||||
-rw-r--r-- | src/coff/base/coff_data.h | 22 | ||||
-rw-r--r-- | src/coff/base/coff_object.cpp | 658 | ||||
-rw-r--r-- | src/coff/base/coff_object.h | 322 | ||||
-rw-r--r-- | src/coff/base/disassembler.cpp | 289 | ||||
-rw-r--r-- | src/coff/base/disassembler.h | 80 | ||||
-rw-r--r-- | src/coff/base/gpdis.cpp | 349 | ||||
-rw-r--r-- | src/coff/base/gpopcode.cpp | 348 | ||||
-rw-r--r-- | src/coff/base/gpopcode.h | 107 | ||||
-rw-r--r-- | src/coff/base/text_coff.cpp | 262 | ||||
-rw-r--r-- | src/coff/base/text_coff.h | 45 |
19 files changed, 3769 insertions, 0 deletions
diff --git a/src/coff/base/Makefile.am b/src/coff/base/Makefile.am new file mode 100644 index 0000000..c6ffbab --- /dev/null +++ b/src/coff/base/Makefile.am @@ -0,0 +1,13 @@ +INCLUDES = -I$(top_srcdir)/src $(all_includes) +METASOURCES = AUTO + +noinst_LTLIBRARIES = libcoff.la +libcoff_la_LDFLAGS = $(all_libraries) +libcoff_la_SOURCES = coff.cpp gpdis.cpp gpopcode.cpp disassembler.cpp \ + coff_data.cpp text_coff.cpp cdb_parser.cpp coff_archive.cpp coff_object.cpp +libcoff_la_DEPENDENCIES = coff_data.cpp + +noinst_DATA = coff.xml +coff_data.cpp: ../xml/xml_coff_parser coff.xml + ../xml/xml_coff_parser +CLEANFILES = coff_data.cpp diff --git a/src/coff/base/base.pro b/src/coff/base/base.pro new file mode 100644 index 0000000..4b4986c --- /dev/null +++ b/src/coff/base/base.pro @@ -0,0 +1,6 @@ +STOPDIR = ../../.. +include($${STOPDIR}/lib.pro) + +TARGET = coff +HEADERS += gpopcode.h disassembler.h coff.h coff_object.h coff_archive.h text_coff.h coff_data.h cdb_parser.h +SOURCES += gpopcode.cpp gpdis.cpp disassembler.cpp coff.cpp coff_object.cpp coff_archive.cpp text_coff.cpp coff_data.cpp cdb_parser.cpp diff --git a/src/coff/base/cdb_parser.cpp b/src/coff/base/cdb_parser.cpp new file mode 100644 index 0000000..2e38b84 --- /dev/null +++ b/src/coff/base/cdb_parser.cpp @@ -0,0 +1,417 @@ +/*************************************************************************** + * Copyright (C) 2007 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 "cdb_parser.h" + +#include <ctype.h> +#include "common/global/pfile.h" + +//---------------------------------------------------------------------------- +const CDB::ScopeType::Data CDB::ScopeType::DATA[Nb_Types] = { + { "G", I18N_NOOP("Global") }, + { "F", I18N_NOOP("File") }, + { "L", I18N_NOOP("Local") }, + { "S", I18N_NOOP("Structure") } // ?? +}; + +const CDB::VarType::Data CDB::VarType::DATA[Nb_Types] = { + { "DA", I18N_NOOP("Array") }, + { "DF", I18N_NOOP("Function") }, + { "DG", I18N_NOOP("Generic Pointer") }, + { "DC", I18N_NOOP("Code Pointer") }, + { "DX", I18N_NOOP("External RAM Pointer") }, + { "DD", I18N_NOOP("Internal RAM Pointer") }, + { "DP", I18N_NOOP("Paged Pointer") }, + { "DI", I18N_NOOP("Upper-128-byte Pointer") }, + { "SL", I18N_NOOP("Long") }, + { "SI", I18N_NOOP("Int") }, + { "SC", I18N_NOOP("Char") }, + { "SS", I18N_NOOP("Short") }, + { "SV", I18N_NOOP("Void") }, + { "SF", I18N_NOOP("Float") }, + { "ST", I18N_NOOP("Structure") }, + { "SX", I18N_NOOP("SBIT") }, + { "SB", I18N_NOOP("Bit Field") } +}; + +const CDB::Sign::Data CDB::Sign::DATA[Nb_Types] = { + { "S", I18N_NOOP("Signed") }, + { "U", I18N_NOOP("Unsigned") } +}; + +const CDB::AddressSpaceType::Data CDB::AddressSpaceType::DATA[Nb_Types] = { + { "A", I18N_NOOP("External Stack") }, + { "B", I18N_NOOP("Internal Stack") }, + { "C", I18N_NOOP("Code") }, + { "D", I18N_NOOP("Code / Static Segment") }, + { "E", I18N_NOOP("Lower-128-byte Internal RAM") }, + { "F", I18N_NOOP("External RAM") }, + { "G", I18N_NOOP("Internal RAM") }, + { "H", I18N_NOOP("Bit Addressable") }, + { "I", I18N_NOOP("SFR Space") }, + { "J", I18N_NOOP("SBIT Space") }, + { "R", I18N_NOOP("Register Space") }, + { "Z", I18N_NOOP("Function or Undefined Space") }, +}; + +//---------------------------------------------------------------------------- +CDB::Object::Object(const PURL::Url &url, Log::Base &log) + : _log(log) +{ + PURL::File file(url, log); + if ( !file.openForRead() ) return; + QStringList lines = file.readLines(); + + for (_line=0; _line<uint(lines.count()); _line++) { + _col = 0; + _current = lines[_line]; + if ( _current.isEmpty() ) continue; + char c; + if ( !readChar(c) ) return; + if ( !readAndCheckChar(':') ) return; + Record *record = 0; + bool ok; + switch (c) { + case 'M': ok = parseModuleRecord(record); break; + case 'F': ok = parseFunctionRecord(record); break; + case 'S': ok = parseSymbolRecord(record); break; + case 'T': ok = parseTypeRecord(record); break; + case 'L': ok = parseLinkerRecord(record); break; + default: + log.log(Log::LineType::Error, i18n("Unrecognized record")); + return; + } + if (!ok) { + delete record; + return; + } + _records.append(record); + } +} + +CDB::Object::~Object() +{ + for (uint i=0; i<uint(_records.count()); i++) delete _records[i]; +} + +void CDB::Object::log(Log::LineType type, const QString &message) +{ + _log.log(type, message + " " + i18n("at line #%1, column #%2").arg(_line+1).arg(_col+1)); +} + +void CDB::Object::logMalformed(const QString &detail) +{ + log(Log::LineType::Error, i18n("Malformed record: ") + detail); +} + +bool CDB::Object::readChar(char &c) +{ + if ( _col==uint(_current.length()) ) { + logMalformed(i18n("unexpected end of line")); + return false; + } + c = _current[_col].latin1(); + _col++; + return true; +} + +bool CDB::Object::readAndCheckChar(char c) +{ + char r; + if ( !readChar(r) ) return false; + if ( r!=c ) { + logMalformed(i18n("was expecting '%1'").arg(c)); + return false; + } + return true; +} + +bool CDB::Object::getString(const QString &s, QString &r) +{ + r = s; + if ( r.isEmpty() ) { + logMalformed(i18n("empty name")); + return false; + } + return true; +} + +bool CDB::Object::readFixedLengthString(QString &s, uint size) +{ + s = QString::null; + for (uint i=0; i<size; i++) { + char c; + if ( !readChar(c) ) return false; + s += c; + } + return true; +} + +bool CDB::Object::readStoppedString(QString &name, char stop) +{ + QString s; + for (;;) { + if ( _col==uint(_current.length()) ) { + if ( stop!=0 ) { + logMalformed(i18n("unexpected end of line")); + return false; + } + break; + } + if ( _current[_col]==stop ) break; + s += _current[_col]; + _col++; + } + return getString(s, name); +} + +bool CDB::Object::getUInt(const QString &s, uint &v) +{ + bool ok; + v = s.toUInt(&ok); + if ( !ok ) logMalformed(i18n("was expecting an uint")); + return ok; +} + +bool CDB::Object::readUInt(uint &v) +{ + QString s; + for (;;) { + if ( _col==uint(_current.length()) ) break; + if ( !isdigit(_current[_col].latin1()) ) break; + s += _current[_col]; + _col++; + } + return getUInt(s, v); +} + +bool CDB::Object::readBool(bool &b) +{ + char c; + if ( !readChar(c) ) return false; + if ( c=='0' ) b = false; + else if ( c=='1' ) b = true; + else { + logMalformed(i18n("was expecting a bool ('%1')").arg(c)); + return false; + } + return true; +} + +bool CDB::Object::readHex(uint &v) +{ + QString s; + for (;;) { + if ( _col==uint(_current.length()) ) break; + if ( !isxdigit(_current[_col].latin1()) ) break; + s += _current[_col]; + _col++; + } + return getUInt(s, v); +} + +bool CDB::Object::parseModuleRecord(Record * &record) +{ + ModuleRecord *mr = new ModuleRecord; + record = mr; + return readStoppedString(mr->filename, 0); +} + +bool CDB::Object::parse(Scope &scope, QString &name) +{ + QString s; + if ( !readFixedLengthString(s, 1) ) return false; + scope.type = ScopeType::fromKey(s); + switch (scope.type.type()) { + case ScopeType::Structure: + case ScopeType::Global: break; + case ScopeType::File: + case ScopeType::Local: + if ( !readStoppedString(scope.name, '$') ) return false; + break; + case ScopeType::Nb_Types: + logMalformed(i18n("unknown ScopeType")); + return false; + } + if ( !readAndCheckChar('$') ) return false; + if ( !readStoppedString(name, '$') ) return false; + if ( !readAndCheckChar('$') ) return false; + if ( !readUInt(scope.level) ) return false; + if ( !readAndCheckChar('$') ) return false; + if ( !readUInt(scope.block) ) return false; + return true; +} + +bool CDB::Object::parse(TypeChain &typeChain) +{ + uint nb; + if ( !readAndCheckChar('{') ) return false; + if ( !readUInt(nb) ) return false; + if ( !readAndCheckChar('}') ) return false; + QString s; + if ( !readStoppedString(s, ':') ) return false; + QStringList list = QStringList::split(',', s, true); + for (uint i=0; i<uint(list.count()); i++) { + DCLType type; + QString key = list[i].mid(0, 2); + type.type = VarType::fromKey(key); + switch (type.type.type()) { + case VarType::Array: + case VarType::BitField: + if ( !getUInt(list[i].mid(2), type.nb) ) return false; + break; + case VarType::Structure: + if ( !getString(list[i].mid(2), type.name) ) return false; + break; + case VarType::Nb_Types: + logMalformed(i18n("unknown DCLType")); + return false; + default: break; + } + typeChain.types.append(type); + } + if ( !readAndCheckChar(':') ) return false; + if ( !readFixedLengthString(s, 1) ) return false; + typeChain.sign = Sign::fromKey(s); + if ( typeChain.sign==Sign::Nb_Types ) { + logMalformed(i18n("unknown Sign")); + return false; + } + return true; +} + +bool CDB::Object::parse(AddressSpace &as) +{ + QString s; + if ( !readFixedLengthString(s, 1) ) return false; + as.type = AddressSpaceType::fromKey(s); + if ( as.type==AddressSpaceType::Nb_Types ) { + logMalformed(i18n("unknown AddressSpaceType")); + return false; + } + if ( !readAndCheckChar(',') ) return false; + if ( !readBool(as.onStack) ) return false; + if ( !readAndCheckChar(',') ) return false; + if ( !readUInt(as.stackOffset) ) return false; + if ( as.type==AddressSpaceType::Register ) { + if ( !readAndCheckChar(',') ) return false; + if ( !readAndCheckChar('[') ) return false; + if ( !readStoppedString(s, ']') ) return false; + as.registers = QStringList::split(',', s, true); + if ( as.registers.count()==0 ) { + logMalformed(i18n("no register defined")); + return false; + } + if ( !readAndCheckChar(']') ) return false; + } + return true; +} + +bool CDB::Object::parse(SymbolRecord &sr) +{ + if ( !parse(sr.scope, sr.name) ) return false; + if ( !readAndCheckChar('(') ) return false; + if ( !parse(sr.typeChain) ) return false; + if ( !readAndCheckChar(')') ) return false; + if ( !readAndCheckChar(',') ) return false; + if ( !parse(sr.addressSpace) ) return false; + return true; +} + +bool CDB::Object::parse(TypeMember &tm) +{ + if ( !readAndCheckChar('(') ) return false; + if ( !readAndCheckChar('{') ) return false; + if ( !readUInt(tm.offset) ) return false; + if ( !readAndCheckChar('}') ) return false; + if ( !readAndCheckChar('S') ) return false; + if ( !readAndCheckChar(':') ) return false; + if ( !parse(tm.symbol) ) return false; + if ( !readAndCheckChar(')') ) return false; + return true; +} + +bool CDB::Object::parseSymbolRecord(Record * &record) +{ + SymbolRecord *sr = new SymbolRecord; + record = sr; + if ( !parse(*sr) ) return false; + return true; +} + +bool CDB::Object::parseFunctionRecord(Record * &record) +{ + FunctionRecord *fr = new FunctionRecord; + record = fr; + if ( !parse(*fr) ) return false; + if ( !readAndCheckChar(',') ) return false; + if ( !readBool(fr->isInterruptHandler) ) return false; + if ( !readAndCheckChar(',') ) return false; + if ( !readUInt(fr->interruptHandler) ) return false; + if ( !readAndCheckChar(',') ) return false; + if ( !readUInt(fr->registerBank) ) return false; + return true; +} + +bool CDB::Object::parseTypeRecord(Record * &record) +{ + TypeRecord *tr = new TypeRecord; + record = tr; + if ( !readAndCheckChar('F') ) return false; + if ( !readStoppedString(tr->filename, '$') ) return false; + if ( !readAndCheckChar('$') ) return false; + if ( !readStoppedString(tr->name, '[') ) return false; + if ( !readAndCheckChar('[') ) return false; + for (;;) { + TypeMember tm; + if ( !parse(tm) ) return false; + tr->members.append(tm); + if ( _current[_col]==']' ) break; + } + if ( !readAndCheckChar(']') ) return false; + return true; +} + +bool CDB::Object::parseLinkerRecord(Record * &record) +{ + LinkerRecord *lr = new LinkerRecord; + record = lr; + char c; + if ( !readChar(c) ) return false; + switch (c) { + case 'A': + lr->type = LinkerRecord::AsmLine; + if ( !readAndCheckChar('$') ) return false; + if ( !readStoppedString(lr->filename, '$') ) return false; + if ( !readAndCheckChar('$') ) return false; + if ( !readUInt(lr->line) ) return false; + break; + case 'C': + lr->type = LinkerRecord::CLine; + if ( !readAndCheckChar('$') ) return false; + if ( !readStoppedString(lr->filename, '$') ) return false; + if ( !readAndCheckChar('$') ) return false; + if ( !readUInt(lr->line) ) return false; + if ( !readAndCheckChar('$') ) return false; + if ( !readUInt(lr->level) ) return false; + if ( !readAndCheckChar('$') ) return false; + if ( !readUInt(lr->block) ) return false; + break; + case 'X': + lr->type = LinkerRecord::EndAddress; + if ( !parse(lr->scope, lr->name) ) return false; + break; + default: + lr->type = LinkerRecord::Address; + if ( !parse(lr->scope, lr->name) ) return false; + break; + } + if ( !readAndCheckChar(':') ) return false; + if ( !readHex(lr->address) ) return false; + return true; +} diff --git a/src/coff/base/cdb_parser.h b/src/coff/base/cdb_parser.h new file mode 100644 index 0000000..42572ab --- /dev/null +++ b/src/coff/base/cdb_parser.h @@ -0,0 +1,166 @@ +/*************************************************************************** + * Copyright (C) 2007 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. * + ***************************************************************************/ +#ifndef SDCC_CDB_PARSER_H +#define SDCC_CDB_PARSER_H + +#include "common/common/key_enum.h" +#include "common/global/log.h" +#include "common/global/purl.h" + +namespace CDB +{ + +//---------------------------------------------------------------------------- +class Record +{ +public: +}; + +class ModuleRecord : public Record +{ +public: + QString filename; +}; + +BEGIN_DECLARE_ENUM(ScopeType) + Global = 0, File, Local, Structure +END_DECLARE_ENUM_STD(ScopeType) + +class Scope +{ +public: + ScopeType type; + QString name; // file or function name + uint level, block; +}; + +BEGIN_DECLARE_ENUM(VarType) + Array = 0, Function, GenericPointer, CodePointer, ExternalRamPointer, + InternalRamPointer, PagedPointer, Upper128bytesPointer, Long, Int, Char, + Short, Void, Float, Structure, Sbit, BitField +END_DECLARE_ENUM_STD(VarType) + +class DCLType +{ +public: + VarType type; + uint nb; // for Array and BitField + QString name; // for Structure +}; + +BEGIN_DECLARE_ENUM(Sign) + Signed = 0, Unsigned +END_DECLARE_ENUM_STD(Sign) + +class TypeChain +{ +public: + QValueVector<DCLType> types; + Sign sign; +}; + +BEGIN_DECLARE_ENUM(AddressSpaceType) + ExternalStack = 0, InternalStack, Code, CodeStaticSegment, + Lower128bytesInternalRam, ExternalRam, InternalRam, BitAddressable, + SFR, SBIT, Register, FunctionOrUndefined +END_DECLARE_ENUM_STD(AddressSpaceType) + +class AddressSpace { +public: + AddressSpaceType type; + bool onStack; + uint stackOffset; // valid if onStack is true + QStringList registers; // for Register type +}; + +class SymbolRecord : public Record +{ +public: + QString name; + Scope scope; + TypeChain typeChain; + AddressSpace addressSpace; +}; + +class FunctionRecord : public SymbolRecord +{ +public: + bool isInterruptHandler; + uint interruptHandler, registerBank; // if isInterruptHandler is true +}; + +class TypeMember +{ +public: + uint offset; + SymbolRecord symbol; +}; + +class TypeRecord : public Record +{ +public: + QString filename, name; + QValueVector<TypeMember> members; +}; + +class LinkerRecord : public Record +{ +public: + enum Type { Address = 0, EndAddress, AsmLine, CLine, Nb_Types }; + Type type; + Scope scope; // for Address and EndAddress + QString name; // for Address and EndAddress + uint address; + uint line; // for AsmLine and CLine + QString filename; // for AsmLine and CLine + uint block, level; // for CLine +}; + +//---------------------------------------------------------------------------- +class Object +{ +public: + Object(const PURL::Url &url, Log::Base &log); + virtual ~Object(); + +private: + Log::Base &_log; + QString _current; + uint _line, _col; + QValueVector<Record *> _records; + + void log(Log::LineType type, const QString &message); + void logMalformed(const QString &detail); + bool readBool(bool &b); + bool getUInt(const QString &s, uint &r); + bool readUInt(uint &v); + bool readChar(char &c); + bool readAndCheckChar(char c); + bool getString(const QString &s, QString &r); + bool readStoppedString(QString &s, char stop); + bool readFixedLengthString(QString &s, uint size); + bool readHex(uint &v); + + bool parse(Scope &scope, QString &name); + bool parse(TypeChain &typeChain); + bool parse(TypeRecord &typeRecord); + bool parse(SymbolRecord &sr); + bool parse(AddressSpace &addressSpace); + bool parse(TypeMember &typeMember); + + bool parseModuleRecord(Record * &record); + bool parseFunctionRecord(Record * &record); + bool parseSymbolRecord(Record * &record); + bool parseTypeRecord(Record * &record); + bool parseLinkerRecord(Record * &record); +}; + +} // namespace + +#endif diff --git a/src/coff/base/coff.cpp b/src/coff/base/coff.cpp new file mode 100644 index 0000000..5eaad84 --- /dev/null +++ b/src/coff/base/coff.cpp @@ -0,0 +1,97 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 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.h" + +#include <time.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" + +//---------------------------------------------------------------------------- +const CoffType::Data CoffType::DATA[Nb_Types] = { + { "archive", I18N_NOOP("Archive") }, + { "object", I18N_NOOP("Object") } +}; + +const Coff::Format::Data Coff::Format::DATA[Nb_Types] = { + { 0, I18N_NOOP("Old Microchip"), 0x1234, { 20, 16, 40, 18, 16, 12 } }, + { 0, I18N_NOOP("PIC30"), 0x1236, { 20, 28, 40, 18, 8, 10 } }, // from PIC30 binutils "coff.h" file + { 0, I18N_NOOP("New Microchip"), 0x1240, { 20, 18, 40, 20, 16, 12 } } // (C18 >= 3.0) +}; + +CoffType Coff::identify(const PURL::Url &url, Log::Base &log) +{ + PURL::File file(url, log); + if ( !file.openForRead() ) return CoffType::Nb_Types; + QByteArray data = file.readAll(); + if ( log.hasError() ) return CoffType::Nb_Types; + uint offset = 0; + Format format; + Q_UINT32 magic; + return identify(data, offset, log, format, magic); +} + +CoffType Coff::identify(const QByteArray &data, uint &offset, Log::Base &log, Format &format, Q_UINT32 &magic) +{ + QString id = "!<arch>\012"; + if ( data.count()>=id.length() ) { + QString s = QString::fromAscii(data.data(), id.length()); + if ( s==id ) { + offset += id.length(); + return CoffType::Archive; + } + } + if ( !getULong(data, offset, 2, log, magic) ) return CoffType::Nb_Types; + log.log(Log::DebugLevel::Extra, QString("COFF format: %1").arg(toHexLabel(magic, 4))); + format = Format::Nb_Types; + FOR_EACH(Format, f) if ( magic==f.data().magic ) format = f; + return CoffType::Object; +} + +//---------------------------------------------------------------------------- +bool Coff::getULong(const QByteArray &data, uint &offset, uint nbBytes, Log::Base &log, Q_UINT32 &v) +{ + bool ok; + v = ::getULong(data, offset, nbBytes, &ok); + if ( !ok ) { + log.log(Log::LineType::Error, i18n("COFF file is truncated (offset: %1 nbBytes: %2 size:%3).").arg(offset).arg(nbBytes).arg(data.count())); + return false; + } + offset += nbBytes; + return true; +} + +bool Coff::getString(const QByteArray &data, uint &offset, uint nbChars, Log::Base &log, QString &name) +{ + if ( !checkAvailable(data, offset, nbChars) ) { + log.log(Log::LineType::Error, i18n("COFF file is truncated (offset: %1 nbBytes: %2 size:%3).").arg(offset).arg(nbChars).arg(data.count())); + return false; + } + name = QString::fromAscii(data.data()+offset, nbChars); + offset += nbChars; + return true; +} + +//---------------------------------------------------------------------------- +bool Coff::Base::initParse(CoffType type, QByteArray &data, uint &offset, Log::Base &log) +{ + PURL::File file(_url, log); + if ( !file.openForRead() ) return false; + data = file.readAll(); + if ( log.hasError() ) return false; + if ( identify(data, offset, log, _format, _magic)!=type ) { + log.log(Log::LineType::Error, i18n("Could not recognize file (magic number is %1).").arg(toHexLabel(_magic, 4))); + return false; + } + return true; +} diff --git a/src/coff/base/coff.h b/src/coff/base/coff.h new file mode 100644 index 0000000..edd0ae5 --- /dev/null +++ b/src/coff/base/coff.h @@ -0,0 +1,64 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 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. * + ***************************************************************************/ +#ifndef COFF_H +#define COFF_H + +#include "common/global/global.h" +#include "devices/pic/base/pic.h" +#include "common/global/purl.h" +#include "common/global/log.h" + +BEGIN_DECLARE_ENUM(CoffType) + Archive = 0, Object +END_DECLARE_ENUM_STD(CoffType) + +//---------------------------------------------------------------------------- +namespace Coff +{ +extern bool getString(const QByteArray &data, uint &offset, uint nbChars, Log::Base &log, QString &name); +extern bool getULong(const QByteArray &data, uint &offset, uint nbBytes, Log::Base &log, Q_UINT32 &v); + +//---------------------------------------------------------------------------- +enum SizeType { HeaderSize = 0, OptHeaderSize, SectionHeaderSize, SymbolSize, + LineNumberSize, RelocationSize, Nb_SizeTypes }; +struct FormatData { + const char *key, *label; + uint magic; + uint sizes[Nb_SizeTypes]; +}; +BEGIN_DECLARE_ENUM(Format) + OldMicrochip = 0, PIC30, NewMicrochip +END_DECLARE_ENUM(Format, FormatData) + +extern CoffType identify(const PURL::Url &url, Log::Base &log); +extern CoffType identify(const QByteArray &data, uint &offset, Log::Base &log, Format &format, Q_UINT32 &magic); + +//---------------------------------------------------------------------------- +class Base +{ +public: + Base(const PURL::Url &url) : _url(url) {} + virtual ~Base() {} + virtual bool parse(Log::Base &log) = 0; + PURL::Url url() const { return _url; } + uint magic() const { return _magic; } + + virtual Log::KeyList information() const = 0; + +protected: + PURL::Url _url; + Format _format; + Q_UINT32 _magic; + + bool initParse(CoffType type, QByteArray &data, uint &offset, Log::Base &log); +}; + +} // namespace + +#endif diff --git a/src/coff/base/coff.xml b/src/coff/base/coff.xml new file mode 100644 index 0000000..229d11a --- /dev/null +++ b/src/coff/base/coff.xml @@ -0,0 +1,342 @@ +<!-- ************************************************************************* --> +<!-- * 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. * --> +<!-- *************************************************************************/--> +<!DOCTYPE piklab> + +<type name="coff"> + <device name="10f200" id="0xf200" /> + <device name="10f202" id="0xf202" /> + <device name="10f204" id="0xf204" /> + <device name="10f206" id="0xf206" /> + <device name="10f220" id="0xf220" /> + <device name="10f222" id="0xf222" /> + <device name="12c508" id="0x2508" /> + <device name="12c508a" id="0x508a" /> + <device name="12c509" id="0x2509" /> + <device name="12c509a" id="0x509a" /> + <device name="12c671" id="0x2671" /> + <device name="12c672" id="0x2672" /> + <device name="12ce518" id="0x2518" /> + <device name="12ce519" id="0x2519" /> + <device name="12ce673" id="0x2673" /> + <device name="12ce674" id="0x2674" /> + <device name="12cr509a" id="0xd09a" /> + <device name="12f508" id="0x2508" /> + <device name="12f509" id="0x2509" /> + <device name="12f510" id="0x2510" /> + <device name="12f629" id="0x2629" /> + <device name="12f635" id="0x2635" /> + <device name="12f675" id="0x2675" /> + <device name="12f683" id="0x2683" /> + <device name="14000" id="0x4000" /> +<!-- <device name="16c5x" id="0x658a" /> --> +<!-- <device name="16cxx" id="0x6c77" /> --> + <device name="16c432" id="0x6432" /> + <device name="16c433" id="0x6433" /> + <device name="16c505" id="0x2505" /> + <device name="16c52" id="0x6c52" /> + <device name="16c54" id="0x6c54" /> + <device name="16c54a" id="0x654a" /> + <device name="16c54b" id="0x654b" /> + <device name="16c54c" id="0x654c" /> + <device name="16c55" id="0x6c55" /> + <device name="16c55a" id="0x655a" /> + <device name="16c554" id="0x6554" /> + <device name="16c557" id="0x6557" /> + <device name="16c558" id="0x6558" /> + <device name="16c56" id="0x6c56" /> + <device name="16c56a" id="0x656a" /> + <device name="16c57" id="0x6c57" /> + <device name="16c57c" id="0x657c" /> + <device name="16c58a" id="0x658a" /> + <device name="16c58b" id="0x658b" /> + <device name="16c61" id="0x6c61" /> + <device name="16c62" id="0x6c62" /> + <device name="16c62a" id="0x662a" /> + <device name="16c62b" id="0x662b" /> + <device name="16c620" id="0x6620" /> + <device name="16c620a" id="0x620a" /> + <device name="16c621" id="0x6621" /> + <device name="16c621a" id="0x621a" /> + <device name="16c622" id="0x6622" /> + <device name="16c622a" id="0x622a" /> + <device name="16c63" id="0x6c63" /> + <device name="16c63a" id="0x663a" /> + <device name="16c64" id="0x6c64" /> + <device name="16c64a" id="0x664a" /> + <device name="16c642" id="0x6642" /> + <device name="16c65" id="0x6c65" /> + <device name="16c65a" id="0x665a" /> + <device name="16c65b" id="0x665b" /> + <device name="16c66" id="0x6c66" /> + <device name="16c662" id="0x6662" /> + <device name="16c67" id="0x6c67" /> + <device name="16c71" id="0x6c71" /> + <device name="16c710" id="0x6710" /> + <device name="16c711" id="0x6711" /> + <device name="16c712" id="0x6712" /> + <device name="16c715" id="0x6715" /> + <device name="16c716" id="0x6716" /> + <device name="16c717" id="0x6717" /> + <device name="16c72" id="0x6c72" /> + <device name="16c72a" id="0x672a" /> + <device name="16c73" id="0x673a" /> + <device name="16c73a" id="0x673a" /> + <device name="16c73b" id="0x673b" /> + <device name="16c74" id="0x6c74" /> + <device name="16c745" id="0x6745" /> +<!-- <device name="16c747" id="0x6747" /> --> + <device name="16c74a" id="0x674a" /> + <device name="16c74b" id="0x674b" /> + <device name="16c76" id="0x6c76" /> + <device name="16c765" id="0x6765" /> + <device name="16c77" id="0x6c77" /> + <device name="16c770" id="0x6770" /> + <device name="16c771" id="0x6771" /> + <device name="16c773" id="0x6773" /> + <device name="16c774" id="0x6774" /> + <device name="16c781" id="0x6781" /> + <device name="16c782" id="0x6782" /> + <device name="16c84" id="0x6c84" /> + <device name="16c923" id="0x6923" /> + <device name="16c924" id="0x6924" /> + <device name="16c925" id="0x6925" /> + <device name="16c926" id="0x6926" /> + <device name="16ce623" id="0x6623" /> + <device name="16ce624" id="0x6624" /> + <device name="16ce625" id="0x6625" /> +<!-- <device name="16cr54" id="0xdc54" /> --> + <device name="16cr54a" id="0xd54a" /> + <device name="16cr54b" id="0xd54b" /> + <device name="16cr54c" id="0xdc54" /> + <device name="16cr56a" id="0xd56a" /> +<!-- <device name="16cr57a" id="0xd57a" /> --> + <device name="16cr57b" id="0xd57b" /> + <device name="16cr57c" id="0xd57c" /> + <device name="16cr58a" id="0xd58a" /> + <device name="16cr58b" id="0xd58b" /> + <device name="16cr62" id="0xdc62" /> + <device name="16cr620a" id="0xd20a" /> + <device name="16cr63" id="0x6d63" /> + <device name="16cr64" id="0xdc64" /> + <device name="16cr65" id="0x6d65" /> + <device name="16cr72" id="0x6d72" /> + <device name="16cr83" id="0xdc83" /> + <device name="16cr84" id="0xdc84" /> + <device name="16f505" id="0x654f" /> + <device name="16f54" id="0x654f" /> + <device name="16f57" id="0x657f" /> + <device name="16f59" id="0x659f" /> + <device name="16f610" id="0x6610" /> + <device name="16f627" id="0x6627" /> + <device name="16f627a" id="0x627a" /> + <device name="16f628" id="0x6628" /> + <device name="16f628a" id="0x628a" /> + <device name="16f630" id="0x6630" /> + <device name="16f636" id="0x6636" /> + <device name="16f639" id="0x6639" /> + <device name="16f648a" id="0x648a" /> + <device name="16f676" id="0x6676" /> + <device name="16f684" id="0x6684" /> + <device name="16f685" id="0x6685" /> + <device name="16f687" id="0x6687" /> + <device name="16f688" id="0x6688" /> + <device name="16f689" id="0x6689" /> + <device name="16f690" id="0x6690" /> + <device name="16f716" id="0x716f" /> + <device name="16f72" id="0x672f" /> + <device name="16f73" id="0x673f" /> + <device name="16f737" id="0x737f" /> + <device name="16f74" id="0x674f" /> + <device name="16f747" id="0x6747" /> + <device name="16f76" id="0x676f" /> + <device name="16f767" id="0x767f" /> + <device name="16f77" id="0x677f" /> + <device name="16f777" id="0x777f" /> + <device name="16f785" id="0x785f" /> + <device name="16f818" id="0x818f" /> + <device name="16f819" id="0x819f" /> + <device name="16f83" id="0x6c83" /> + <device name="16f84" id="0x6f84" /> + <device name="16f84a" id="0x684a" /> + <device name="16f87" id="0x687f" /> + <device name="16f870" id="0x870f" /> + <device name="16f871" id="0x871f" /> + <device name="16f872" id="0x872f" /> + <device name="16f873" id="0x873f" /> + <device name="16f873a" id="0x873a" /> + <device name="16f874" id="0x874f" /> + <device name="16f874a" id="0x874a" /> + <device name="16f876" id="0x876f" /> + <device name="16f876a" id="0x876a" /> + <device name="16f877" id="0x877f" /> + <device name="16f877a" id="0x877a" /> + <device name="16f88" id="0x688f" /> + <device name="16f882" id="0x882f" /> + <device name="16f883" id="0x883f" /> + <device name="16f884" id="0x884f" /> + <device name="16f886" id="0x886f" /> + <device name="16f887" id="0x887f" /> + <device name="16f913" id="0x913f" /> + <device name="16f914" id="0x914f" /> + <device name="16f916" id="0x916f" /> + <device name="16f917" id="0x917f" /> + <device name="16hv540" id="0x6540" /> +<!-- <device name="17cxx" id="0x7756" /> --> + <device name="17c42" id="0x7c42" /> + <device name="17c42a" id="0x742a" /> + <device name="17c43" id="0x7c43" /> + <device name="17c44" id="0x7c44" /> + <device name="17c752" id="0x7752" /> + <device name="17c756" id="0x7756" /> + <device name="17c756a" id="0x756a" /> + <device name="17c762" id="0x7762" /> + <device name="17c766" id="0x7766" /> + <device name="17cr42" id="0xe42a" /> + <device name="17cr43" id="0xec43" /> + + <device name="18c242" id="0x8242" /> + <device name="18c252" id="0x8252" /> + <device name="18c442" id="0x8442" /> + <device name="18c452" id="0x8452" /> + <device name="18c601" id="0x8601" /> + <device name="18c658" id="0x8658" /> + <device name="18c801" id="0x8801" /> + <device name="18c858" id="0x8858" /> + <device name="18f1220" id="0xa122" /> + <device name="18f1230" id="0xa123 0x1230" /> +<!-- <device name="18f1231" id="0x1231" /> --> + <device name="18f1320" id="0xa132" /> + <device name="18f1330" id="0xa133 0x1330" /> +<!-- <device name="18f1331" id="0x1331" /> --> + <device name="18f2220" id="0xa222" /> + <device name="18f2221" id="0x2221" /> + <device name="18f2320" id="0xa232" /> + <device name="18f2321" id="0x2321" /> + <device name="18f2331" id="0x2331" /> + <device name="18f2410" id="0x2410" /> + <device name="18f242" id="0x242f" /> + <device name="18f2420" id="0x2420" /> + <device name="18f2431" id="0x2431" /> + <device name="18f2439" id="0x2439" /> + <device name="18f2450" id="0x2450" /> + <device name="18f2455" id="0x2455" /> + <device name="18f248" id="0x8248" /> + <device name="18f2480" id="0x2480" /> + <device name="18f24J10" id="0xD410" /> + <device name="18f2510" id="0x2510" /> + <device name="18f2515" id="0x2515" /> + <device name="18f252" id="0x252f" /> + <device name="18f2520" id="0x2520" /> + <device name="18f2525" id="0x2525" /> + <device name="18f2539" id="0x2539" /> + <device name="18f2550" id="0x2550" /> + <device name="18f258" id="0x8258" /> + <device name="18f2580" id="0x2580" /> + <device name="18f2585" id="0x2585" /> + <device name="18f25J10" id="0xD510" /> + <device name="18f2610" id="0x2610 0xa261" /> + <device name="18f2620" id="0x2620 0xa262" /> + <device name="18f2680" id="0x2680" /> +<!-- <device name="18f2681" id="0x2681" /> --> + <device name="18f2682" id="0x2682" /> + <device name="18f2685" id="0x2685" /> + <device name="18f4220" id="0xa422" /> + <device name="18f4221" id="0x4221" /> + <device name="18f4320" id="0xa432" /> + <device name="18f4321" id="0x4321" /> + <device name="18f4331" id="0x4331" /> + <device name="18f4410" id="0x4410" /> + <device name="18f442" id="0x442f" /> + <device name="18f4420" id="0x4420" /> + <device name="18f4431" id="0x4431" /> + <device name="18f4439" id="0x4439" /> + <device name="18f4450" id="0x4450" /> + <device name="18f4455" id="0x4455" /> + <device name="18f448" id="0x8448" /> + <device name="18f4480" id="0x4480" /> + <device name="18f44J10" id="0xE410" /> + <device name="18f4510" id="0x4510" /> + <device name="18f4515" id="0x4515" /> + <device name="18f452" id="0x452f" /> + <device name="18f4520" id="0x4520" /> + <device name="18f4525" id="0x4525" /> + <device name="18f4539" id="0x4539" /> + <device name="18f4550" id="0x4550" /> + <device name="18f458" id="0x8458" /> + <device name="18f4580" id="0x4580" /> + <device name="18f4585" id="0x4585" /> + <device name="18f45J10" id="0xE510" /> + <device name="18f4610" id="0xa461 0x4610" /> + <device name="18f4620" id="0xa462 0x4620" /> + <device name="18f4680" id="0x4680" /> +<!-- <device name="18f4681" id="0x4681" /> --> + <device name="18f4682" id="0x4682" /> + <device name="18f4685" id="0x4685" /> + <device name="18f6310" id="0xa631 0x6310" /> + <device name="18f6390" id="0xa639 0x6390" /> + <device name="18f6410" id="0xa641 0x6410" /> + <device name="18f6490" id="0xa649 0x6490" /> +<!-- <device name="18f64j15" id="0xb415" /> --> + <device name="18f6520" id="0xa652" /> + <device name="18f6525" id="0x6525" /> + <device name="18f6527" id="0x6527" /> + <device name="18f6585" id="0x6585" /> + <device name="18f65j10" id="0xb510" /> + <device name="18f65j15" id="0xb515" /> + <device name="18f6620" id="0xa662" /> + <device name="18f6621" id="0xa621" /> + <device name="18f6622" id="0xf622" /> + <device name="18f6627" id="0xa627 0x6627" /> + <device name="18f6680" id="0x6680" /> + <device name="18f66j10" id="0xb610" /> + <device name="18f66j15" id="0xb615" /> + <device name="18f66j60" id="0xb660" /> + <device name="18f66j65" id="0xb665" /> + <device name="18f6720" id="0xa672" /> + <device name="18f6722" id="0x6722" /> + <device name="18f67j10" id="0xb710" /> + <device name="18f67j60" id="0xb760" /> + <device name="18f8310" id="0x8310" /> + <device name="18f8390" id="0x8390" /> + <device name="18f8410" id="0x8410" /> + <device name="18f8490" id="0x8490" /> +<!-- <device name="18f84j15" id="0xc415" /> --> + <device name="18f8520" id="0xa852" /> + <device name="18f8525" id="0x8525" /> + <device name="18f8527" id="0x8527" /> + <device name="18f8585" id="0x8585" /> + <device name="18f85j10" id="0xc510" /> + <device name="18f85j15" id="0xc515" /> + <device name="18f8620" id="0xa862" /> + <device name="18f8621" id="0x8621" /> + <device name="18f8622" id="0x8622" /> + <device name="18f8627" id="0x8627" /> + <device name="18f8680" id="0x8680" /> + <device name="18f86j10" id="0xc610" /> + <device name="18f86j15" id="0xc615" /> + <device name="18f86j60" id="0xc660" /> + <device name="18f86j65" id="0xc665" /> + <device name="18f8720" id="0xa872" /> + <device name="18f8722" id="0x8721" /> + <device name="18f87j10" id="0xc710" /> + <device name="18f87j60" id="0xc760" /> + <device name="18f96j60" id="0xd660" /> + <device name="18f96j65" id="0xd665" /> + <device name="18f97j60" id="0xd760" /> +<!-- + <device name="rf509af" id="0x6509" /> + <device name="rf509ag" id="0x7509" /> + <device name="rf675f" id="0x3675" /> + <device name="rf675h" id="0x4675" /> + <device name="rf675k" id="0x5675" /> + <device name="sx18" id="0x0018" /> + <device name="sx20" id="0x0020" /> + <device name="sx28" id="0x0028" /> +--> +</type> diff --git a/src/coff/base/coff_archive.cpp b/src/coff/base/coff_archive.cpp new file mode 100644 index 0000000..72a8883 --- /dev/null +++ b/src/coff/base/coff_archive.cpp @@ -0,0 +1,129 @@ +/*************************************************************************** + * 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_archive.h" + +//---------------------------------------------------------------------------- +Coff::Member::Member(const QByteArray &data, uint &offset, Log::Base &log) +{ + // parse header + QString s; + if ( !getString(data, offset, 256, log, s) ) return; + int i = s.find('/'); + if ( i==-1 ) { + log.log(Log::LineType::Error, i18n("Member name not terminated by '/' (\"%1\").").arg(s)); + return; + } + _name = s.mid(0, i); + if ( !getString(data, offset, 12, log, s) ) return; // mtime + if ( !getString(data, offset, 10, log, s) ) return; + i = s.find('l'); + if ( i==-1 ) { + log.log(Log::LineType::Error, i18n("File size not terminated by 'l' (\"%1\").").arg(s)); + return; + } + bool ok; + _nbBytes = s.mid(0, i).toUInt(&ok); + if ( !ok ) { + log.log(Log::LineType::Error, i18n("Wrong format for file size \"%1\".").arg(s)); + return; + } + Q_UINT32 v; + if ( !getULong(data, offset, 2, log, v) ) return; + log.log(Log::DebugLevel::Extra, i18n("Magic number: %1").arg(toHexLabel(v, 4))); +// if ( v!=0x600A ) { +// log.log(Log::LineType::Error, i18n("Wrong magic for Microchip archive (\"%1\").").arg(toHexLabel(v, 4))); +// return; +// } + offset += _nbBytes; +} + +//---------------------------------------------------------------------------- +Coff::Archive::Archive(const PURL::Url &url) + : Base(url) +{} + +bool Coff::Archive::parse(Log::Base &log) +{ + QByteArray data; + uint offset = 0, symbolEnd = 0; + Member *symbol = 0; + if ( !initParse(CoffType::Archive, data, offset, log) ) return false; + for (;;) { + if ( offset==uint(data.count()) ) break; // end of archive + uint start = offset; + Member *member = new Member(data, offset, log); + if ( log.hasError() ) return false; + if ( member->name().isEmpty() ) { + symbolEnd = offset; + symbol = member; + } else { + _members[member->name()] = member; + _offsets[start] = member; + } + } + if (symbol) { + if ( !readSymbols(data, symbolEnd - symbol->nbBytes(), log) ) return false; + delete symbol; + } + return true; +} + +Coff::Archive::~Archive() +{ + QMap<QString, Member *>::const_iterator it; + for (it=_members.begin(); it!=_members.end(); ++it) delete it.data(); +} + +bool Coff::Archive::readSymbols(const QByteArray &data, uint offset, Log::Base &log) +{ + Q_UINT32 nb; + if ( !getULong(data, offset, 4, log, nb) ) return false; + QValueVector<Member *> members(nb); + for (uint i=0; i<nb; i++) { + Q_UINT32 start; + if ( !getULong(data, offset, 4, log, start) ) return false; + if ( !_offsets.contains(start) ) { + log.log(Log::LineType::Error, i18n("Unknown file member offset: %1").arg(toHexLabel(start, 8))); + return false; + } + members[i] = _offsets[start]; + } + for (uint i=0; i<nb; i++) { + QString name(data.data() + offset); + offset += name.length() + 1; + _symbols[name] = members[i]; + } + return true; +} + +Log::KeyList Coff::Archive::information() const +{ + Log::KeyList keys(i18n("Information:")); + keys.append(i18n("No. of file members:"), QString::number(members().count())); + keys.append(i18n("No. of symbols:"), QString::number(symbols().count())); + return keys; +} + +Log::KeyList Coff::Archive::membersInformation() const +{ + Log::KeyList keys(i18n("File Members:")); + QMap<QString, Member *>::const_iterator it; + for (it=members().begin(); it!=members().end(); ++it) + keys.append(it.key(), i18n("size: %1 bytes").arg(it.data()->nbBytes())); + return keys; +} + +Log::KeyList Coff::Archive::symbolsInformation() const +{ + Log::KeyList keys(i18n("Symbols:")); + QMap<QString, Member *>::const_iterator it; + for (it=symbols().begin(); it!=symbols().end(); ++it) + keys.append(it.key(), it.data()->name()); + return keys; +} diff --git a/src/coff/base/coff_archive.h b/src/coff/base/coff_archive.h new file mode 100644 index 0000000..ba43a38 --- /dev/null +++ b/src/coff/base/coff_archive.h @@ -0,0 +1,53 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifndef COFF_ARCHIVE_H +#define COFF_ARCHIVE_H + +#include "coff.h" + +namespace Coff +{ +//---------------------------------------------------------------------------- +class Member +{ +public: + Member(const QByteArray &data, uint &offset, Log::Base &log); + QString name() const { return _name; } + uint nbBytes() const { return _nbBytes; } + +private: + QString _name; + uint _nbBytes; +}; + +//---------------------------------------------------------------------------- +class Archive : public Base +{ +public: + Archive(const PURL::Url &url); + virtual ~Archive(); + virtual bool parse(Log::Base &log); + const QMap<QString, Member *>members() const { return _members; } + const QMap<QString, Member *>symbols() const { return _symbols; } + + virtual Log::KeyList information() const; + Log::KeyList membersInformation() const; + Log::KeyList symbolsInformation() const; + +private: + QMap<QString, Member *> _members; // name -> Member * + QMap<uint, Member *> _offsets; // offset -> Member * + QMap<QString, Member *> _symbols; // name -> Member * + + bool readSymbols(const QByteArray &data, uint offset, Log::Base &log); +}; + +} // namespace + +#endif diff --git a/src/coff/base/coff_data.h b/src/coff/base/coff_data.h new file mode 100644 index 0000000..9676e42 --- /dev/null +++ b/src/coff/base/coff_data.h @@ -0,0 +1,22 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifndef COFF_DATA_H +#define COFF_DATA_H + +namespace Coff +{ + enum { MAX_NB_IDS = 2 }; + struct Data { + uint ids[MAX_NB_IDS]; + }; + extern QString findId(uint id); + +} // namespace + +#endif 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; +} diff --git a/src/coff/base/coff_object.h b/src/coff/base/coff_object.h new file mode 100644 index 0000000..8b98129 --- /dev/null +++ b/src/coff/base/coff_object.h @@ -0,0 +1,322 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifndef COFF_OBJECT_H +#define COFF_OBJECT_H + +#include "coff.h" +#include "devices/base/register.h" + +namespace Coff +{ +//---------------------------------------------------------------------------- +extern bool getName(const QByteArray &data, uint &offset, uint nbChars, uint stringTableOffset, Log::Base &log, QString &name); +extern int disassemble(long int opcode, long int opcode2, int org, Pic::Architecture architecture, char *buffer, size_t sizeof_buffer); + +BEGIN_DECLARE_ENUM(OptHeaderFormat) + OldMicrochip = 0, NewMicrochip, Picc, Ccsc +END_DECLARE_ENUM_STD(OptHeaderFormat) + +struct OptHeaderData { + uint magic; + OptHeaderFormat optHeaderFormat; + bool parsed; +}; +extern const OptHeaderData OPT_HEADER_DATA[]; + +class Object; +class Section; + +//---------------------------------------------------------------------------- +class Element +{ +public: + Element(const Object &object) : _object(object) {} + virtual ~Element() {} + +protected: + const Object &_object; +}; + +//---------------------------------------------------------------------------- +class BaseSymbol : public Element +{ +public: + BaseSymbol(const Object &object) : Element(object) {} + virtual bool isAuxSymbol() const = 0; +}; + +BEGIN_DECLARE_ENUM(AuxSymbolType) + Direct = 0, File, Identifier, Section +END_DECLARE_ENUM_STD(AuxSymbolType) + +class AuxSymbol : public BaseSymbol +{ +public: + virtual bool isAuxSymbol() const { return true; } + static AuxSymbol *factory(const Object &object, AuxSymbolType type, const QByteArray &data, + uint offset, uint stringTableOffset, Log::Base &log); + +public: + AuxSymbol(const Object &object) : BaseSymbol(object) {} + virtual AuxSymbolType type() const = 0; +}; + +class AuxSymbolDirect : public AuxSymbol +{ +public: + AuxSymbolDirect(const Object &object, const QByteArray &data, uint offset, uint stringTableOffset, Log::Base &log); + virtual AuxSymbolType type() const { return AuxSymbolType::Direct; } + +private: + uchar _command; + QString _string; +}; + +class AuxSymbolFile : public AuxSymbol +{ +public: + AuxSymbolFile(const Object &object, const QByteArray &data, uint offset, uint stringTableOffset, Log::Base &log); + virtual AuxSymbolType type() const { return AuxSymbolType::File; } + QString filename() const { return _filename; } + uint line() const { return _line; } + +private: + uint _line; + QString _filename; +}; + +class AuxSymbolIdentifier : public AuxSymbol +{ +public: + AuxSymbolIdentifier(const Object &object, const QByteArray &data, uint offset, uint stringTableOffset, Log::Base &log); + virtual AuxSymbolType type() const { return AuxSymbolType::Identifier; } + QString string() const { return _string; } + +private: + QString _string; +}; + +class AuxSymbolSection : public AuxSymbol +{ +public: + AuxSymbolSection(const Object &object, const QByteArray &data, uint offset, uint stringTableOffset, Log::Base &log); + virtual AuxSymbolType type() const { return AuxSymbolType::Section; } + +private: + uint _length, _nbRelocations, _nbLineNumbers; +}; + +class AuxSymbolUnknown : public AuxSymbol +{ +public: + AuxSymbolUnknown(const Object &object) : AuxSymbol(object) {} + virtual AuxSymbolType type() const { return AuxSymbolType::Nb_Types; } +}; + +//---------------------------------------------------------------------------- +BEGIN_DECLARE_ENUM(SymbolSectionType) + InsideSection = 0, UndefinedSection, AbsoluteValue, DebugSymbol +END_DECLARE_ENUM_STD(SymbolSectionType) + +struct SymbolClassData { + const char *key, *label; + uint id; +}; +BEGIN_DECLARE_ENUM(SymbolClass) + Automatic = 0, External, Static, Register, ExternalDefinition, + Label, UndefinedLabel, MemberOfStructure, FunctionArgument, StructureTag, + MemberOfUnion, UnionTag, TypeDefinition, UndefinedStatic, EnumerationTag, + MemberOfEnumeration, RegisterParameter, BitField, AutoArgument, EndOfBlock, + BeginEndOfBlock, BeginEndOfFunction, EndOfStructure, Filename, LineNumber, + DuplicateTag, Section +END_DECLARE_ENUM(SymbolClass, SymbolClassData) + +struct SymbolTypeData { + const char *key, *label; + uint id; +}; +BEGIN_DECLARE_ENUM(SymbolType) + Void = 0, Char, Short, Int, Long, Float, Double, Struct, Union, + Enum, MemberOfEnum, UChar, UShort, UInt, ULong, LongDouble +END_DECLARE_ENUM(SymbolType, SymbolTypeData) + +struct SymbolDerivedTypeData { + const char *key, *label; + uint id; +}; +BEGIN_DECLARE_ENUM(SymbolDerivedType) + Pointer = 0, Function, Array +END_DECLARE_ENUM(SymbolDerivedType, SymbolDerivedTypeData) + +class Symbol : public BaseSymbol +{ +public: + Symbol(const Object &object, const QByteArray &data, uint offset, uint stringTableOffset, + const QString &lastFilename, Log::Base &log); + virtual bool isAuxSymbol() const { return false; } + QString name() const { return _name; } + QString filename() const { return _filename; } + const QValueVector<AuxSymbol *> &auxSymbols() const { return _aux; } + SymbolClass symbolClass() const { return _sclass; } + SymbolSectionType sectionType() const; + SymbolType type() const { return _type; } + SymbolDerivedType derivedType() const { return _dtype; } + uint value() const { return _value; } + uint section() const { Q_ASSERT( sectionType()==SymbolSectionType::InsideSection ); return _section; } + +private: + QString _name, _filename; + uint _value, _section; + SymbolClass _sclass; + SymbolType _type; + SymbolDerivedType _dtype; + QValueVector<AuxSymbol *> _aux; +}; + +//---------------------------------------------------------------------------- +class Relocation : public Element +{ +public: + Relocation(const Object &object, const Section §ion, const QByteArray &data, + uint offset, Log::Base &log); + +private: + ulong _address, _type; + short _offset; + const Symbol *_symbol; +}; + +//---------------------------------------------------------------------------- +class CodeLine : public Element +{ +public: + CodeLine(const Object &object, const Section §ion, const QByteArray &data, + uint offset, const QString &lastFilename, Log::Base &log); + const Section §ion() const { return _section; } + QString filename() const { return _filename; } + uint line() const { return _line; } + Address address() const { return _address; } + const Symbol *symbol() const { return _symbol; } + +private: + const Section &_section; + uint _line; + Address _address; + QString _filename; + const Symbol *_symbol; +}; + +//---------------------------------------------------------------------------- +BEGIN_DECLARE_ENUM(SectionType) + Config = 0, DeviceId, UserIds, UninitializedData, InitializedData, DataRom, Code +END_DECLARE_ENUM_STD(SectionType) + +class Section : public Element +{ +public: + class InstructionData { + public: + BitValue value; + QString opcode, disasm; + }; + +public: + Section(const Device::Data &device, const Object &object, const QByteArray &data, uint offset, + uint stringTableOffset, Log::Base &log); + ~Section(); + SectionType type() const; + QString name() const { return _name; } + Address address() const { return _address; } + uint size() const { return _size; } + uint flags() const { return _flags; } + const QMap<Address, InstructionData> &instructions() const { return _instructions; } + const QValueVector<Relocation *> &relocations() const { return _relocations; } + const QValueVector<CodeLine *> &lines() const { return _lines; } + +private: + QString _name; + Address _address; + uint _size, _flags; + QMap<Address, InstructionData> _instructions; + QValueVector<Relocation *> _relocations; + QValueVector<CodeLine *> _lines; + + enum Flag { FText = 0x00020, FData = 0x00040, FBSS = 0x00080, FDataRom = 0x00100, + FAbs = 0x01000, FShared = 0x02000, FOverlay = 0x04000, FAccess = 0x08000, + FActivationRecord = 0x10000 }; +}; + +//---------------------------------------------------------------------------- +class Object : public Base +{ +public: + Object(const Device::Data *device, const PURL::Url &url); + virtual ~Object(); + virtual bool parse(Log::Base &log); + Format format() const { return _format; } + const Device::Data *device() const { return _device; } + uint size(SizeType stype) const { return _format.data().sizes[stype]; } + OptHeaderFormat optHeaderFormat() const { return _optHeaderFormat; } + uint optHeaderMagic() const { return _optHeaderMagic; } + uint nbSymbols() const { return _symbols.count(); } + const BaseSymbol *symbol(uint i) const { return _symbols[i]; } + const Symbol *symbol(const QString &name) const { return (_msymbols.contains(name) ? _msymbols[name] : 0); } + uint nbSections() const { return _sections.count(); } + const Section *section(uint i) const { return _sections[i]; } + const QStringList &filenames() const { return _filenames; } + const QMap<QString, Address> &variables() const { return _variables; } + QString variableName(Address address) const; + + enum Flag { RelocationStripped = 0x0001, Executable = 0x0002, LineNumberStripped = 0x0004, + SymbolStripped = 0x0080, Extended18 = 0x4000, Generic = 0x8000 }; + Q_DECLARE_FLAGS(Flags, Flag) + +protected: + Q_UINT32 _optHeaderMagic; + OptHeaderFormat _optHeaderFormat; + const Device::Data *_device; + uint _nbSections, _nbSymbols, _symbolOffset; + Flags _flags; + QValueVector<BaseSymbol *> _symbols; + QMap<QString, Symbol *> _msymbols; // name -> Symbol * + QValueVector<Section *> _sections; + QStringList _filenames; + QMap<QString, Address> _variables; // name -> address + + virtual bool parseHeader(const QByteArray &data, uint &offset, Log::Base &log); + virtual bool parseOptionnalHeader(const QByteArray &data, uint &offset, Log::Base &log); +}; +Q_DECLARE_OPERATORS_FOR_FLAGS(Object::Flags) + +} // namespace + +//---------------------------------------------------------------------------- +namespace Pic +{ + +class RegisterNameData +{ +public: + RegisterNameData() {} + RegisterNameData(const QString &label, const Register::TypeData &data) : _label(label), _data(data) {} + QString label() const { return _label; } + const Register::TypeData &data() const { return _data; } + bool operator <(const RegisterNameData &rnd) const { return _label<rnd._label; }; + +private: + QString _label; + Register::TypeData _data; +}; +extern QValueVector<RegisterNameData> sfrList(const Pic::Data &data); +extern QValueVector<RegisterNameData> gprList(const Pic::Data &data, const Coff::Object *coff); +extern QValueVector<RegisterNameData> variableList(const Pic::Data &data, const Coff::Object &coff); + +} // namespace + +#endif diff --git a/src/coff/base/disassembler.cpp b/src/coff/base/disassembler.cpp new file mode 100644 index 0000000..663c163 --- /dev/null +++ b/src/coff/base/disassembler.cpp @@ -0,0 +1,289 @@ +/*************************************************************************** + * Copyright (C) 2006-2007 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 "disassembler.h" + +#include <qregexp.h> + +#include "devices/base/device_group.h" +#include "devices/pic/pic/pic_memory.h" +#include "coff_object.h" + +//----------------------------------------------------------------------------- +QString SourceLine::comment(PURL::SourceFamily family, const QString &text) +{ + switch (family.type()) { + case PURL::SourceFamily::Asm: return "; " + text; + case PURL::SourceFamily::C: return "/* " + text + " */"; + case PURL::SourceFamily::JAL: return "-- " + text; + case PURL::SourceFamily::Cpp: return "// " + text; + case PURL::SourceFamily::Basic: return "' " + text; + case PURL::SourceFamily::Nb_Types: break; + } + Q_ASSERT(false); + return QString::null; +} + +namespace SourceLine +{ +class LineData { +public: + LineData() : group(-1) {} + QString text, comment; + int group; +}; +} // namespace + +QStringList SourceLine::lines(PURL::SourceFamily family, const List &list, uint nbSpaces) +{ + QValueList<LineData> lines; + QValueList<uint> groupCommentColumn; + groupCommentColumn.append(0); + List::const_iterator it; + for (it=list.begin(); it!=list.end(); ++it) { + LineData data; + switch((*it).type) { + case Indented: + data.text = repeat(" ", nbSpaces); + case NotIndented: + if ( (*it).code.isEmpty() && !(*it).comment.isEmpty() ) data.text += comment(family, (*it).comment); + else { + data.text += (*it).code; + data.comment = (*it).comment; + data.group = groupCommentColumn.count() - 1; + groupCommentColumn[data.group] = qMax(groupCommentColumn[data.group], uint(data.text.length())); + } + break; + case Separator: + data.text = comment(family, "-----------------------------------------------------------------------"); + groupCommentColumn.append(0); + break; + case Empty: + break; + case Title: + data.text = comment(family, (*it).comment); + break; + } + lines += data; + } + QStringList slines; + QValueList<LineData>::const_iterator lit; + for (lit=lines.begin(); lit!=lines.end(); ++lit) { + if ( (*lit).group==-1 || (*lit).comment.isEmpty() ) slines += (*lit).text; + else { + uint col = groupCommentColumn[(*lit).group] + 1; + slines += (*lit).text.leftJustify(col, ' ') + comment(family, (*lit).comment); + } + } + return slines; +} + +QString SourceLine::text(PURL::SourceFamily family, const List &list, uint nbSpaces) +{ + return lines(family, list, nbSpaces).join("\n") + "\n"; +} + +QString SourceLine::transformConfigName(const Pic::Data &data, uint wordIndex, const QString &name) +{ + if ( !data.is18Family() ) return name; + bool ok; + (void)fromHexLabel(name, &ok); + if (ok) return name; + QString s = name + '_'; + if ( data.name()=="18C601" || data.name()=="18C801" || data.name().startsWith("18F" ) ) + s += QString::number(wordIndex/2+1) + (wordIndex%2==0 ? 'L' : 'H'); + else s += QString::number(wordIndex); + return s; +} + +QStringList SourceLine::ignoredConfigNames(const Pic::Data &data, uint wordIndex) +{ + QStringList cnames; + const QStringList &names = data.config()._words[wordIndex].ignoredCNames; + for (uint i=0; i<uint(names.count()); i++) cnames += transformConfigName(data, wordIndex, names[i]); + return cnames; +} + +QStringList SourceLine::extraConfigNames(const Pic::Data &data, uint wordIndex, const Pic::Config::Value &value) +{ + QStringList cnames; + const QStringList &names = value.configNames[Pic::ConfigNameType::Extra]; + for (uint i=0; i<uint(names.count()); i++) cnames += transformConfigName(data, wordIndex, names[i]); + return cnames; +} + +QStringList SourceLine::configNames(Pic::ConfigNameType type, const Pic::Memory &memory, uint word, bool &ok) +{ + ok = true; + const Pic::Data &data = memory.device(); + const Pic::Config &config = data.config(); + BitValue v = memory.normalizedWord(Pic::MemoryRangeType::Config, word); + const Pic::Config::Word &cword = config._words[word]; + QStringList cnames; + for (uint k=0; k<uint(cword.masks.count()); k++) { + const Pic::Config::Mask &cmask = cword.masks[k]; + if ( cmask.value.isInside(cword.pmask) ) continue; // protected bits + for (int l=cmask.values.count()-1; l>=0; l--) { + const Pic::Config::Value &cvalue = cmask.values[l]; + if ( !cvalue.value.isInside(v) ) continue; + QStringList vcnames = cvalue.configNames[type]; + if ( vcnames.isEmpty() && type!=Pic::ConfigNameType::Default ) vcnames = cvalue.configNames[Pic::ConfigNameType::Default]; + for (uint i=0; i<uint(vcnames.count()); i++) { + if ( vcnames[i].isEmpty() ) ok = false; + else cnames += transformConfigName(data, word, vcnames[i]); + } + break; + } + } + return cnames; +} + +//----------------------------------------------------------------------------- +QString GPUtils::toDeviceName(const QString &device) +{ + if ( device.startsWith("PS") ) return device.lower(); + return "p" + device.lower(); +} + +SourceLine::List GPUtils::includeLines(const Device::Data &data) +{ + SourceLine::List lines; + QString include = toDeviceName(data.name()); + if ( data.name()=="12CR509A" ) include = "p12c509a"; + else if ( QRegExp("16CR?5.?[A-C]?").exactMatch(data.name()) ) include = "p16c5x"; + else if ( QRegExp("16F5.?").exactMatch(data.name()) ) include = "p16f5x"; + else if ( data.name()=="16CR620A" ) include = "p16c620a"; + lines.appendIndentedCode("#include <" + include + ".inc>"); + return lines; +} + +SourceLine::List GPUtils::generateConfigLines(const Pic::Memory &memory, bool &ok) +{ + SourceLine::List lines; + const Pic::Data &data = memory.device(); + const Pic::Config &config = data.config(); + for (uint i=0; i<data.nbWords(Pic::MemoryRangeType::Config); i++) { + const Pic::Config::Word &cword = config._words[i]; + QStringList cnames = SourceLine::configNames(Pic::ConfigNameType::Default, memory, i, ok); + if ( cnames.isEmpty() ) continue; + QString code = "__CONFIG "; + if ( !cword.name.isEmpty() ) code += "_" + cword.name + ", "; + code += cnames.join(" & "); + lines.appendIndentedCode(code); + } + return lines; +} + +SourceLine::List GPUtils::disassemble(const Pic::Memory &memory) +{ + SourceLine::List lines; + const Pic::Data &data = memory.device(); + + // includes + lines += includeLines(data); + lines.appendNotIndentedCode("processor " + toDeviceName(data.name())); + + // memory config + bool isDefault = true; + for (uint k=0; k<data.nbWords(Pic::MemoryRangeType::Config); k++) { + BitValue op = memory.normalizedWord(Pic::MemoryRangeType::Config, k); + BitValue mask = data.config()._words[k].usedMask(); + if ( !mask.isInside(op) ) isDefault = false; // this is not completely correct but otherwise empty config is written... + } + if ( !isDefault ) { + lines.appendEmpty(); + lines.appendSeparator(); + bool ok; + lines += generateConfigLines(memory, ok); + } + + // user ids + QString tmp; + for (uint k=0; k<data.nbWords(Pic::MemoryRangeType::UserId); k++) { + BitValue op = memory.normalizedWord(Pic::MemoryRangeType::UserId, k); + BitValue mask = data.userIdRecommendedMask(); + if ( mask.isInside(op) ) continue; + if ( data.is18Family() ) { + Address ad = data.range(Pic::MemoryRangeType::UserId).start + data.range(Pic::MemoryRangeType::UserId).hexFileOffset + k*data.addressIncrement(Pic::MemoryRangeType::UserId); + lines.appendIndentedCode("__IDLOCS " + toHexLabel(ad, data.nbCharsAddress()) + ", " + toHexLabel(op, data.nbCharsWord(Pic::MemoryRangeType::UserId))); + } else tmp += toHex(op.nybble(0), 1); + } + if ( !tmp.isEmpty() ) { + lines.appendEmpty(); + lines.appendSeparator(); + lines.appendIndentedCode("__IDLOCS 0x" + tmp); + } + + // memory code + lines.appendEmpty(); + lines.appendSeparator(); + lines.appendTitle("code memory"); + bool first = true, newOrg = true; + uint nb = data.nbWords(Pic::MemoryRangeType::Code); + for (uint k=0; k<nb; k++) { + BitValue op = memory.normalizedWord(Pic::MemoryRangeType::Code, k); + BitValue mask = data.mask(Pic::MemoryRangeType::Code); + if ( mask.isInside(op) ) newOrg = true; + else { + if (newOrg) { + if ( !first ) tmp += '\n'; + first = false; + Address org = data.range(Pic::MemoryRangeType::Code).start + data.range(Pic::MemoryRangeType::Code).hexFileOffset + k*data.addressIncrement(Pic::MemoryRangeType::Code); + lines.appendNotIndentedCode("org " + toHexLabel(org, data.nbCharsAddress())); + newOrg = false; + } + char buffer[512]; + buffer[0] = 0; + BitValue op2 = ((k+1)<nb ? memory.word(Pic::MemoryRangeType::Code, k+1) : 0); + uint n = Coff::disassemble(op.toUInt(), op2.toUInt(), k, data.architecture(), buffer, 512); + lines.appendIndentedCode(QString(buffer)); + if ( n==2 ) k++; + } + } + + // eeprom data + lines.appendEmpty(); + lines.appendSeparator(); + lines.appendTitle("eeprom memory"); + newOrg = true; + nb = data.nbWords(Pic::MemoryRangeType::Eeprom); + for (uint k=0; k<nb; k++) { + BitValue op = memory.normalizedWord(Pic::MemoryRangeType::Eeprom, k); + BitValue mask = data.mask(Pic::MemoryRangeType::Eeprom); + if ( mask.isInside(op) ) newOrg = true; + else { + if (newOrg) { + Address org = data.range(Pic::MemoryRangeType::Eeprom).start + data.range(Pic::MemoryRangeType::Eeprom).hexFileOffset + k*data.addressIncrement(Pic::MemoryRangeType::Eeprom); + lines.appendNotIndentedCode("org " + toHexLabel(org, data.nbCharsAddress())); + newOrg = false; + } + lines.appendIndentedCode("de " + toHexLabel(op, data.nbCharsWord(Pic::MemoryRangeType::Eeprom))); + } + } + + lines.appendNotIndentedCode("end"); + return lines; +} + +//----------------------------------------------------------------------------- +SourceLine::List Tool::SourceGenerator::templateSourceFile(PURL::ToolType type, const Device::Data &data, bool &ok) const +{ + SourceLine::List lines; + lines.appendSeparator(); + lines.appendTitle(i18n("Template source file generated by piklab")); + lines += includeLines(type, data); + lines.appendEmpty(); + lines.appendSeparator(); + lines.appendTitle(i18n("Configuration bits: adapt to your setup and needs")); + Device::Memory *memory = data.group().createMemory(data); + lines += configLines(type, *memory, ok); + delete memory; + lines.appendEmpty(); + lines += sourceFileContent(type, data, ok); + return lines; +} diff --git a/src/coff/base/disassembler.h b/src/coff/base/disassembler.h new file mode 100644 index 0000000..e713610 --- /dev/null +++ b/src/coff/base/disassembler.h @@ -0,0 +1,80 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifndef DISASSEMBLER_H +#define DISASSEMBLER_H + +#include "common/common/purl_base.h" +#include "devices/pic/base/pic_config.h" +namespace Device { class Data; class Memory; } +namespace Pic { class Data; class Memory; } + +//----------------------------------------------------------------------------- +namespace SourceLine +{ + +enum Type { Indented, NotIndented, Title, Separator, Empty }; + +class Data { +public: + Data(Type _type = Empty, const QString &_code = QString::null, const QString &_comment = QString::null) + : type(_type), code(_code), comment(_comment) {} + Type type; + QString code, comment; +}; + +class List : public QValueList<Data> +{ +public: + List() {} + void appendSeparator() { append(Separator); } + void appendEmpty() { append(Empty); } + void appendTitle(const QString &text) { append(Data(Title, QString::null, text)); } + void appendIndentedCode(const QString &code, const QString &comment = QString::null) { append(Data(Indented, code, comment)); } + void appendNotIndentedCode(const QString &code, const QString &comment = QString::null) { append(Data(NotIndented, code, comment)); } +}; + +extern QString comment(PURL::SourceFamily family, const QString &text); +extern QStringList lines(PURL::SourceFamily family, const List &list, uint nbSpaces); +extern QString text(PURL::SourceFamily family, const List &list, uint nbSpaces); +extern QString transformConfigName(const Pic::Data &data, uint wordIndex, const QString &name); +extern QStringList ignoredConfigNames(const Pic::Data &data, uint wordIndex); +extern QStringList extraConfigNames(const Pic::Data &data, uint wordIndex, const Pic::Config::Value &value); +extern QStringList configNames(Pic::ConfigNameType type, const Pic::Memory &memory, uint word, bool &ok); + +} // namespace + +//----------------------------------------------------------------------------- +namespace GPUtils +{ + +extern QString toDeviceName(const QString &device); +extern SourceLine::List includeLines(const Device::Data &data); +extern SourceLine::List generateConfigLines(const Pic::Memory &memory, bool &ok); +extern SourceLine::List disassemble(const Pic::Memory &memory); + +} // namespace + +//----------------------------------------------------------------------------- +namespace Tool +{ + +class SourceGenerator +{ +public: + SourceGenerator() {} + virtual ~SourceGenerator() {} + virtual SourceLine::List configLines(PURL::ToolType type, const Device::Memory &memory, bool &ok) const = 0; + SourceLine::List templateSourceFile(PURL::ToolType type, const Device::Data &data, bool &ok) const; + virtual SourceLine::List sourceFileContent(PURL::ToolType type, const Device::Data &data, bool &ok) const = 0; + virtual SourceLine::List includeLines(PURL::ToolType type, const Device::Data &data) const = 0; +}; + +} // namespace + +#endif diff --git a/src/coff/base/gpdis.cpp b/src/coff/base/gpdis.cpp new file mode 100644 index 0000000..2df4f24 --- /dev/null +++ b/src/coff/base/gpdis.cpp @@ -0,0 +1,349 @@ +/* Disassemble memory + Copyright (C) 2001, 2002, 2003, 2004, 2005 + Craig Franklin + +This file is part of gputils. + +gputils 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, or (at your option) +any later version. + +gputils is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with gputils; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include <assert.h> +#include "devices/pic/base/pic.h" +#include "coff_object.h" +#include "gpopcode.h" + +#define DECODE_ARG0 snprintf(buffer, sizeof_buffer, "%s", instruction->name) + +#define DECODE_ARG1(ARG1) snprintf(buffer, sizeof_buffer, "%s\t%#lx", \ + instruction->name,\ + ARG1) + +#define DECODE_ARG1WF(ARG1, ARG2) snprintf(buffer, sizeof_buffer, "%s\t%#lx, %s", \ + instruction->name,\ + ARG1, \ + (ARG2 ? "f" : "w")) + +#define DECODE_ARG2(ARG1, ARG2) snprintf(buffer, sizeof_buffer, "%s\t%#lx, %#lx", \ + instruction->name,\ + ARG1, \ + ARG2) + +#define DECODE_ARG3(ARG1, ARG2, ARG3) snprintf(buffer, sizeof_buffer, "%s\t%#lx, %#lx, %#lx", \ + instruction->name,\ + ARG1, \ + ARG2, \ + ARG3) + +bool gp_decode_mnemonics = false; +bool gp_decode_extended = false; + +int Coff::disassemble(long int opcode, long int opcode2, + int org, + Pic::Architecture architecture, + char *buffer, + size_t sizeof_buffer) +{ + int i; + int value; + struct insn *instruction = NULL; + int num_words = 1; + + switch (architecture.type()) { + case Pic::Architecture::P24F: + case Pic::Architecture::P24H: + case Pic::Architecture::P30F: + case Pic::Architecture::P33F: + snprintf(buffer, sizeof_buffer, "--"); + return 0; + case Pic::Architecture::P10X: + for(i = 0; i < num_op_12c5xx; i++) { + if((op_12c5xx[i].mask & opcode) == op_12c5xx[i].opcode) { + instruction = &op_12c5xx[i]; + break; + } + } + break; +/* case PROC_CLASS_SX: + for(i = 0; i < num_op_sx; i++) { + if((op_sx[i].mask & opcode) == op_sx[i].opcode) { + instruction = &op_sx[i]; + break; + } + } + break; +*/ + case Pic::Architecture::P16X: + for(i = 0; i < num_op_16cxx; i++) { + if((op_16cxx[i].mask & opcode) == op_16cxx[i].opcode) { + instruction = &op_16cxx[i]; + break; + } + } + break; + case Pic::Architecture::P17C: + for(i = 0; i < num_op_17cxx; i++) { + if((op_17cxx[i].mask & opcode) == op_17cxx[i].opcode) { + instruction = &op_17cxx[i]; + break; + } + } + break; + case Pic::Architecture::P18C: + case Pic::Architecture::P18F: + case Pic::Architecture::P18J: + if (gp_decode_mnemonics) { + for(i = 0; i < num_op_18cxx_sp; i++) { + if((op_18cxx_sp[i].mask & opcode) == op_18cxx_sp[i].opcode) { + instruction = &op_18cxx_sp[i]; + break; + } + } + } + if (instruction == NULL) { + for(i = 0; i < num_op_18cxx; i++) { + if((op_18cxx[i].mask & opcode) == op_18cxx[i].opcode) { + instruction = &op_18cxx[i]; + break; + } + } + } + if ((instruction == NULL) && (gp_decode_extended)) { + /* might be from the extended instruction set */ + for(i = 0; i < num_op_18cxx_ext; i++) { + if((op_18cxx_ext[i].mask & opcode) == op_18cxx_ext[i].opcode) { + instruction = &op_18cxx_ext[i]; + break; + } + } + } + break; + default: + assert(0); + } + + if (instruction == NULL) { + snprintf(buffer, sizeof_buffer, "dw\t%#lx ;unknown opcode", opcode); + return num_words; + } + + switch (instruction->classType) + { + case INSN_CLASS_LIT3_BANK: + DECODE_ARG1((opcode & 0x7) << 5); + break; + case INSN_CLASS_LIT3_PAGE: + DECODE_ARG1((opcode & 0x7) << 9); + break; + case INSN_CLASS_LIT1: + DECODE_ARG1(opcode & 1); + break; + case INSN_CLASS_LIT4: + DECODE_ARG1(opcode & 0xf); + break; + case INSN_CLASS_LIT4S: + DECODE_ARG1((opcode & 0xf0) >> 4); + break; + case INSN_CLASS_LIT6: + DECODE_ARG1(opcode & 0x3f); + break; + case INSN_CLASS_LIT8: + case INSN_CLASS_LIT8C12: + case INSN_CLASS_LIT8C16: + DECODE_ARG1(opcode & 0xff); + break; + case INSN_CLASS_LIT9: + DECODE_ARG1(opcode & 0x1ff); + break; + case INSN_CLASS_LIT11: + DECODE_ARG1(opcode & 0x7ff); + break; + case INSN_CLASS_LIT13: + DECODE_ARG1(opcode & 0x1fff); + break; + case INSN_CLASS_LITFSR: + DECODE_ARG2(((opcode >> 6) & 0x3), (opcode & 0x3f)); + break; + case INSN_CLASS_RBRA8: + value = opcode & 0xff; + /* twos complement number */ + if (value & 0x80) { + value = -((value ^ 0xff) + 1); + } + DECODE_ARG1((unsigned long)(org + value + 1) * 2); + break; + case INSN_CLASS_RBRA11: + value = opcode & 0x7ff; + /* twos complement number */ + if (value & 0x400) { + value = -((value ^ 0x7ff) + 1); + } + DECODE_ARG1((unsigned long)(org + value + 1) * 2); + break; + case INSN_CLASS_LIT20: + { + long int dest; + + num_words = 2; + dest = (opcode2 & 0xfff) << 8; + dest |= opcode & 0xff; + DECODE_ARG1(dest * 2); + } + break; + case INSN_CLASS_CALL20: + { + long int dest; + + num_words = 2; + dest = (opcode2 & 0xfff) << 8; + dest |= opcode & 0xff; + snprintf(buffer, sizeof_buffer, "%s\t%#lx, %#lx", + instruction->name, + dest * 2, + (opcode >> 8) & 1); + } + break; + case INSN_CLASS_FLIT12: + { + long int k; + long int file; + + num_words = 2; + k = opcode2 & 0xff; + k |= ((opcode & 0xf) << 8); + file = (opcode >> 4) & 0x3; + DECODE_ARG2(file, k); + } + break; + case INSN_CLASS_FF: + { + long int file1; + long int file2; + + num_words = 2; + file1 = opcode & 0xfff; + file2 = opcode2 & 0xfff; + DECODE_ARG2(file1, file2); + } + break; + case INSN_CLASS_FP: + DECODE_ARG2((opcode & 0xff), ((opcode >> 8) & 0x1f)); + break; + case INSN_CLASS_PF: + DECODE_ARG2(((opcode >> 8) & 0x1f), (opcode & 0xff)); + break; + case INSN_CLASS_SF: + { + long int offset; + long int file; + + num_words = 2; + offset = opcode & 0x7f; + file = opcode2 & 0xfff; + DECODE_ARG2(offset, file); + } + break; + case INSN_CLASS_SS: + { + long int offset1; + long int offset2; + + num_words = 2; + offset1 = opcode & 0x7f; + offset2 = opcode2 & 0x7f; + DECODE_ARG2(offset1, offset2); + } + break; + case INSN_CLASS_OPF5: + DECODE_ARG1(opcode & 0x1f); + break; + case INSN_CLASS_OPWF5: + DECODE_ARG1WF((opcode & 0x1f), ((opcode >> 5) & 1)); + break; + case INSN_CLASS_B5: + DECODE_ARG2((opcode & 0x1f), ((opcode >> 5) & 7)); + break; + case INSN_CLASS_B8: + DECODE_ARG2((opcode & 0xff), ((opcode >> 8) & 7)); + break; + case INSN_CLASS_OPF7: + DECODE_ARG1(opcode & 0x7f); + break; + case INSN_CLASS_OPF8: + DECODE_ARG1(opcode & 0xff); + break; + case INSN_CLASS_OPWF7: + DECODE_ARG1WF((opcode & 0x7f), ((opcode >> 7) & 1)); + break; + case INSN_CLASS_OPWF8: + DECODE_ARG1WF((opcode & 0xff), ((opcode >> 8) & 1)); + break; + case INSN_CLASS_B7: + DECODE_ARG2((opcode & 0x7f), ((opcode >> 7) & 7)); + break; + case INSN_CLASS_OPFA8: + DECODE_ARG2((opcode & 0xff), ((opcode >> 8) & 1)); + break; + case INSN_CLASS_BA8: + DECODE_ARG3((opcode & 0xff), ((opcode >> 9) & 7), ((opcode >> 8) & 1)); + break; + case INSN_CLASS_OPWFA8: + DECODE_ARG3((opcode & 0xff), ((opcode >> 9) & 1), ((opcode >> 8) & 1)); + break; + case INSN_CLASS_IMPLICIT: + DECODE_ARG0; + break; + case INSN_CLASS_TBL: + { + char op[5]; + + switch(opcode & 0x3) + { + case 0: + strncpy(op, "*", sizeof(op)); + break; + case 1: + strncpy(op, "*+", sizeof(op)); + break; + case 2: + strncpy(op, "*-", sizeof(op)); + break; + case 3: + strncpy(op, "+*", sizeof(op)); + break; + default: + assert(0); + } + + snprintf(buffer, + sizeof_buffer, + "%s\t%s", + instruction->name, + op); + } + break; + case INSN_CLASS_TBL2: + DECODE_ARG2(((opcode >> 9) & 1), (opcode & 0xff)); + break; + case INSN_CLASS_TBL3: + DECODE_ARG3(((opcode >> 9) & 1), + ((opcode >> 8) & 1), + (opcode & 0xff)); + break; + default: + assert(0); + } + + return num_words; +} diff --git a/src/coff/base/gpopcode.cpp b/src/coff/base/gpopcode.cpp new file mode 100644 index 0000000..87cb3b4 --- /dev/null +++ b/src/coff/base/gpopcode.cpp @@ -0,0 +1,348 @@ +/* GNU PIC opcode definitions + Copyright (C) 2001, 2002, 2003, 2004, 2005 + Craig Franklin + +This file is part of gputils. + +gputils 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, or (at your option) +any later version. + +gputils is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with gputils; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "gpopcode.h" + +/* FIXME: use const struct */ + +/* PIC 12-bit instruction set */ +struct insn op_12c5xx[] = { + { "addwf", 0xfc0, 0x1c0, INSN_CLASS_OPWF5 }, + { "andlw", 0xf00, 0xe00, INSN_CLASS_LIT8 }, + { "andwf", 0xfc0, 0x140, INSN_CLASS_OPWF5 }, + { "bcf", 0xf00, 0x400, INSN_CLASS_B5 }, + { "bsf", 0xf00, 0x500, INSN_CLASS_B5 }, + { "btfsc", 0xf00, 0x600, INSN_CLASS_B5 }, + { "btfss", 0xf00, 0x700, INSN_CLASS_B5 }, + { "call", 0xf00, 0x900, INSN_CLASS_LIT8C12 }, + { "clrf", 0xfe0, 0x060, INSN_CLASS_OPF5 }, + { "clrw", 0xfff, 0x040, INSN_CLASS_IMPLICIT }, + { "clrwdt", 0xfff, 0x004, INSN_CLASS_IMPLICIT }, + { "comf", 0xfc0, 0x240, INSN_CLASS_OPWF5 }, + { "decf", 0xfc0, 0x0c0, INSN_CLASS_OPWF5 }, + { "decfsz", 0xfc0, 0x2c0, INSN_CLASS_OPWF5 }, + { "goto", 0xe00, 0xa00, INSN_CLASS_LIT9 }, + { "incf", 0xfc0, 0x280, INSN_CLASS_OPWF5 }, + { "incfsz", 0xfc0, 0x3c0, INSN_CLASS_OPWF5 }, + { "iorlw", 0xf00, 0xd00, INSN_CLASS_LIT8 }, + { "iorwf", 0xfc0, 0x100, INSN_CLASS_OPWF5 }, + { "movf", 0xfc0, 0x200, INSN_CLASS_OPWF5 }, + { "movlw", 0xf00, 0xc00, INSN_CLASS_LIT8 }, + { "movwf", 0xfe0, 0x020, INSN_CLASS_OPF5 }, + { "nop", 0xfff, 0x000, INSN_CLASS_IMPLICIT }, + { "option", 0xfff, 0x002, INSN_CLASS_IMPLICIT }, + { "retlw", 0xf00, 0x800, INSN_CLASS_LIT8 }, + { "return", 0xfff, 0x800, INSN_CLASS_IMPLICIT }, /* FIXME: special mnemonic */ + { "rlf", 0xfc0, 0x340, INSN_CLASS_OPWF5 }, + { "rrf", 0xfc0, 0x300, INSN_CLASS_OPWF5 }, + { "sleep", 0xfff, 0x003, INSN_CLASS_IMPLICIT }, + { "subwf", 0xfc0, 0x080, INSN_CLASS_OPWF5 }, + { "swapf", 0xfc0, 0x380, INSN_CLASS_OPWF5 }, + { "tris", 0xff8, 0x000, INSN_CLASS_OPF5 }, + { "xorlw", 0xf00, 0xf00, INSN_CLASS_LIT8 }, + { "xorwf", 0xfc0, 0x180, INSN_CLASS_OPWF5 } +}; + +const int num_op_12c5xx = TABLE_SIZE(op_12c5xx); + +/* Scenix SX has a superset of the PIC 12-bit instruction set */ +/* + * It would be nice if there was a more elegant way to do this, + * either by adding a flags field to struct insn, or by allowing a + * processor to have more than one associated table. + */ +struct insn op_sx[] = { + { "addwf", 0xfc0, 0x1c0, INSN_CLASS_OPWF5 }, + { "andlw", 0xf00, 0xe00, INSN_CLASS_LIT8 }, + { "andwf", 0xfc0, 0x140, INSN_CLASS_OPWF5 }, + { "bank", 0xff8, 0x018, INSN_CLASS_LIT3_BANK }, /* SX only */ + { "bcf", 0xf00, 0x400, INSN_CLASS_B5 }, + { "bsf", 0xf00, 0x500, INSN_CLASS_B5 }, + { "btfsc", 0xf00, 0x600, INSN_CLASS_B5 }, + { "btfss", 0xf00, 0x700, INSN_CLASS_B5 }, + { "call", 0xf00, 0x900, INSN_CLASS_LIT8C12 }, + { "clrf", 0xfe0, 0x060, INSN_CLASS_OPF5 }, + { "clrw", 0xfff, 0x040, INSN_CLASS_IMPLICIT }, + { "clrwdt", 0xfff, 0x004, INSN_CLASS_IMPLICIT }, + { "comf", 0xfc0, 0x240, INSN_CLASS_OPWF5 }, + { "decf", 0xfc0, 0x0c0, INSN_CLASS_OPWF5 }, + { "decfsz", 0xfc0, 0x2c0, INSN_CLASS_OPWF5 }, + { "goto", 0xe00, 0xa00, INSN_CLASS_LIT9 }, + { "incf", 0xfc0, 0x280, INSN_CLASS_OPWF5 }, + { "incfsz", 0xfc0, 0x3c0, INSN_CLASS_OPWF5 }, + { "iorlw", 0xf00, 0xd00, INSN_CLASS_LIT8 }, + { "iorwf", 0xfc0, 0x100, INSN_CLASS_OPWF5 }, + { "iread", 0xfff, 0x041, INSN_CLASS_IMPLICIT }, /* SX only */ + { "mode", 0xff0, 0x050, INSN_CLASS_LIT4 }, /* SX only */ + { "movf", 0xfc0, 0x200, INSN_CLASS_OPWF5 }, + { "movlw", 0xf00, 0xc00, INSN_CLASS_LIT8 }, + { "movmw", 0xfff, 0x042, INSN_CLASS_IMPLICIT }, /* SX only */ + { "movwf", 0xfe0, 0x020, INSN_CLASS_OPF5 }, + { "movwm", 0xfff, 0x043, INSN_CLASS_IMPLICIT }, /* SX only */ + { "nop", 0xfff, 0x000, INSN_CLASS_IMPLICIT }, + { "option", 0xfff, 0x002, INSN_CLASS_IMPLICIT }, + { "page", 0xff8, 0x010, INSN_CLASS_LIT3_PAGE }, /* SX only */ + { "reti", 0xfff, 0x00e, INSN_CLASS_IMPLICIT }, /* SX only */ + { "retiw", 0xfff, 0x00f, INSN_CLASS_IMPLICIT }, /* SX only */ + { "retlw", 0xf00, 0x800, INSN_CLASS_LIT8 }, + { "retp", 0xfff, 0x00d, INSN_CLASS_IMPLICIT }, /* SX only */ + { "return", 0xfff, 0x00c, INSN_CLASS_IMPLICIT }, /* SX only */ + { "rlf", 0xfc0, 0x340, INSN_CLASS_OPWF5 }, + { "rrf", 0xfc0, 0x300, INSN_CLASS_OPWF5 }, + { "sleep", 0xfff, 0x003, INSN_CLASS_IMPLICIT }, + { "subwf", 0xfc0, 0x080, INSN_CLASS_OPWF5 }, + { "swapf", 0xfc0, 0x380, INSN_CLASS_OPWF5 }, + { "tris", 0xff8, 0x000, INSN_CLASS_OPF5 }, + { "xorlw", 0xf00, 0xf00, INSN_CLASS_LIT8 }, + { "xorwf", 0xfc0, 0x180, INSN_CLASS_OPWF5 } +}; + +const int num_op_sx = TABLE_SIZE(op_sx); + +/* PIC 14-bit instruction set */ +struct insn op_16cxx[] = { + { "addlw", 0x3e00, 0x3e00, INSN_CLASS_LIT8 }, + { "addwf", 0x3f00, 0x0700, INSN_CLASS_OPWF7 }, + { "andlw", 0x3f00, 0x3900, INSN_CLASS_LIT8 }, + { "andwf", 0x3f00, 0x0500, INSN_CLASS_OPWF7 }, + { "bcf", 0x3c00, 0x1000, INSN_CLASS_B7 }, + { "bsf", 0x3c00, 0x1400, INSN_CLASS_B7 }, + { "btfsc", 0x3c00, 0x1800, INSN_CLASS_B7 }, + { "btfss", 0x3c00, 0x1c00, INSN_CLASS_B7 }, + { "call", 0x3800, 0x2000, INSN_CLASS_LIT11 }, + { "clrf", 0x3f80, 0x0180, INSN_CLASS_OPF7 }, + { "clrw", 0x3fff, 0x0103, INSN_CLASS_IMPLICIT }, + { "clrwdt", 0x3fff, 0x0064, INSN_CLASS_IMPLICIT }, + { "comf", 0x3f00, 0x0900, INSN_CLASS_OPWF7 }, + { "decf", 0x3f00, 0x0300, INSN_CLASS_OPWF7 }, + { "decfsz", 0x3f00, 0x0b00, INSN_CLASS_OPWF7 }, + { "goto", 0x3800, 0x2800, INSN_CLASS_LIT11 }, + { "incf", 0x3f00, 0x0a00, INSN_CLASS_OPWF7 }, + { "incfsz", 0x3f00, 0x0f00, INSN_CLASS_OPWF7 }, + { "iorlw", 0x3f00, 0x3800, INSN_CLASS_LIT8 }, + { "iorwf", 0x3f00, 0x0400, INSN_CLASS_OPWF7 }, + { "movf", 0x3f00, 0x0800, INSN_CLASS_OPWF7 }, + { "movlw", 0x3c00, 0x3000, INSN_CLASS_LIT8 }, + { "movwf", 0x3f80, 0x0080, INSN_CLASS_OPF7 }, + { "nop", 0x3f9f, 0x0000, INSN_CLASS_IMPLICIT }, + { "option", 0x3fff, 0x0062, INSN_CLASS_IMPLICIT }, + { "retfie", 0x3fff, 0x0009, INSN_CLASS_IMPLICIT }, + { "retlw", 0x3c00, 0x3400, INSN_CLASS_LIT8 }, + { "return", 0x3fff, 0x0008, INSN_CLASS_IMPLICIT }, + { "rlf", 0x3f00, 0x0d00, INSN_CLASS_OPWF7 }, + { "rrf", 0x3f00, 0x0c00, INSN_CLASS_OPWF7 }, + { "sleep", 0x3fff, 0x0063, INSN_CLASS_IMPLICIT }, + { "sublw", 0x3e00, 0x3c00, INSN_CLASS_LIT8 }, + { "subwf", 0x3f00, 0x0200, INSN_CLASS_OPWF7 }, + { "swapf", 0x3f00, 0x0e00, INSN_CLASS_OPWF7 }, + { "tris", 0x3ff8, 0x0060, INSN_CLASS_OPF7 }, + { "xorlw", 0x3f00, 0x3a00, INSN_CLASS_LIT8 }, + { "xorwf", 0x3f00, 0x0600, INSN_CLASS_OPWF7 } +}; + +const int num_op_16cxx = TABLE_SIZE(op_16cxx); + +/* PIC 16-bit instruction set */ +struct insn op_17cxx[] = { + { "addlw", 0xff00, 0xb100, INSN_CLASS_LIT8 }, + { "addwf", 0xfe00, 0x0e00, INSN_CLASS_OPWF8 }, + { "addwfc", 0xfe00, 0x1000, INSN_CLASS_OPWF8 }, + { "andlw", 0xff00, 0xb500, INSN_CLASS_LIT8 }, + { "andwf", 0xfe00, 0x0a00, INSN_CLASS_OPWF8 }, + { "bcf", 0xf800, 0x8800, INSN_CLASS_B8 }, + { "bsf", 0xf800, 0x8000, INSN_CLASS_B8 }, + { "btfsc", 0xf800, 0x9800, INSN_CLASS_B8 }, + { "btfss", 0xf800, 0x9000, INSN_CLASS_B8 }, + { "btg", 0xf800, 0x3800, INSN_CLASS_B8 }, + { "call", 0xe000, 0xe000, INSN_CLASS_LIT13 }, + { "clrf", 0xfe00, 0x2800, INSN_CLASS_OPWF8 }, + { "clrwdt", 0xffff, 0x0004, INSN_CLASS_IMPLICIT }, + { "comf", 0xfe00, 0x1200, INSN_CLASS_OPWF8 }, + { "cpfseq", 0xff00, 0x3100, INSN_CLASS_OPF8 }, + { "cpfsgt", 0xff00, 0x3200, INSN_CLASS_OPF8 }, + { "cpfslt", 0xff00, 0x3000, INSN_CLASS_OPF8 }, + { "daw", 0xfe00, 0x2e00, INSN_CLASS_OPWF8 }, + { "decf", 0xfe00, 0x0600, INSN_CLASS_OPWF8 }, + { "decfsz", 0xfe00, 0x1600, INSN_CLASS_OPWF8 }, + { "dcfsnz", 0xfe00, 0x2600, INSN_CLASS_OPWF8 }, + { "goto", 0xe000, 0xc000, INSN_CLASS_LIT13 }, + { "incf", 0xfe00, 0x1400, INSN_CLASS_OPWF8 }, + { "incfsz", 0xfe00, 0x1e00, INSN_CLASS_OPWF8 }, + { "infsnz", 0xfe00, 0x2400, INSN_CLASS_OPWF8 }, + { "iorlw", 0xff00, 0xb300, INSN_CLASS_LIT8 }, + { "iorwf", 0xfe00, 0x0800, INSN_CLASS_OPWF8 }, + { "lcall", 0xff00, 0xb700, INSN_CLASS_LIT8C16 }, + { "movfp", 0xe000, 0x6000, INSN_CLASS_FP }, + { "movpf", 0xe000, 0x4000, INSN_CLASS_PF }, + { "movlb", 0xff00, 0xb800, INSN_CLASS_LIT8 }, + { "movlr", 0xfe00, 0xba00, INSN_CLASS_LIT4S }, + { "movlw", 0xff00, 0xb000, INSN_CLASS_LIT8 }, + { "movwf", 0xff00, 0x0100, INSN_CLASS_OPF8 }, + { "mullw", 0xff00, 0xbc00, INSN_CLASS_LIT8 }, + { "mulwf", 0xff00, 0x3400, INSN_CLASS_OPF8 }, + { "negw", 0xfe00, 0x2c00, INSN_CLASS_OPWF8 }, + { "nop", 0xffff, 0x0000, INSN_CLASS_IMPLICIT }, + { "retfie", 0xffff, 0x0005, INSN_CLASS_IMPLICIT }, + { "retlw", 0xff00, 0xb600, INSN_CLASS_LIT8 }, + { "return", 0xffff, 0x0002, INSN_CLASS_IMPLICIT }, + { "rlcf", 0xfe00, 0x1a00, INSN_CLASS_OPWF8 }, + { "rlncf", 0xfe00, 0x2200, INSN_CLASS_OPWF8 }, + { "rrcf", 0xfe00, 0x1800, INSN_CLASS_OPWF8 }, + { "rrncf", 0xfe00, 0x2000, INSN_CLASS_OPWF8 }, + { "setf", 0xfe00, 0x2a00, INSN_CLASS_OPWF8 }, + { "sleep", 0xffff, 0x0003, INSN_CLASS_IMPLICIT }, + { "sublw", 0xff00, 0xb200, INSN_CLASS_LIT8 }, + { "subwf", 0xfe00, 0x0400, INSN_CLASS_OPWF8 }, + { "subwfb", 0xfe00, 0x0200, INSN_CLASS_OPWF8 }, + { "swapf", 0xfe00, 0x1c00, INSN_CLASS_OPWF8 }, + { "tablrd", 0xfc00, 0xa800, INSN_CLASS_TBL3 }, + { "tablwt", 0xfc00, 0xac00, INSN_CLASS_TBL3 }, + { "tlrd", 0xfc00, 0xa000, INSN_CLASS_TBL2 }, + { "tlwt", 0xfc00, 0xa400, INSN_CLASS_TBL2 }, + { "tstfsz", 0xff00, 0x3300, INSN_CLASS_OPF8 }, + { "xorlw", 0xff00, 0xb400, INSN_CLASS_LIT8 }, + { "xorwf", 0xfe00, 0x0c00, INSN_CLASS_OPWF8 } +}; + +const int num_op_17cxx = TABLE_SIZE(op_17cxx); + +struct insn op_18cxx[] = { + { "addlw", 0xff00, 0x0f00, INSN_CLASS_LIT8 }, + { "addwf", 0xfc00, 0x2400, INSN_CLASS_OPWFA8 }, + { "addwfc", 0xfc00, 0x2000, INSN_CLASS_OPWFA8 }, + { "andlw", 0xff00, 0x0b00, INSN_CLASS_LIT8 }, + { "andwf", 0xfc00, 0x1400, INSN_CLASS_OPWFA8 }, + { "bc", 0xff00, 0xe200, INSN_CLASS_RBRA8 }, + { "bcf", 0xf000, 0x9000, INSN_CLASS_BA8 }, + { "bn", 0xff00, 0xe600, INSN_CLASS_RBRA8 }, + { "bnc", 0xff00, 0xe300, INSN_CLASS_RBRA8 }, + { "bnn", 0xff00, 0xe700, INSN_CLASS_RBRA8 }, + { "bnov", 0xff00, 0xe500, INSN_CLASS_RBRA8 }, + { "bnz", 0xff00, 0xe100, INSN_CLASS_RBRA8 }, + { "bov", 0xff00, 0xe400, INSN_CLASS_RBRA8 }, + { "bra", 0xf800, 0xd000, INSN_CLASS_RBRA11 }, + { "bsf", 0xf000, 0x8000, INSN_CLASS_BA8 }, + { "btfsc", 0xf000, 0xb000, INSN_CLASS_BA8 }, + { "btfss", 0xf000, 0xa000, INSN_CLASS_BA8 }, + { "btg", 0xf000, 0x7000, INSN_CLASS_BA8 }, + { "bz", 0xff00, 0xe000, INSN_CLASS_RBRA8 }, + { "call", 0xfe00, 0xec00, INSN_CLASS_CALL20 }, + { "clrf", 0xfe00, 0x6a00, INSN_CLASS_OPFA8 }, + { "clrwdt", 0xffff, 0x0004, INSN_CLASS_IMPLICIT }, + { "comf", 0xfc00, 0x1c00, INSN_CLASS_OPWFA8 }, + { "cpfseq", 0xfe00, 0x6200, INSN_CLASS_OPFA8 }, + { "cpfsgt", 0xfe00, 0x6400, INSN_CLASS_OPFA8 }, + { "cpfslt", 0xfe00, 0x6000, INSN_CLASS_OPFA8 }, + { "daw", 0xffff, 0x0007, INSN_CLASS_IMPLICIT }, + { "decf", 0xfc00, 0x0400, INSN_CLASS_OPWFA8 }, + { "decfsz", 0xfc00, 0x2c00, INSN_CLASS_OPWFA8 }, + { "dcfsnz", 0xfc00, 0x4c00, INSN_CLASS_OPWFA8 }, + { "goto", 0xff00, 0xef00, INSN_CLASS_LIT20 }, + { "incf", 0xfc00, 0x2800, INSN_CLASS_OPWFA8 }, + { "incfsz", 0xfc00, 0x3c00, INSN_CLASS_OPWFA8 }, + { "infsnz", 0xfc00, 0x4800, INSN_CLASS_OPWFA8 }, + { "iorlw", 0xff00, 0x0900, INSN_CLASS_LIT8 }, + { "iorwf", 0xfc00, 0x1000, INSN_CLASS_OPWFA8 }, + { "lfsr", 0xffc0, 0xee00, INSN_CLASS_FLIT12 }, + { "movf", 0xfc00, 0x5000, INSN_CLASS_OPWFA8 }, + { "movff", 0xf000, 0xc000, INSN_CLASS_FF }, + { "movlb", 0xff00, 0x0100, INSN_CLASS_LIT8 }, + { "movlw", 0xff00, 0x0e00, INSN_CLASS_LIT8 }, + { "movwf", 0xfe00, 0x6e00, INSN_CLASS_OPFA8 }, + { "mullw", 0xff00, 0x0d00, INSN_CLASS_LIT8 }, + { "mulwf", 0xfe00, 0x0200, INSN_CLASS_OPFA8 }, + { "negf", 0xfe00, 0x6c00, INSN_CLASS_OPFA8 }, + { "nop", 0xffff, 0x0000, INSN_CLASS_IMPLICIT }, + { "pop", 0xffff, 0x0006, INSN_CLASS_IMPLICIT }, + { "push", 0xffff, 0x0005, INSN_CLASS_IMPLICIT }, + { "rcall", 0xf800, 0xd800, INSN_CLASS_RBRA11 }, + { "reset", 0xffff, 0x00ff, INSN_CLASS_IMPLICIT }, + { "retfie", 0xfffe, 0x0010, INSN_CLASS_LIT1 }, + { "retlw", 0xff00, 0x0c00, INSN_CLASS_LIT8 }, + { "return", 0xfffe, 0x0012, INSN_CLASS_LIT1 }, + { "rlcf", 0xfc00, 0x3400, INSN_CLASS_OPWFA8 }, + { "rlncf", 0xfc00, 0x4400, INSN_CLASS_OPWFA8 }, + { "rrcf", 0xfc00, 0x3000, INSN_CLASS_OPWFA8 }, + { "rrncf", 0xfc00, 0x4000, INSN_CLASS_OPWFA8 }, + { "setf", 0xfe00, 0x6800, INSN_CLASS_OPFA8 }, + { "sleep", 0xffff, 0x0003, INSN_CLASS_IMPLICIT }, + { "subfwb", 0xfc00, 0x5400, INSN_CLASS_OPWFA8 }, + { "sublw", 0xff00, 0x0800, INSN_CLASS_LIT8 }, + { "subwf", 0xfc00, 0x5c00, INSN_CLASS_OPWFA8 }, + { "subwfb", 0xfc00, 0x5800, INSN_CLASS_OPWFA8 }, + { "swapf", 0xfc00, 0x3800, INSN_CLASS_OPWFA8 }, + { "tblrd", 0xfffc, 0x0008, INSN_CLASS_TBL }, + { "tblwt", 0xfffc, 0x000c, INSN_CLASS_TBL }, + { "tstfsz", 0xfe00, 0x6600, INSN_CLASS_OPFA8 }, + { "xorlw", 0xff00, 0x0a00, INSN_CLASS_LIT8 }, + { "xorwf", 0xfc00, 0x1800, INSN_CLASS_OPWFA8 } +}; + +const int num_op_18cxx = TABLE_SIZE(op_18cxx); + +/* PIC 16-bit "Special" instruction set */ +struct insn op_18cxx_sp[] = { + { "clrc", 0xffff, 0x90d8, INSN_CLASS_IMPLICIT }, + { "clrdc", 0xffff, 0x92d8, INSN_CLASS_IMPLICIT }, + { "clrn", 0xffff, 0x98d8, INSN_CLASS_IMPLICIT }, + { "clrov", 0xffff, 0x96d8, INSN_CLASS_IMPLICIT }, + { "clrw", 0xffff, 0x6ae8, INSN_CLASS_IMPLICIT }, + { "clrz", 0xffff, 0x94d8, INSN_CLASS_IMPLICIT }, + { "setc", 0xffff, 0x80d8, INSN_CLASS_IMPLICIT }, + { "setdc", 0xffff, 0x82d8, INSN_CLASS_IMPLICIT }, + { "setn", 0xffff, 0x88d8, INSN_CLASS_IMPLICIT }, + { "setov", 0xffff, 0x86d8, INSN_CLASS_IMPLICIT }, + { "setz", 0xffff, 0x84d8, INSN_CLASS_IMPLICIT }, + { "skpc", 0xffff, 0xa0d8, INSN_CLASS_IMPLICIT }, + { "skpdc", 0xffff, 0xa2d8, INSN_CLASS_IMPLICIT }, + { "skpn", 0xffff, 0xa8d8, INSN_CLASS_IMPLICIT }, + { "skpov", 0xffff, 0xa6d8, INSN_CLASS_IMPLICIT }, + { "skpz", 0xffff, 0xa4d8, INSN_CLASS_IMPLICIT }, + { "skpnc", 0xffff, 0xb0d8, INSN_CLASS_IMPLICIT }, + { "skpndc", 0xffff, 0xb2d8, INSN_CLASS_IMPLICIT }, + { "skpnn", 0xffff, 0xb8d8, INSN_CLASS_IMPLICIT }, + { "skpnov", 0xffff, 0xb6d8, INSN_CLASS_IMPLICIT }, + { "skpnz", 0xffff, 0xb4d8, INSN_CLASS_IMPLICIT }, + { "tgc", 0xffff, 0x70d8, INSN_CLASS_IMPLICIT }, + { "tgdc", 0xffff, 0x72d8, INSN_CLASS_IMPLICIT }, + { "tgn", 0xffff, 0x78d8, INSN_CLASS_IMPLICIT }, + { "tgov", 0xffff, 0x76d8, INSN_CLASS_IMPLICIT }, + { "tgz", 0xffff, 0x74d8, INSN_CLASS_IMPLICIT } + +}; + +const int num_op_18cxx_sp = TABLE_SIZE(op_18cxx_sp); + +/* PIC 16-bit Extended instruction set */ +struct insn op_18cxx_ext[] = { + { "addfsr", 0xff00, 0xe800, INSN_CLASS_LITFSR }, + { "addulnk", 0xffc0, 0xe8c0, INSN_CLASS_LIT6 }, + { "callw", 0xffff, 0x0014, INSN_CLASS_IMPLICIT }, + { "movsf", 0xff80, 0xeb00, INSN_CLASS_SF }, + { "movss", 0xff80, 0xeb80, INSN_CLASS_SS }, + { "pushl", 0xff00, 0xea00, INSN_CLASS_LIT8 }, + { "subfsr", 0xff00, 0xe900, INSN_CLASS_LITFSR }, + { "subulnk", 0xffc0, 0xe9c0, INSN_CLASS_LIT6 } + +}; + +const int num_op_18cxx_ext = TABLE_SIZE(op_18cxx_ext); + diff --git a/src/coff/base/gpopcode.h b/src/coff/base/gpopcode.h new file mode 100644 index 0000000..aed25f9 --- /dev/null +++ b/src/coff/base/gpopcode.h @@ -0,0 +1,107 @@ +/* GNU PIC opcode definitions + Copyright (C) 2001, 2002, 2003, 2004, 2005 + Craig Franklin + +This file is part of gputils. + +gputils 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, or (at your option) +any later version. + +gputils is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with gputils; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#ifndef __GPOPCODE_H__ +#define __GPOPCODE_H__ + +enum insn_class { + INSN_CLASS_LIT1, /* bit 0 contains a 1 bit literal */ + INSN_CLASS_LIT4S, /* Bits 7:4 contain a 4 bit literal, bits 3:0 are unused */ + INSN_CLASS_LIT6, /* bits 5:0 contain an 6 bit literal */ + INSN_CLASS_LIT8, /* bits 7:0 contain an 8 bit literal */ + INSN_CLASS_LIT8C12, /* bits 7:0 contain an 8 bit literal, 12 bit CALL */ + INSN_CLASS_LIT8C16, /* bits 7:0 contain an 8 bit literal, 16 bit CALL */ + INSN_CLASS_LIT9, /* bits 8:0 contain a 9 bit literal */ + INSN_CLASS_LIT11, /* bits 10:0 contain an 11 bit literal */ + INSN_CLASS_LIT13, /* bits 12:0 contain an 11 bit literal */ + INSN_CLASS_LITFSR, /* bits 5:0 contain an 6 bit literal for fsr 7:6 */ + INSN_CLASS_IMPLICIT, /* instruction has no variable bits at all */ + INSN_CLASS_OPF5, /* bits 4:0 contain a register address */ + INSN_CLASS_OPWF5, /* as above, but bit 5 has a destination flag */ + INSN_CLASS_B5, /* as for OPF5, but bits 7:5 have bit number */ + INSN_CLASS_OPF7, /* bits 6:0 contain a register address */ + INSN_CLASS_OPWF7, /* as above, but bit 7 has destination flag */ + INSN_CLASS_B7, /* as for OPF7, but bits 9:7 have bit number */ + + INSN_CLASS_OPF8, /* bits 7:0 contain a register address */ + INSN_CLASS_OPFA8, /* bits 7:0 contain a register address & bit has access flag */ + INSN_CLASS_OPWF8, /* as above, but bit 8 has dest flag */ + INSN_CLASS_OPWFA8, /* as above, but bit 9 has dest flag & bit 8 has access flag */ + INSN_CLASS_B8, /* like OPF7, but bits 9:11 have bit number */ + INSN_CLASS_BA8, /* like OPF7, but bits 9:11 have bit number & bit 8 has access flag */ + INSN_CLASS_LIT20, /* 20bit lit, bits 7:0 in first word bits 19:8 in second */ + INSN_CLASS_CALL20, /* Like LIT20, but bit 8 has fast push flag */ + INSN_CLASS_RBRA8, /* Bits 7:0 contain a relative branch address */ + INSN_CLASS_RBRA11, /* Bits 10:0 contain a relative branch address */ + INSN_CLASS_FLIT12, /* LFSR, 12bit lit loaded into 1 of 4 FSRs */ + INSN_CLASS_FF, /* two 12bit file addresses */ + INSN_CLASS_FP, /* Bits 7:0 contain a register address, bits 12:8 contains a peripheral address */ + INSN_CLASS_PF, /* Bits 7:0 contain a register address, bits 12:8 contains a peripheral address */ + + INSN_CLASS_SF, /* 7 bit offset added to FSR2, fetched memory placed at 12 bit address */ + INSN_CLASS_SS, /* two 7 bit offsets, memory moved using FSR2 */ + + INSN_CLASS_TBL, /* a table read or write instruction */ + INSN_CLASS_TBL2, /* a table read or write instruction. + Bits 7:0 contains a register address; Bit 8 is unused; + Bit 9, table byte select. (0:lower ; 1:upper) */ + INSN_CLASS_TBL3, /* a table read or write instruction. + Bits 7:0 contains a register address; + Bit 8, 1 if increment pointer, 0 otherwise; + Bit 9, table byte select. (0:lower ; 1:upper) */ + INSN_CLASS_FUNC, /* instruction is an assembler function */ + INSN_CLASS_LIT3_BANK, /* SX: bits 3:0 contain a 3 bit literal, shifted 5 bits */ + INSN_CLASS_LIT3_PAGE, /* SX: bits 3:0 contain a 3 bit literal, shifted 9 bits */ + INSN_CLASS_LIT4 /* SX: bits 3:0 contain a 4 bit literal */ +}; + +struct insn { + const char *name; + long int mask; + long int opcode; + enum insn_class classType; + //int attribs; +}; + +#define TABLE_SIZE(X) (sizeof(X) / sizeof(X[0])) + +extern struct insn op_12c5xx[]; +extern const int num_op_12c5xx; + +extern struct insn op_sx[]; +extern const int num_op_sx; + +extern struct insn op_16cxx[]; +extern const int num_op_16cxx; + +extern struct insn op_17cxx[]; +extern const int num_op_17cxx; + +extern struct insn op_18cxx[]; +extern const int num_op_18cxx; + +extern struct insn op_18cxx_sp[]; +extern const int num_op_18cxx_sp; + +extern struct insn op_18cxx_ext[]; +extern const int num_op_18cxx_ext; + +#endif diff --git a/src/coff/base/text_coff.cpp b/src/coff/base/text_coff.cpp new file mode 100644 index 0000000..0d0862e --- /dev/null +++ b/src/coff/base/text_coff.cpp @@ -0,0 +1,262 @@ +/*************************************************************************** + * 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 "text_coff.h" + +#include "common/global/pfile.h" + +namespace Coff +{ +class CodeData { +public: + QString address, opcode, disasm1, disasm2; +}; +class LineData { +public: + QValueVector<CodeData> codes; + QString lineNumber, lineText; +}; +class FileData { +public: + PURL::Url url; + bool read; + QValueVector<LineData> lines; +}; +} + +Coff::TextObject::TextObject(const Device::Data *device, const PURL::Url &url) + : Object(device, url), _initialized(true) +{} + +bool Coff::TextObject::parse(Log::Base &log) +{ + bool ok = Object::parse(log); + _initialized = !ok; + return ok; +} + +PURL::Url Coff::TextObject::urlForFilename(const QString &filename) const +{ + PURL::Url rurl = PURL::Url::fromPathOrUrl(filename); + return rurl.toAbsolute(url().directory()); +} + +const Coff::Section *Coff::TextObject::section(const CodeLine &cline) const +{ + if ( cline.section().instructions().contains(cline.address()) ) return &cline.section(); + // possible for coff generated by picc... + for (uint i=0; i<uint(_sections.count()); i++) { + if ( _sections[i]->type()!=SectionType::Code ) continue; + if ( _sections[i]->instructions().contains(cline.address()) ) return _sections[i]; + } + return 0; +} + +void Coff::TextObject::init() const +{ + if (_initialized) return; + _initialized = true; + + // open and read files + QMap<QString, FileData> fd; + for (uint i=0; i<uint(_sections.count()); i++) { + if ( _sections[i]->type()!=SectionType::Code ) continue; + for (uint k=0; k<uint(_sections[i]->lines().count()); k++) { + QString filename = _sections[i]->lines()[k]->filename(); + if ( filename.isEmpty() || fd.contains(filename) ) continue; + _filenames.append(filename); + FileData fdata; + fdata.url = urlForFilename(filename); + Log::StringView sview; + PURL::File file(fdata.url, sview); + fdata.read = file.openForRead(); + if (fdata.read) { + QStringList lines = file.readLines(); + fdata.lines.resize(lines.count()); + for (uint i=0; i<uint(lines.count()); i++) + fdata.lines[i].lineText = lines[i]; + } else fdata.lines.resize(nbLines(filename)); + fd[filename] = fdata; + } + } + + // create strings (for later justification) + const uint addressWidth = _device->nbCharsAddress(); + uint opcodeWidth = 0, disasm1Width = 0, disasm2Width = 0, lineNumberWidth = 0, lineTextWidth = 0; + QMap<QString, FileData>::iterator it; + for (it=fd.begin(); it!=fd.end(); ++it) { + for (uint i=0; i<uint(it.data().lines.count()); i++) { + LineData &ldata = it.data().lines[i]; + QValueVector<const CodeLine *> lines = findCodeLines(it.key(), i); + ldata.codes.resize(lines.count()); + for (uint k=0; k<uint(lines.count()); k++) { + Address address = lines[k]->address(); + ldata.codes[k].address = toHex(address, addressWidth).upper(); + const Section *sec = section(*lines[k]); + if (sec) { + ldata.codes[k].opcode = "0x" + sec->instructions()[address].opcode.upper(); + //qDebug("%s: %s", ldata.codes[k].address.latin1(), ldata.codes[k].opcode.latin1()); + opcodeWidth = qMax(opcodeWidth, uint(ldata.codes[k].opcode.length())); + QString s = sec->instructions()[address].disasm; + int j = s.find('\t'); + if ( j!=-1 ) { + ldata.codes[k].disasm2 = s.mid(j+1); + disasm2Width = qMax(disasm2Width, uint(ldata.codes[k].disasm2.length())); + } + ldata.codes[k].disasm1 = (j==-1 ? s : s.mid(0, j)); + disasm1Width = qMax(disasm1Width, uint(ldata.codes[k].disasm1.length())); + } + } + ldata.lineNumber = QString::number(i+1); + lineNumberWidth = qMax(lineNumberWidth, uint(ldata.lineNumber.length())); + lineTextWidth = qMax(lineTextWidth, uint(ldata.lineText.length())); + } + } + uint asmWidth = addressWidth + 4 + opcodeWidth + 4 + disasm1Width + 2 + disasm2Width; + uint totalWidth = asmWidth + 4 + lineNumberWidth + 2 + lineTextWidth; + + // create text + for (it = fd.begin(); it!=fd.end(); ++it) { + QString s = QString("--- ") + it.data().url.pretty() + " "; + _list += s.leftJustify(totalWidth, '-'); + if ( !it.data().read ) { + s = QString("--- ") + i18n("File could not be read") + " "; + _list += s.leftJustify(totalWidth, '-'); + } + for (uint i=0; i<uint(it.data().lines.count()); i++) { + const LineData &ldata = it.data().lines[i]; + QString cline = repeat(" ", 4) + ldata.lineNumber.leftJustify(lineNumberWidth) + ": " + ldata.lineText; + if ( ldata.codes.count()==0 ) _list += stripEndingWhiteSpaces(repeat(" ", asmWidth) + cline); + else for (uint k=0; k<uint(ldata.codes.count()); k++) { + if ( ldata.codes[k].opcode.isEmpty() ) continue; + QString line; + line += ldata.codes[k].address + repeat(" ", 4); + line += ldata.codes[k].opcode.leftJustify(opcodeWidth) + repeat(" ", 4); + line += ldata.codes[k].disasm1.leftJustify(disasm1Width) + repeat(" ", 2); + line += ldata.codes[k].disasm2.leftJustify(disasm2Width); + _lines[fromHex(ldata.codes[k].address, 0)] = _list.count()+1; + if ( k==0 ) line += cline; + _list += stripEndingWhiteSpaces(line); + } + } + } +} + +uint Coff::TextObject::nbLines(const QString &filename) const +{ + init(); + uint nb = 0; + for (uint i=0; i<uint(_sections.count()); i++) { + if ( _sections[i]->type()!=SectionType::Code ) continue; + for (uint k=0; k<uint(_sections[i]->lines().count()); k++) { + const CodeLine *cl = _sections[i]->lines()[k]; + if ( cl->filename()==filename ) nb = qMax(nb, cl->line()); + } + } + return nb; +} + +QValueVector<const Coff::CodeLine *> Coff::TextObject::findCodeLines(const QString &filename, uint line) const +{ + init(); + QValueVector<const CodeLine *> list; + for (uint i=0; i<uint(_sections.count()); i++) { + if ( _sections[i]->type()!=SectionType::Code ) continue; + for (uint k=0; k<uint(_sections[i]->lines().count()); k++) { + const CodeLine *cl = _sections[i]->lines()[k]; + if ( (cl->line()-1)==line && cl->filename()==filename ) list.append(cl); + } + } + return list; +} + +int Coff::TextObject::lineForAddress(const PURL::Url &url, Address address) const +{ + init(); + if ( url==_url && _lines.contains(address) ) return _lines[address]-1; + for (uint i=0; i<uint(_sections.count()); i++) { + if ( _sections[i]->type()!=SectionType::Code ) continue; + for (uint k=0; k<uint(_sections[i]->lines().count()); k++) { + const CodeLine *cl = _sections[i]->lines()[k]; + if ( cl->address()!=address ) continue; + QString filename = cl->filename(); + if ( filename.isEmpty() || urlForFilename(filename)!=url ) continue; + return cl->line()-1; + } + } + return -1; +} + +QMap<PURL::Url, uint> Coff::TextObject::sourceLinesForAddress(Address address) const +{ + QMap<PURL::Url, uint> slines; + init(); + for (uint i=0; i<uint(_sections.count()); i++) { + if ( _sections[i]->type()!=SectionType::Code ) continue; + for (uint k=0; k<uint(_sections[i]->lines().count()); k++) { + const CodeLine *cl = _sections[i]->lines()[k]; + if ( cl->address()!=address ) continue; + QString filename = cl->filename(); + if ( filename.isEmpty() ) continue; + slines[urlForFilename(filename)] = cl->line()-1; + } + } + if ( _lines.contains(address) ) slines[_url] = _lines[address] - 1; + return slines; +} + +QValueVector<Address> Coff::TextObject::addresses(const PURL::Url &url, uint line) const +{ + init(); + QValueVector<Address> ad; + if ( url==_url ) { + QMap<Address, uint>::const_iterator it; + for (it=_lines.begin(); it!=_lines.end(); ++it) + if ( line==(it.data()-1) ) ad.append(it.key()); + return ad; + } + for (uint i=0; i<uint(_sections.count()); i++) { + if ( _sections[i]->type()!=SectionType::Code ) continue; + for (uint k=0; k<uint(_sections[i]->lines().count()); k++) { + const CodeLine *cl = _sections[i]->lines()[k]; + if ( line!=(cl->line()-1) ) continue; + QString filename = cl->filename(); + if ( filename.isEmpty() || urlForFilename(filename)!=url ) continue; + ad.append(cl->address()); + } + } + return ad; +} + +const QStringList &Coff::TextObject::filenames() const +{ + init(); + return _filenames; +} + +QString Coff::TextObject::disassembly() const +{ + init(); + if ( _list.isEmpty() ) return i18n("Parsing COFF file is not supported for this device or an error occured."); + return _list.join("\n"); +} + +Log::KeyList Coff::TextObject::information() const +{ + Log::KeyList keys; + keys.append(i18n("Format:"), i18n("%1 (magic id: %2)").arg(format().label()).arg(toHexLabel(format().data().magic, 4))); + QString name = (format()==Format::PIC30 || device()==0 ? "?" : device()->name()); + keys.append(i18n("Device:"), name); + OptHeaderFormat ohf = optHeaderFormat(); + QString label = (ohf==OptHeaderFormat::Nb_Types ? i18n("Unknown") : ohf.label()); + keys.append(i18n("Option header:"), i18n("%1 (magic id: %2)").arg(label).arg(toHexLabel(optHeaderMagic(), 4))); + keys.append(i18n("No. of sections:"), QString::number(nbSections())); + keys.append(i18n("No. of symbols:"), QString::number(nbSymbols())); + keys.append(i18n("No. of variables:"), QString::number(variables().count())); + return keys; +} diff --git a/src/coff/base/text_coff.h b/src/coff/base/text_coff.h new file mode 100644 index 0000000..7b6e673 --- /dev/null +++ b/src/coff/base/text_coff.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * 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. * + ***************************************************************************/ +#ifndef TEXT_COFF_H +#define TEXT_COFF_H + +#include "coff_object.h" + +namespace Coff +{ + +class TextObject : public Object +{ +public: + TextObject(const Device::Data *device, const PURL::Url &url); + virtual bool parse(Log::Base &log); + int lineForAddress(const PURL::Url &url, Address address) const; + QMap<PURL::Url, uint> sourceLinesForAddress(Address address) const; // url -> line + QValueVector<Address> addresses(const PURL::Url &url, uint line) const; + const QStringList &filenames() const; + + QString disassembly() const; + virtual Log::KeyList information() const; + +private: + mutable bool _initialized; + mutable QMap<Address, uint> _lines; // address -> line in disassembly listing + mutable QStringList _list; + mutable QStringList _filenames; + + uint nbLines(const QString &filename) const; + QValueVector<const CodeLine *> findCodeLines(const QString &filename, uint line) const; + PURL::Url urlForFilename(const QString &filename) const; + void init() const; + const Section *section(const CodeLine &cline) const; +}; + +} // namespace + +#endif |