summaryrefslogtreecommitdiffstats
path: root/src/coff/base
diff options
context:
space:
mode:
Diffstat (limited to 'src/coff/base')
-rw-r--r--src/coff/base/Makefile.am13
-rw-r--r--src/coff/base/base.pro6
-rw-r--r--src/coff/base/cdb_parser.cpp417
-rw-r--r--src/coff/base/cdb_parser.h166
-rw-r--r--src/coff/base/coff.cpp97
-rw-r--r--src/coff/base/coff.h64
-rw-r--r--src/coff/base/coff.xml342
-rw-r--r--src/coff/base/coff_archive.cpp129
-rw-r--r--src/coff/base/coff_archive.h53
-rw-r--r--src/coff/base/coff_data.h22
-rw-r--r--src/coff/base/coff_object.cpp658
-rw-r--r--src/coff/base/coff_object.h322
-rw-r--r--src/coff/base/disassembler.cpp289
-rw-r--r--src/coff/base/disassembler.h80
-rw-r--r--src/coff/base/gpdis.cpp349
-rw-r--r--src/coff/base/gpopcode.cpp348
-rw-r--r--src/coff/base/gpopcode.h107
-rw-r--r--src/coff/base/text_coff.cpp262
-rw-r--r--src/coff/base/text_coff.h45
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 &section,
+ 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 &section,
+ 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 &section, 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 &section, const QByteArray &data,
+ uint offset, const QString &lastFilename, Log::Base &log);
+ const Section &section() 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