diff options
Diffstat (limited to 'src/coff/base/text_coff.cpp')
-rw-r--r-- | src/coff/base/text_coff.cpp | 262 |
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; +} |