summaryrefslogtreecommitdiffstats
path: root/src/coff/base/text_coff.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/coff/base/text_coff.cpp')
-rw-r--r--src/coff/base/text_coff.cpp262
1 files changed, 262 insertions, 0 deletions
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;
+}