From 0f717e1063154f0baec62f80e043d4d1c3317ce0 Mon Sep 17 00:00:00 2001 From: Harisuddin Mohamed Isa Date: Wed, 15 Jan 2020 20:05:33 +0800 Subject: PEL: Print SRC section into JSON For BMC created errors, look up the reason code in the message registry for error description and also meaning of data stored in hexwords 6-9 (if any). Added registry message field in peltool list output. "Primary SRC": { "Section Version": "1", "Sub-section type": "1", "Created by": "0x1000", "SRC Version": "0x02", "SRC Format": "0x55", "Power Control Net Fault": "False", "Error Details": { "Message": "PS 0x64 had a PGOOD Fault", "PS_NUM": "0x64" }, "Valid Word Count": "0x09", "Reference Code": "BD8D1001", "Hex Word 2": "00000055", "Hex Word 3": "00000010", "Hex Word 4": "00000000", "Hex Word 5": "00000000", "Hex Word 6": "00000064", "Hex Word 7": "00000000", "Hex Word 8": "00000000", "Hex Word 9": "00000000" } "Primary SRC": { "Section Version": "1", "Sub-section type": "0", "Created by": "0x4552", "SRC Version": "0x02", "SRC Format": "0x2008000", "Power Control Net Fault": "False", "Valid Word Count": "0x04", "Reference Code": "B2001020", "Hex Word 2": "02008000", "Hex Word 3": "00000000", "Hex Word 4": "00000012", "Callout Section": { "Callout Count": "1", "Callouts": [{ "FRU Type": "Symbolic FRU", "Priority": "Medium Priority", "Part Number": "NEXTLVL" }] } } Testing: Manually run peltool and verified out. All unit tests passed. Signed-off-by: Harisuddin Mohamed Isa Change-Id: I124627ba785413ebda02305b7d9f95431922e714 --- extensions/openpower-pels/callout.hpp | 10 ++ extensions/openpower-pels/json_utils.cpp | 2 +- extensions/openpower-pels/json_utils.hpp | 27 ++- extensions/openpower-pels/manager.cpp | 3 +- extensions/openpower-pels/pel_values.cpp | 43 +++-- extensions/openpower-pels/pel_values.hpp | 15 ++ extensions/openpower-pels/registry.cpp | 90 +++++++--- extensions/openpower-pels/registry.hpp | 62 ++++++- extensions/openpower-pels/src.cpp | 258 +++++++++++++++++++++++++++- extensions/openpower-pels/src.hpp | 41 ++++- extensions/openpower-pels/tools/peltool.cpp | 30 +++- 11 files changed, 530 insertions(+), 51 deletions(-) (limited to 'extensions') diff --git a/extensions/openpower-pels/callout.hpp b/extensions/openpower-pels/callout.hpp index 76eb0f9..caf3aec 100644 --- a/extensions/openpower-pels/callout.hpp +++ b/extensions/openpower-pels/callout.hpp @@ -64,6 +64,16 @@ class Callout */ void flatten(Stream& pel) const; + /** + * @brief Returns the flags field of a callout + * + * @return uint8_t - The flags + */ + uint8_t flags() const + { + return _flags; + } + /** * @brief Returns the priority field of a callout * diff --git a/extensions/openpower-pels/json_utils.cpp b/extensions/openpower-pels/json_utils.cpp index c6ea9f6..a25311c 100644 --- a/extensions/openpower-pels/json_utils.cpp +++ b/extensions/openpower-pels/json_utils.cpp @@ -139,7 +139,7 @@ char* dumpHex(const void* data, size_t size) } void jsonInsert(std::string& jsonStr, const std::string& fieldName, - std::string& fieldValue, uint8_t indentCount) + std::string fieldValue, uint8_t indentCount) { const int8_t spacesToAppend = colAlign - (indentCount * indentLevel) - fieldName.length() - 3; diff --git a/extensions/openpower-pels/json_utils.hpp b/extensions/openpower-pels/json_utils.hpp index 14c2ce4..f3fb767 100644 --- a/extensions/openpower-pels/json_utils.hpp +++ b/extensions/openpower-pels/json_utils.hpp @@ -39,7 +39,7 @@ char* dumpHex(const void* data, size_t size); * @param[in] indentCount - Indent count for the line */ void jsonInsert(std::string& jsonStr, const std::string& fieldName, - std::string& fieldValue, uint8_t indentCount); + std::string fieldValue, uint8_t indentCount); /** * @brief Inserts key-value array into a JSON string @@ -51,5 +51,30 @@ void jsonInsert(std::string& jsonStr, const std::string& fieldName, */ void jsonInsertArray(std::string& jsonStr, const std::string& fieldName, std::vector& values, uint8_t indentCount); + +/** + * @brief Converts an integer to a formatted string + * @param[in] format - the format of output string + * @param[in] number - the integer to convert + * @return std::string - the formatted string + */ +template +std::string getNumberString(const char* format, T number) +{ + char* value = nullptr; + std::string numString; + + static_assert(std::is_integral::value, "Integral required."); + + int len = asprintf(&value, format, number); + if (len) + { + numString = value; + } + free(value); + + return numString; +} + } // namespace pels } // namespace openpower diff --git a/extensions/openpower-pels/manager.cpp b/extensions/openpower-pels/manager.cpp index a705e67..a00da37 100644 --- a/extensions/openpower-pels/manager.cpp +++ b/extensions/openpower-pels/manager.cpp @@ -31,6 +31,7 @@ namespace pels using namespace phosphor::logging; namespace fs = std::filesystem; +namespace rg = openpower::pels::message; namespace common_error = sdbusplus::xyz::openbmc_project::Common::Error; @@ -130,7 +131,7 @@ void Manager::createPEL(const std::string& message, uint32_t obmcLogID, const std::vector& additionalData, const std::vector& associations) { - auto entry = _registry.lookup(message); + auto entry = _registry.lookup(message, rg::LookupType::name); std::string msg; if (entry) diff --git a/extensions/openpower-pels/pel_values.cpp b/extensions/openpower-pels/pel_values.cpp index cb00150..7e7f93b 100644 --- a/extensions/openpower-pels/pel_values.cpp +++ b/extensions/openpower-pels/pel_values.cpp @@ -206,12 +206,12 @@ const PELValues actionFlagsValues = { * The possible values for the Callout Priority field in the SRC. */ const PELValues calloutPriorityValues = { - {'H', "high", "Mandatory, replace all with this type as a unit"}, - {'M', "medium", "Medium Priority"}, - {'A', "medium_group_a", "Medium Priority A, replace these as a group"}, - {'B', "medium_group_b", "Medium Priority B, replace these as a group"}, - {'C', "medium_group_c", "Medium Priority C, replace these as a group"}, - {'L', "low", "Lowest priority replacement"}}; + {0x48, "high", "Mandatory, replace all with this type as a unit"}, + {0x4D, "medium", "Medium Priority"}, + {0x41, "medium_group_a", "Medium Priority A, replace these as a group"}, + {0x42, "medium_group_b", "Medium Priority B, replace these as a group"}, + {0x43, "medium_group_c", "Medium Priority C, replace these as a group"}, + {0x4C, "low", "Lowest priority replacement"}}; PELValues::const_iterator findByValue(uint32_t value, const PELValues& fields) { @@ -235,7 +235,6 @@ PELValues::const_iterator findByName(const std::string& name, * @brief Map for section IDs */ const std::map sectionTitles = { - {"PH", "Private Header"}, {"UH", "User Header"}, {"PS", "Primary SRC"}, @@ -244,7 +243,7 @@ const std::map sectionTitles = { {"MT", "Failing MTMS"}, {"DH", "Dump Location"}, {"SW", "Firmware Error"}, - {"LP", "Impacted Part"}, + {"LP", "Impacted Partition"}, {"LR", "Logical Resource"}, {"HM", "HMC ID"}, {"EP", "EPOW"}, @@ -253,8 +252,32 @@ const std::map sectionTitles = { {"CH", "Call Home"}, {"UD", "User Data"}, {"EI", "Env Info"}, - {"ED", "Extended User Data"}, -}; + {"ED", "Extended User Data"}}; + +/** + * @brief Map for Procedure Descriptions + */ +const std::map procedureDesc = {{"TODO", "TODO"}}; + +/** + * @brief Map for Callout Failing Component Types + */ +const std::map failingComponentType = { + {0x10, "Normal Hardware FRU"}, + {0x20, "Code FRU"}, + {0x30, "Configuration error, configuration procedure required"}, + {0x40, "Maintenance Procedure Required"}, + {0x90, "External FRU"}, + {0xA0, "External Code FRU"}, + {0xB0, "Tool FRU"}, + {0xC0, "Symbolic FRU"}, + {0xE0, "Symbolic FRU with trusted location code"}}; + +/** + * @brief Map for Boolean value + */ +const std::map boolString = {{true, "True"}, + {false, "False"}}; /** * @brief Map for creator IDs diff --git a/extensions/openpower-pels/pel_values.hpp b/extensions/openpower-pels/pel_values.hpp index a52c8b3..2424c63 100644 --- a/extensions/openpower-pels/pel_values.hpp +++ b/extensions/openpower-pels/pel_values.hpp @@ -112,6 +112,21 @@ extern const std::map creatorIDs; */ extern const std::map transmissionStates; +/** + * @brief Map for Procedure Descriptions + */ +extern const std::map procedureDesc; + +/** + * @brief Map for Callout Failing Component Types + */ +extern const std::map failingComponentType; + +/** + * @brief Map for Boolean value + */ +extern const std::map boolString; + } // namespace pel_values } // namespace pels } // namespace openpower diff --git a/extensions/openpower-pels/registry.cpp b/extensions/openpower-pels/registry.cpp index d749ab9..3c4e016 100644 --- a/extensions/openpower-pels/registry.cpp +++ b/extensions/openpower-pels/registry.cpp @@ -264,37 +264,34 @@ uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode, } // namespace helper -std::optional Registry::lookup(const std::string& name) +std::optional Registry::lookup(const std::string& name, LookupType type, + bool toCache) { - // Look in /etc first in case someone put a test file there - fs::path debugFile{fs::path{debugFilePath} / registryFileName}; - nlohmann::json registry; - std::ifstream file; - - if (fs::exists(debugFile)) - { - log("Using debug PEL message registry"); - file.open(debugFile); - } - else - { - file.open(_registryFile); - } - - try + std::optional registryTmp; + auto& registryOpt = (_registry) ? _registry : registryTmp; + if (!registryOpt) { - registry = nlohmann::json::parse(file); - } - catch (std::exception& e) - { - log("Error parsing message registry JSON", - entry("JSON_ERROR=%s", e.what())); - return std::nullopt; + registryOpt = readRegistry(_registryFile); + if (!registryOpt) + { + return std::nullopt; + } + else if (toCache) + { + // Save message registry in memory for peltool + _registry = std::move(registryTmp); + } } - + auto& reg = (_registry) ? _registry : registryTmp; + const auto& registry = reg.value(); // Find an entry with this name in the PEL array. - auto e = std::find_if(registry["PELs"].begin(), registry["PELs"].end(), - [&name](const auto& j) { return name == j["Name"]; }); + auto e = std::find_if( + registry["PELs"].begin(), registry["PELs"].end(), + [&name, &type](const auto& j) { + return ((name == j["Name"] && type == LookupType::name) || + (name == j["SRC"]["ReasonCode"] && + type == LookupType::reasonCode)); + }); if (e != registry["PELs"].end()) { @@ -371,6 +368,14 @@ std::optional Registry::lookup(const std::string& name) entry.src.powerFault = src["PowerFault"]; } + auto& doc = (*e)["Documentation"]; + entry.doc.message = doc["Message"]; + entry.doc.description = doc["Description"]; + if (doc.find("MessageArgSources") != doc.end()) + { + entry.doc.messageArgSources = doc["MessageArgSources"]; + } + return entry; } catch (std::exception& e) @@ -383,6 +388,37 @@ std::optional Registry::lookup(const std::string& name) return std::nullopt; } +std::optional + Registry::readRegistry(const std::filesystem::path& registryFile) +{ + // Look in /etc first in case someone put a test file there + fs::path debugFile{fs::path{debugFilePath} / registryFileName}; + nlohmann::json registry; + std::ifstream file; + + if (fs::exists(debugFile)) + { + log("Using debug PEL message registry"); + file.open(debugFile); + } + else + { + file.open(registryFile); + } + + try + { + registry = nlohmann::json::parse(file); + } + catch (std::exception& e) + { + log("Error parsing message registry JSON", + entry("JSON_ERROR=%s", e.what())); + return std::nullopt; + } + return registry; +} + } // namespace message } // namespace pels } // namespace openpower diff --git a/extensions/openpower-pels/registry.hpp b/extensions/openpower-pels/registry.hpp index d75c30a..0a75d8e 100644 --- a/extensions/openpower-pels/registry.hpp +++ b/extensions/openpower-pels/registry.hpp @@ -13,6 +13,39 @@ namespace message { constexpr auto registryFileName = "message_registry.json"; +enum class LookupType +{ + name = 0, + reasonCode = 1 +}; + +/** + * @brief Represents the Documentation related fields in the message registry. + * It is part of the 'Entry' structure that will be filled in when + * an error is looked up in the registry. + * + * If a field is wrapped by std::optional, it means the field is + * optional in the JSON and higher level code knows how to handle it. + */ +struct DOC +{ + /** + * @brief Description of error + */ + std::string description; + + /** + * @brief Error message field + */ + std::string message; + + /** + * @brief An optional vector of SRC word 6-9 to use as the source of the + * numeric arguments that will be substituted into any placeholder + * in the Message field. + */ + std::optional> messageArgSources; +}; /** * @brief Represents the SRC related fields in the message registry. @@ -123,6 +156,11 @@ struct Entry * The SRC related fields. */ SRC src; + + /** + * The Documentation related fields. + */ + DOC doc; }; /** @@ -155,24 +193,42 @@ class Registry } /** - * @brief Find a registry entry based on its error name. + * @brief Find a registry entry based on its error name or reason code. * * This function does do some basic sanity checking on the JSON contents, * but there is also an external program that enforces a schema on the * registry JSON that should catch all of these problems ahead of time. * * @param[in] name - The error name, like xyz.openbmc_project.Error.Foo - * + * - OR + * - The reason code, like 0x1001 + * @param[in] type - LookupType enum value + * @param[in] toCache - boolean to cache registry in memory * @return optional A filled in message registry structure if * found, otherwise an empty optional object. */ - std::optional lookup(const std::string& name); + std::optional lookup(const std::string& name, LookupType type, + bool toCache = false); private: + /** + * @brief Parse message registry file using nlohmann::json + * @param[in] registryFile - The message registry JSON file + * @return optional The full message registry object or an + * empty optional object upon failure. + */ + std::optional + readRegistry(const std::filesystem::path& registryFile); + /** * @brief The path to the registry JSON file. */ std::filesystem::path _registryFile; + + /** + * @brief The full message registry object. + */ + std::optional _registry; }; namespace helper diff --git a/extensions/openpower-pels/src.cpp b/extensions/openpower-pels/src.cpp index b2b86bf..570c6c6 100644 --- a/extensions/openpower-pels/src.cpp +++ b/extensions/openpower-pels/src.cpp @@ -15,13 +15,18 @@ */ #include "src.hpp" +#include "json_utils.hpp" +#include "paths.hpp" +#include "pel_values.hpp" + #include namespace openpower { namespace pels { - +namespace pv = openpower::pels::pel_values; +namespace rg = openpower::pels::message; using namespace phosphor::logging; void SRC::unflatten(Stream& stream) @@ -177,5 +182,256 @@ void SRC::validate() _valid = failed ? false : true; } +std::optional SRC::getErrorDetails(message::Registry& registry, + DetailLevel type, + bool toCache) const +{ + const std::string jsonIndent(indentLevel, 0x20); + std::string errorOut; + uint8_t errorType = + strtoul(asciiString().substr(0, 2).c_str(), nullptr, 16); + if (errorType == static_cast(SRCType::bmcError) || + errorType == static_cast(SRCType::powerError)) + { + auto entry = registry.lookup("0x" + asciiString().substr(4, 4), + rg::LookupType::reasonCode, toCache); + if (entry) + { + errorOut.append(jsonIndent + "\"Error Details\": {\n"); + auto errorMsg = getErrorMessage(*entry); + if (errorMsg) + { + if (type == DetailLevel::message) + { + return errorMsg.value(); + } + else + { + jsonInsert(errorOut, "Message", errorMsg.value(), 2); + } + } + if (entry->src.hexwordADFields) + { + std::map adFields = + entry->src.hexwordADFields.value(); + for (const auto& hexwordMap : adFields) + { + jsonInsert(errorOut, hexwordMap.second, + getNumberString("0x%X", + _hexData[getWordIndexFromWordNum( + hexwordMap.first)]), + 2); + } + } + errorOut.erase(errorOut.size() - 2); + errorOut.append("\n"); + errorOut.append(jsonIndent + "},\n"); + return errorOut; + } + } + return std::nullopt; +} + +std::optional + SRC::getErrorMessage(const message::Entry& regEntry) const +{ + try + { + if (regEntry.doc.messageArgSources) + { + size_t msgLen = regEntry.doc.message.length(); + char msg[msgLen + 1]; + strcpy(msg, regEntry.doc.message.c_str()); + std::vector argSourceVals; + std::string message; + const auto& argValues = regEntry.doc.messageArgSources.value(); + for (size_t i = 0; i < argValues.size(); ++i) + { + argSourceVals.push_back(_hexData[getWordIndexFromWordNum( + argValues[i].back() - '0')]); + } + const char* msgPointer = msg; + while (*msgPointer) + { + if (*msgPointer == '%') + { + msgPointer++; + size_t wordIndex = *msgPointer - '0'; + if (isdigit(*msgPointer) && wordIndex >= 1 && + static_cast(wordIndex) <= + argSourceVals.size()) + { + message.append(getNumberString( + "0x%X", argSourceVals[wordIndex - 1])); + } + else + { + message.append("%" + std::string(1, *msgPointer)); + } + } + else + { + message.push_back(*msgPointer); + } + msgPointer++; + } + return message; + } + else + { + return regEntry.doc.message; + } + } + catch (const std::exception& e) + { + log("Cannot get error message from registry entry", + entry("ERROR=%s", e.what())); + } + return std::nullopt; +} + +std::optional SRC::getCallouts() const +{ + if (!_callouts) + { + return std::nullopt; + } + std::string printOut; + const std::string jsonIndent(indentLevel, 0x20); + const auto& callout = _callouts->callouts(); + const auto& compDescrp = pv::failingComponentType; + printOut.append(jsonIndent + "\"Callout Section\": {\n"); + jsonInsert(printOut, "Callout Count", std::to_string(callout.size()), 2); + printOut.append(jsonIndent + jsonIndent + "\"Callouts\": ["); + for (auto& entry : callout) + { + printOut.append("{\n"); + if (entry->fruIdentity()) + { + jsonInsert( + printOut, "FRU Type", + compDescrp.at(entry->fruIdentity()->failingComponentType()), 3); + jsonInsert(printOut, "Priority", + pv::getValue(entry->priority(), + pel_values::calloutPriorityValues), + 3); + if (!entry->locationCode().empty()) + { + jsonInsert(printOut, "Location Code", entry->locationCode(), 3); + } + if (entry->fruIdentity()->getPN().has_value()) + { + jsonInsert(printOut, "Part Number", + entry->fruIdentity()->getPN().value(), 3); + } + if (entry->fruIdentity()->getMaintProc().has_value()) + { + jsonInsert(printOut, "Procedure Number", + entry->fruIdentity()->getMaintProc().value(), 3); + if (pv::procedureDesc.find( + entry->fruIdentity()->getMaintProc().value()) != + pv::procedureDesc.end()) + { + jsonInsert( + printOut, "Description", + pv::procedureDesc.at( + entry->fruIdentity()->getMaintProc().value()), + 3); + } + } + if (entry->fruIdentity()->getCCIN().has_value()) + { + jsonInsert(printOut, "CCIN", + entry->fruIdentity()->getCCIN().value(), 3); + } + if (entry->fruIdentity()->getSN().has_value()) + { + jsonInsert(printOut, "Serial Number", + entry->fruIdentity()->getSN().value(), 3); + } + } + if (entry->pceIdentity()) + { + const auto& pceIdentMtms = entry->pceIdentity()->mtms(); + if (!pceIdentMtms.machineTypeAndModel().empty()) + { + jsonInsert(printOut, "PCE MTMS", + pceIdentMtms.machineTypeAndModel() + "_" + + pceIdentMtms.machineSerialNumber(), + 3); + } + if (!entry->pceIdentity()->enclosureName().empty()) + { + jsonInsert(printOut, "PCE Name", + entry->pceIdentity()->enclosureName(), 3); + } + } + if (entry->mru()) + { + const auto& mruCallouts = entry->mru()->mrus(); + std::string mruId; + for (auto& element : mruCallouts) + { + if (!mruId.empty()) + { + mruId.append(", " + getNumberString("%08X", element.id)); + } + else + { + mruId.append(getNumberString("%08X", element.id)); + } + } + jsonInsert(printOut, "MRU Id", mruId, 3); + } + printOut.erase(printOut.size() - 2); + printOut.append("\n" + jsonIndent + jsonIndent + "}, "); + }; + printOut.erase(printOut.size() - 2); + printOut.append("]\n" + jsonIndent + "}"); + return printOut; +} + +std::optional SRC::getJSON() const +{ + std::string ps; + jsonInsert(ps, "Section Version", getNumberString("%d", _header.version), + 1); + jsonInsert(ps, "Sub-section type", getNumberString("%d", _header.subType), + 1); + jsonInsert(ps, "Created by", getNumberString("0x%X", _header.componentID), + 1); + jsonInsert(ps, "SRC Version", getNumberString("0x%02X", _version), 1); + jsonInsert(ps, "SRC Format", getNumberString("0x%02X", _hexData[0]), 1); + jsonInsert(ps, "Power Control Net Fault", + pv::boolString.at(isPowerFaultEvent()), 1); + rg::Registry registry(getMessageRegistryPath() / rg::registryFileName); + auto errorDetails = getErrorDetails(registry, DetailLevel::json); + if (errorDetails) + { + ps.append(errorDetails.value()); + } + jsonInsert(ps, "Valid Word Count", getNumberString("0x%02X", _wordCount), + 1); + std::string refcode = asciiString(); + refcode = refcode.substr(0, refcode.find(0x20)); + jsonInsert(ps, "Reference Code", refcode, 1); + for (size_t i = 2; i <= _wordCount; i++) + { + jsonInsert( + ps, "Hex Word " + std::to_string(i), + getNumberString("%08X", _hexData[getWordIndexFromWordNum(i)]), 1); + } + auto calloutJson = getCallouts(); + if (calloutJson) + { + ps.append(calloutJson.value()); + } + else + { + ps.erase(ps.size() - 2); + } + return ps; +} + } // namespace pels } // namespace openpower diff --git a/extensions/openpower-pels/src.hpp b/extensions/openpower-pels/src.hpp index dada63a..2296f6f 100644 --- a/extensions/openpower-pels/src.hpp +++ b/extensions/openpower-pels/src.hpp @@ -21,6 +21,11 @@ constexpr uint8_t bmcSRCFormat = 0x55; constexpr uint8_t primaryBMCPosition = 0x10; constexpr size_t baseSRCSize = 72; +enum class DetailLevel +{ + message = 0x01, + json = 0x02 +}; /** * @class SRC * @@ -45,7 +50,10 @@ class SRC : public Section enum HeaderFlags { additionalSections = 0x01, - powerFaultEvent = 0x02 + powerFaultEvent = 0x02, + hypDumpInit = 0x04, + i5OSServiceEventBit = 0x10, + virtualProgressSRC = 0x80 }; SRC() = delete; @@ -212,6 +220,23 @@ class SRC : public Section return wordNum - 2; } + /** + * @brief Get section in JSON. + * @return std::optional - SRC section's JSON + */ + std::optional getJSON() const override; + + /** + * @brief Get error details based on refcode and hexwords + * @param[in] registry - Registry object + * @param[in] type - detail level enum value : single message or full json + * @param[in] toCache - boolean to cache registry in memory, default=false + * @return std::optional - Error details + */ + std::optional getErrorDetails(message::Registry& registry, + DetailLevel type, + bool toCache = false) const; + private: /** * @brief Fills in the user defined hex words from the @@ -280,6 +305,20 @@ class SRC : public Section */ void validate() override; + /** + * @brief Get error description from message registry + * @param[in] regEntry - The message registry entry for the error + * @return std::optional - Error message + */ + std::optional + getErrorMessage(const message::Entry& regEntry) const; + + /** + * @brief Get Callout info in JSON + * @return std::optional - Callout details + */ + std::optional getCallouts() const; + /** * @brief The SRC version field */ diff --git a/extensions/openpower-pels/tools/peltool.cpp b/extensions/openpower-pels/tools/peltool.cpp index 5c040ca..f1d5f59 100644 --- a/extensions/openpower-pels/tools/peltool.cpp +++ b/extensions/openpower-pels/tools/peltool.cpp @@ -16,6 +16,7 @@ #include "config.h" #include "../bcd_time.hpp" +#include "../paths.hpp" #include "../pel.hpp" #include "../pel_types.hpp" #include "../pel_values.hpp" @@ -197,7 +198,7 @@ std::string trim(std::string s, const char* t = ws) } template -std::string genPELJSON(T itr, bool hidden) +std::string genPELJSON(T itr, bool hidden, message::Registry& registry) { std::size_t found; std::string val; @@ -224,9 +225,24 @@ std::string genPELJSON(T itr, bool hidden) val = std::string(tmpValStr); listStr += "\t\"" + val + "\": {\n"; // ASCII - val = pel.primarySRC() ? pel.primarySRC().value()->asciiString() - : "No SRC"; - listStr += "\t\t\"SRC\": \"" + trim(val) + "\",\n"; + if (pel.primarySRC()) + { + val = pel.primarySRC().value()->asciiString(); + listStr += "\t\t\"SRC\": \"" + + val.substr(0, val.find(0x20)) + "\",\n"; + // Registry message + auto regVal = pel.primarySRC().value()->getErrorDetails( + registry, DetailLevel::message, true); + if (regVal) + { + val = regVal.value(); + listStr += "\t\t\"Message\": \"" + val + "\",\n"; + } + } + else + { + listStr += "\t\t\"SRC\": \"No SRC\",\n"; + } // platformid sprintf(tmpValStr, "0x%X", pel.privateHeader().plid()); val = std::string(tmpValStr); @@ -308,8 +324,10 @@ void printList(bool order, bool hidden) fileNameToTimestamp((*it).path().filename())); } } - auto buildJSON = [&listStr, &hidden](const auto& i) { - listStr += genPELJSON(i, hidden); + message::Registry registry(getMessageRegistryPath() / + message::registryFileName); + auto buildJSON = [&listStr, &hidden, ®istry](const auto& i) { + listStr += genPELJSON(i, hidden, registry); }; if (order) { -- cgit v1.2.1