From 61a1e98403a2b1eee31d3b26be712c22f172c69a Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Thu, 28 Jan 2016 00:21:51 +0100 Subject: [PATCH] UT NE A18 - fixed a bug in findNextVolume - added recursive function to add offset information - fixed and compressed attributes are now visible too --- UEFITool/uefitool.cpp | 2 +- common/ffsbuilder.cpp | 38 ++++++++++++------------ common/ffsparser.cpp | 67 +++++++++++++++++++++++++++++++------------ common/ffsparser.h | 3 +- 4 files changed, 71 insertions(+), 39 deletions(-) diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp index 7885403..dd10e1b 100644 --- a/UEFITool/uefitool.cpp +++ b/UEFITool/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.30.0_alpha17")) +version(tr("0.30.0_alpha18")) { clipboard = QApplication::clipboard(); diff --git a/common/ffsbuilder.cpp b/common/ffsbuilder.cpp index ef258ff..4bfeb46 100644 --- a/common/ffsbuilder.cpp +++ b/common/ffsbuilder.cpp @@ -10,7 +10,6 @@ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. */ - #include "ffsbuilder.h" FfsBuilder::FfsBuilder(const TreeModel* treeModel, QObject *parent) @@ -70,7 +69,7 @@ STATUS FfsBuilder::buildCapsule(const QModelIndex & index, QByteArray & capsule) // Right now there is only one capsule image element supported if (model->rowCount(index) != 1) { - msg(tr("buildCapsule: building of capsules with %1 elements are not supported, original item data used").arg(model->rowCount(index)), index); + msg(tr("buildCapsule: building of capsules with %1 elements are not supported, original item data is used").arg(model->rowCount(index)), index); // Use original item data capsule = model->header(index).append(model->body(index)); return ERR_SUCCESS; @@ -90,14 +89,14 @@ STATUS FfsBuilder::buildCapsule(const QModelIndex & index, QByteArray & capsule) // Check build result if (result) { - msg(tr("buildCapsule: building of \"%1\" failed with error \"%2\", original item data used").arg(model->name(imageIndex)).arg(errorCodeToQString(result)), imageIndex); + msg(tr("buildCapsule: building of \"%1\" failed with error \"%2\", original item data is used").arg(model->name(imageIndex)).arg(errorCodeToQString(result)), imageIndex); capsule.append(model->header(imageIndex)).append(model->body(imageIndex)); } else capsule.append(imageData); } else { - msg(tr("buildCapsule: unexpected child item of type \"%1\" can't be processed, original item data used").arg(itemTypeToQString(model->type(imageIndex))), imageIndex); + msg(tr("buildCapsule: unexpected child item of type \"%1\" can't be processed, original item data is used").arg(itemTypeToQString(model->type(imageIndex))), imageIndex); capsule.append(model->header(imageIndex)).append(model->body(imageIndex)); } @@ -129,11 +128,10 @@ STATUS FfsBuilder::buildCapsule(const QModelIndex & index, QByteArray & capsule) STATUS FfsBuilder::buildIntelImage(const QModelIndex & index, QByteArray & intelImage) { + // Sanity check if (!index.isValid()) return ERR_SUCCESS; - - // No action if (model->action(index) == Actions::NoAction) { intelImage = model->header(index).append(model->body(index)); @@ -146,7 +144,7 @@ STATUS FfsBuilder::buildIntelImage(const QModelIndex & index, QByteArray & intel // First child will always be descriptor for this type of image, and it's read only QByteArray descriptor = model->header(index.child(0, 0)).append(model->body(index.child(0, 0))); - // Other regions can be in different order, GbE, PDR and EC my be skipped + // Other regions can be in different order, GbE, PDR and EC may be skipped QByteArray gbe; QByteArray me; QByteArray bios; @@ -178,9 +176,10 @@ STATUS FfsBuilder::buildIntelImage(const QModelIndex & index, QByteArray & intel if (!gbe.isEmpty()) { msg(tr("buildIntelImage: more than one GbE region found during image rebuild, the latest one is used"), index); } + result = buildGbeRegion(currentRegion, gbe); if (result) { - msg(tr("buildIntelImage: building of GbE region failed with error \"%1\", original item data used").arg(errorCodeToQString(result)), currentRegion); + msg(tr("buildIntelImage: building of GbE region failed with error \"%1\", original item data is used").arg(errorCodeToQString(result)), currentRegion); gbe = model->header(currentRegion).append(model->body(currentRegion)); } break; @@ -188,9 +187,10 @@ STATUS FfsBuilder::buildIntelImage(const QModelIndex & index, QByteArray & intel if (!me.isEmpty()) { msg(tr("buildIntelImage: more than one ME region found during image rebuild, the latest one is used"), index); } + result = buildMeRegion(currentRegion, me); if (result) { - msg(tr("buildIntelImage: building of ME region failed with error \"%1\", original item data used").arg(errorCodeToQString(result)), currentRegion); + msg(tr("buildIntelImage: building of ME region failed with error \"%1\", original item data is used").arg(errorCodeToQString(result)), currentRegion); me = model->header(currentRegion).append(model->body(currentRegion)); } break; @@ -198,9 +198,10 @@ STATUS FfsBuilder::buildIntelImage(const QModelIndex & index, QByteArray & intel if (!bios.isEmpty()) { msg(tr("buildIntelImage: more than one BIOS region found during image rebuild, the latest one is used"), index); } + result = buildRawArea(currentRegion, bios); if (result) { - msg(tr("buildIntelImage: building of BIOS region failed with error \"%1\", original item data used").arg(errorCodeToQString(result)), currentRegion); + msg(tr("buildIntelImage: building of BIOS region failed with error \"%1\", original item data is used").arg(errorCodeToQString(result)), currentRegion); bios = model->header(currentRegion).append(model->body(currentRegion)); } break; @@ -208,9 +209,10 @@ STATUS FfsBuilder::buildIntelImage(const QModelIndex & index, QByteArray & intel if (!pdr.isEmpty()) { msg(tr("buildIntelImage: more than one PDR region found during image rebuild, the latest one is used"), index); } + result = buildPdrRegion(currentRegion, pdr); if (result) { - msg(tr("buildIntelImage: building of PDR region failed with error \"%1\", original item data used").arg(errorCodeToQString(result)), currentRegion); + msg(tr("buildIntelImage: building of PDR region failed with error \"%1\", original item data is used").arg(errorCodeToQString(result)), currentRegion); pdr = model->header(currentRegion).append(model->body(currentRegion)); } break; @@ -218,9 +220,10 @@ STATUS FfsBuilder::buildIntelImage(const QModelIndex & index, QByteArray & intel if (!ec.isEmpty()) { msg(tr("buildIntelImage: more than one EC region found during image rebuild, the latest one is used"), index); } + result = buildEcRegion(currentRegion, ec); if (result) { - msg(tr("buildIntelImage: building of EC region failed with error \"%1\", original item data used").arg(errorCodeToQString(result)), currentRegion); + msg(tr("buildIntelImage: building of EC region failed with error \"%1\", original item data is used").arg(errorCodeToQString(result)), currentRegion); ec = model->header(currentRegion).append(model->body(currentRegion)); } break; @@ -230,8 +233,7 @@ STATUS FfsBuilder::buildIntelImage(const QModelIndex & index, QByteArray & intel } } - - + // Check size of new image, it must be same as old one UINT32 newSize = intelImage.size(); UINT32 oldSize = model->body(index).size(); @@ -307,13 +309,13 @@ STATUS FfsBuilder::buildRawArea(const QModelIndex & index, QByteArray & rawArea, result = buildPadding(currentChild, currentData); } else { - msg(tr("buildRawArea: unexpected child item of type \"%1\" can't be processed, original item data used").arg(itemTypeToQString(model->type(currentChild))), currentChild); + msg(tr("buildRawArea: unexpected child item of type \"%1\" can't be processed, original item data is used").arg(itemTypeToQString(model->type(currentChild))), currentChild); result = ERR_SUCCESS; currentData = model->header(currentChild).append(model->body(currentChild)); } // Check build result if (result) { - msg(tr("buildRawArea: building of \"%1\" failed with error \"%2\", original item data used").arg(model->name(currentChild)).arg(errorCodeToQString(result)), currentChild); + msg(tr("buildRawArea: building of \"%1\" failed with error \"%2\", original item data is used").arg(model->name(currentChild)).arg(errorCodeToQString(result)), currentChild); currentData = model->header(currentChild).append(model->body(currentChild)); } // Append current data @@ -363,7 +365,7 @@ STATUS FfsBuilder::buildPadding(const QModelIndex & index, QByteArray & padding) else if (model->action(index) == Actions::Erase) { padding = model->header(index).append(model->body(index)); if(erase(index, padding)) - msg(tr("buildPadding: erase failed, original item data used"), index); + msg(tr("buildPadding: erase failed, original item data is used"), index); return ERR_SUCCESS; } @@ -387,7 +389,7 @@ STATUS FfsBuilder::buildNonUefiData(const QModelIndex & index, QByteArray & data else if (model->action(index) == Actions::Erase) { data = model->header(index).append(model->body(index)); if (erase(index, data)) - msg(tr("buildNonUefiData: erase failed, original item data used"), index); + msg(tr("buildNonUefiData: erase failed, original item data is used"), index); return ERR_SUCCESS; } diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp index 1fd034a..d731a47 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -221,7 +221,10 @@ STATUS FfsParser::parseImageFile(const QByteArray & buffer, const QModelIndex & result = parseRawArea(flashImage, biosIndex); if (result) return result; - + + // Add offsets + addOffsetsRecursive(index); + // Check if the last VTF is found if (!lastVtf.isValid()) { msg(tr("parseImageFile: not a single Volume Top File is found, the image may be corrupted"), biosIndex); @@ -627,6 +630,9 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa model->addItem(Types::Padding, getPaddingType(padding), name, QString(), info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index); } + // Add offsets + addOffsetsRecursive(index); + // Check if the last VTF is found if (!lastVtf.isValid()) { msg(tr("parseIntelImage: not a single Volume Top File is found, the image may be corrupted"), index); @@ -831,14 +837,14 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde // Get parsing data PARSING_DATA pdata = parsingDataFromQModelIndex(index); - UINT32 offset = pdata.offset; UINT32 headerSize = model->header(index).size(); + UINT32 offset = pdata.offset + headerSize; // Search for first volume STATUS result; UINT32 prevVolumeOffset; - result = findNextVolume(index, data, 0, prevVolumeOffset); + result = findNextVolume(index, data, offset, 0, prevVolumeOffset); if (result) return result; @@ -853,7 +859,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde .hexarg(padding.size()).arg(padding.size()); // Construct parsing data - pdata.offset = offset + headerSize; + pdata.offset = offset; // Add tree item model->addItem(Types::Padding, getPaddingType(padding), name, QString(), info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index); @@ -877,7 +883,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde .hexarg(padding.size()).arg(padding.size()); // Construct parsing data - pdata.offset = offset + headerSize + paddingOffset; + pdata.offset = offset + paddingOffset; // Add tree item model->addItem(Types::Padding, getPaddingType(padding), name, QString(), info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index); @@ -909,7 +915,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde .hexarg(padding.size()).arg(padding.size()); // Construct parsing data - pdata.offset = offset + headerSize + volumeOffset; + pdata.offset = offset + volumeOffset; // Add tree item QModelIndex paddingIndex = model->addItem(Types::Padding, getPaddingType(padding), name, QString(), info, QByteArray(), padding, TRUE, parsingDataToQByteArray(pdata), index); @@ -938,7 +944,7 @@ STATUS FfsParser::parseRawArea(const QByteArray & data, const QModelIndex & inde // Go to next volume prevVolumeOffset = volumeOffset; prevVolumeSize = volumeSize; - result = findNextVolume(index, data, volumeOffset + prevVolumeSize, volumeOffset); + result = findNextVolume(index, data, offset, volumeOffset + prevVolumeSize, volumeOffset); } // Padding at the end of BIOS space @@ -1184,25 +1190,25 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare return ERR_SUCCESS; } -STATUS FfsParser::findNextVolume(const QModelIndex index, const QByteArray & bios, UINT32 volumeOffset, UINT32 & nextVolumeOffset) +STATUS FfsParser::findNextVolume(const QModelIndex index, const QByteArray & bios, const UINT32 parentOffset, const UINT32 volumeOffset, UINT32 & nextVolumeOffset) { int nextIndex = bios.indexOf(EFI_FV_SIGNATURE, volumeOffset); if (nextIndex < EFI_FV_SIGNATURE_OFFSET) return ERR_VOLUMES_NOT_FOUND; // Check volume header to be sane - for (; nextIndex > 0; nextIndex = bios.indexOf(EFI_FV_SIGNATURE, volumeOffset + nextIndex + 1)) { + for (; nextIndex > 0; nextIndex = bios.indexOf(EFI_FV_SIGNATURE, nextIndex + 1)) { const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(bios.constData() + nextIndex - EFI_FV_SIGNATURE_OFFSET); if (volumeHeader->FvLength < sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 2 * sizeof(EFI_FV_BLOCK_MAP_ENTRY) || volumeHeader->FvLength >= 0xFFFFFFFFUL) { - msg(tr("findNextVolume: volume candidate skipped, has invalid FvLength %1h").hexarg2(volumeHeader->FvLength, 16), index); + msg(tr("findNextVolume: volume candidate at offset %1h skipped, has invalid FvLength %2h").hexarg(parentOffset + (nextIndex - EFI_FV_SIGNATURE_OFFSET)).hexarg2(volumeHeader->FvLength, 16), index); continue; } if (volumeHeader->Reserved != 0xFF && volumeHeader->Reserved != 0x00) { - msg(tr("findNextVolume: volume candidate skipped, has invalid Reserved byte value %1").hexarg2(volumeHeader->Reserved, 2), index); + msg(tr("findNextVolume: volume candidate at offset %1h skipped, has invalid Reserved byte value %2").hexarg(parentOffset + (nextIndex - EFI_FV_SIGNATURE_OFFSET)).hexarg2(volumeHeader->Reserved, 2), index); continue; } if (volumeHeader->Revision != 1 && volumeHeader->Revision != 2) { - msg(tr("findNextVolume: volume candidate skipped, has invalid Revision byte value %1").hexarg2(volumeHeader->Revision, 2), index); + msg(tr("findNextVolume: volume candidate at offset %1h skipped, has invalid Revision byte value %2").hexarg(parentOffset + (nextIndex - EFI_FV_SIGNATURE_OFFSET)).hexarg2(volumeHeader->Revision, 2), index); continue; } // All checks passed, volume found @@ -2729,9 +2735,6 @@ STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const U // Get parsing data for the current item PARSING_DATA pdata = parsingDataFromQModelIndex(index); - // Show offset - model->addInfo(index, tr("Offset: %1h\n").hexarg(pdata.offset), false); - // Check address sanity if ((const UINT64)diff + pdata.offset <= 0xFFFFFFFFUL) { // Update info @@ -2765,10 +2768,6 @@ STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const U } } - //TODO: debugging, don't shows FIT file fixed attribute correctly - model->addInfo(index, tr("\nCompressed: %1").arg(model->compressed(index) ? tr("Yes") : tr("No"))); - model->addInfo(index, tr("\nFixed: %1").arg(model->fixed(index) ? tr("Yes") : tr("No"))); - // Process child items for (int i = 0; i < model->rowCount(index); i++) { addMemoryAddressesRecursive(index.child(i, 0), diff); @@ -2776,3 +2775,33 @@ STATUS FfsParser::addMemoryAddressesRecursive(const QModelIndex & index, const U return ERR_SUCCESS; } + +STATUS FfsParser::addOffsetsRecursive(const QModelIndex & index) +{ + // Sanity check + if (!index.isValid()) + return ERR_INVALID_PARAMETER; + + // Get parsing data for the current item + PARSING_DATA pdata = parsingDataFromQModelIndex(index); + + // Add current offset if the element is not compressed + if (!model->compressed(index)) { + model->addInfo(index, tr("Offset: %1h\n").hexarg(pdata.offset), false); + } + // Or it's compressed, but it's parent isn't + else if (index.parent().isValid() && !model->compressed(index.parent())) { + model->addInfo(index, tr("Offset: %1h\n").hexarg(pdata.offset), false); + } + + //TODO: show FIT file fixed attribute correctly + model->addInfo(index, tr("\nCompressed: %1").arg(model->compressed(index) ? tr("Yes") : tr("No"))); + model->addInfo(index, tr("\nFixed: %1").arg(model->fixed(index) ? tr("Yes") : tr("No"))); + + // Process child items + for (int i = 0; i < model->rowCount(index); i++) { + addOffsetsRecursive(index.child(i, 0)); + } + + return ERR_SUCCESS; +} diff --git a/common/ffsparser.h b/common/ffsparser.h index 8a28ee3..7be8f09 100644 --- a/common/ffsparser.h +++ b/common/ffsparser.h @@ -91,12 +91,13 @@ private: UINT8 getPaddingType(const QByteArray & padding); STATUS parseAprioriRawSection(const QByteArray & body, QString & parsed); - STATUS findNextVolume(const QModelIndex index, const QByteArray & bios, const UINT32 volumeOffset, UINT32 & nextVolumeOffset); + STATUS findNextVolume(const QModelIndex index, const QByteArray & bios, const UINT32 parentOffset, const UINT32 volumeOffset, UINT32 & nextVolumeOffset); STATUS getVolumeSize(const QByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize); UINT32 getFileSize(const QByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion); UINT32 getSectionSize(const QByteArray & file, const UINT32 sectionOffset, const UINT8 ffsVersion); STATUS performSecondPass(const QModelIndex & index); + STATUS addOffsetsRecursive(const QModelIndex & index); STATUS addMemoryAddressesRecursive(const QModelIndex & index, const UINT32 diff); // Internal operations