/*************************************************************************** * Copyright (C) 2006 Nicolas Hadacek * * * * 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: TQString address, opcode, disasm1, disasm2; }; class LineData { public: TQValueVector codes; TQString lineNumber, lineText; }; class FileData { public: PURL::Url url; bool read; TQValueVector 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 TQString &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; itype()!=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 TQMap fd; for (uint i=0; itype()!=SectionType::Code ) continue; for (uint k=0; klines().count()); k++) { TQString 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) { TQStringList lines = file.readLines(); fdata.lines.resize(lines.count()); for (uint i=0; inbCharsAddress(); uint opcodeWidth = 0, disasm1Width = 0, disasm2Width = 0, lineNumberWidth = 0, lineTextWidth = 0; TQMap::iterator it; for (it=fd.begin(); it!=fd.end(); ++it) { for (uint i=0; i lines = findCodeLines(it.key(), i); ldata.codes.resize(lines.count()); for (uint k=0; kaddress(); 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(); //tqDebug("%s: %s", ldata.codes[k].address.latin1(), ldata.codes[k].opcode.latin1()); opcodeWidth = qMax(opcodeWidth, uint(ldata.codes[k].opcode.length())); TQString 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 = TQString::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) { TQString s = TQString("--- ") + it.data().url.pretty() + " "; _list += s.leftJustify(totalWidth, '-'); if ( !it.data().read ) { s = TQString("--- ") + i18n("File could not be read") + " "; _list += s.leftJustify(totalWidth, '-'); } for (uint i=0; itype()!=SectionType::Code ) continue; for (uint k=0; klines().count()); k++) { const CodeLine *cl = _sections[i]->lines()[k]; if ( cl->filename()==filename ) nb = qMax(nb, cl->line()); } } return nb; } TQValueVector Coff::TextObject::findCodeLines(const TQString &filename, uint line) const { init(); TQValueVector list; for (uint i=0; itype()!=SectionType::Code ) continue; for (uint k=0; klines().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; itype()!=SectionType::Code ) continue; for (uint k=0; klines().count()); k++) { const CodeLine *cl = _sections[i]->lines()[k]; if ( cl->address()!=address ) continue; TQString filename = cl->filename(); if ( filename.isEmpty() || urlForFilename(filename)!=url ) continue; return cl->line()-1; } } return -1; } TQMap Coff::TextObject::sourceLinesForAddress(Address address) const { TQMap slines; init(); for (uint i=0; itype()!=SectionType::Code ) continue; for (uint k=0; klines().count()); k++) { const CodeLine *cl = _sections[i]->lines()[k]; if ( cl->address()!=address ) continue; TQString filename = cl->filename(); if ( filename.isEmpty() ) continue; slines[urlForFilename(filename)] = cl->line()-1; } } if ( _lines.contains(address) ) slines[_url] = _lines[address] - 1; return slines; } TQValueVector
Coff::TextObject::addresses(const PURL::Url &url, uint line) const { init(); TQValueVector
ad; if ( url==_url ) { TQMap::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; itype()!=SectionType::Code ) continue; for (uint k=0; klines().count()); k++) { const CodeLine *cl = _sections[i]->lines()[k]; if ( line!=(cl->line()-1) ) continue; TQString filename = cl->filename(); if ( filename.isEmpty() || urlForFilename(filename)!=url ) continue; ad.append(cl->address()); } } return ad; } const TQStringList &Coff::TextObject::filenames() const { init(); return _filenames; } TQString 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))); TQString name = (format()==Format::PIC30 || device()==0 ? "?" : device()->name()); keys.append(i18n("Device:"), name); OptHeaderFormat ohf = optHeaderFormat(); TQString 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:"), TQString::number(nbSections())); keys.append(i18n("No. of symbols:"), TQString::number(nbSymbols())); keys.append(i18n("No. of variables:"), TQString::number(variables().count())); return keys; }