PEL: PELTool Application
PELTooL application would be used to interact with PELs. This commit has
the first functionality, where a PEL file is passed and all PEL sections
are hexdumped in a JSON object.
Signed-off-by: Aatir <aatrapps@gmail.com>
Change-Id: I155d75bb58cbd14a297b094314f7fd1f271f4f37
diff --git a/extensions/openpower-pels/hexdump.cpp b/extensions/openpower-pels/hexdump.cpp
new file mode 100644
index 0000000..df9c650
--- /dev/null
+++ b/extensions/openpower-pels/hexdump.cpp
@@ -0,0 +1,121 @@
+#include "hexdump.hpp"
+
+#include <stdio.h>
+
+#include <cstring>
+#include <sstream>
+#include <string>
+
+namespace openpower
+{
+namespace pels
+{
+
+std::string escapeJSON(const std::string& input)
+{
+ std::string output;
+ output.reserve(input.length());
+
+ for (const auto c : input)
+ {
+ switch (c)
+ {
+ case '"':
+ output += "\\\"";
+ break;
+ case '/':
+ output += "\\/";
+ break;
+ case '\b':
+ output += "\\b";
+ break;
+ case '\f':
+ output += "\\f";
+ break;
+ case '\n':
+ output += "\\n";
+ break;
+ case '\r':
+ output += "\\r";
+ break;
+ case '\t':
+ output += "\\t";
+ break;
+ case '\\':
+ output += "\\\\";
+ break;
+ default:
+ output += c;
+ break;
+ }
+ }
+
+ return output;
+}
+char* dumpHex(const void* data, size_t size)
+{
+ const int symbolSize = 100;
+ char* buffer = (char*)calloc(10 * size, sizeof(char));
+ char* symbol = (char*)calloc(symbolSize, sizeof(char));
+ char ascii[17];
+ size_t i, j;
+ ascii[16] = '\0';
+ for (i = 0; i < size; ++i)
+ {
+ if (i % 16 == 0)
+ {
+ strcat(buffer, "\"");
+ }
+ snprintf(symbol, symbolSize, "%02X ", ((unsigned char*)data)[i]);
+ strcat(buffer, symbol);
+ memset(symbol, 0, strlen(symbol));
+ if (((unsigned char*)data)[i] >= ' ' &&
+ ((unsigned char*)data)[i] <= '~')
+ {
+ ascii[i % 16] = ((unsigned char*)data)[i];
+ }
+ else
+ {
+ ascii[i % 16] = '.';
+ }
+ if ((i + 1) % 8 == 0 || i + 1 == size)
+ {
+ std::string asciiString(ascii);
+ asciiString = escapeJSON(asciiString);
+ const char* asciiToPrint = asciiString.c_str();
+ strcat(buffer, " ");
+ if ((i + 1) % 16 == 0)
+ {
+ if (i + 1 != size)
+ {
+ snprintf(symbol, symbolSize, "| %s\", \n ", asciiToPrint);
+ }
+ else
+ {
+ snprintf(symbol, symbolSize, "| %s\" \n ", asciiToPrint);
+ }
+ strcat(buffer, symbol);
+ memset(symbol, 0, strlen(symbol));
+ }
+ else if (i + 1 == size)
+ {
+ ascii[(i + 1) % 16] = '\0';
+ if ((i + 1) % 16 <= 8)
+ {
+ strcat(buffer, " ");
+ }
+ for (j = (i + 1) % 16; j < 16; ++j)
+ {
+ strcat(buffer, " ");
+ }
+ snprintf(symbol, symbolSize, "| %s\" \n ", asciiToPrint);
+ strcat(buffer, symbol);
+ memset(symbol, 0, strlen(symbol));
+ }
+ }
+ }
+ free(symbol);
+ return buffer;
+}
+} // namespace pels
+} // namespace openpower
diff --git a/extensions/openpower-pels/hexdump.hpp b/extensions/openpower-pels/hexdump.hpp
new file mode 100644
index 0000000..bd26884
--- /dev/null
+++ b/extensions/openpower-pels/hexdump.hpp
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <ctype.h>
+#include <stdio.h>
+
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace openpower
+{
+namespace pels
+{
+
+/**
+ * @brief escape json - use it for PEL hex dumps.
+ * @param[in] std::string - the unescaped JSON as a string literal
+ * @return std::string - escaped JSON string literal
+ */
+std::string escapeJSON(const std::string& input);
+
+/**
+ * @brief get hex dump for PEL section in json format.
+ * @param[in] const void* - Raw PEL data
+ * @param[i] size_t - size of Raw PEL
+ * @return char * - the Hex dump
+ */
+char* dumpHex(const void* data, size_t size);
+
+} // namespace pels
+} // namespace openpower
diff --git a/extensions/openpower-pels/openpower-pels.mk b/extensions/openpower-pels/openpower-pels.mk
index 5099168..7690af4 100644
--- a/extensions/openpower-pels/openpower-pels.mk
+++ b/extensions/openpower-pels/openpower-pels.mk
@@ -8,6 +8,7 @@
extensions/openpower-pels/failing_mtms.cpp \
extensions/openpower-pels/fru_identity.cpp \
extensions/openpower-pels/generic.cpp \
+ extensions/openpower-pels/hexdump.cpp \
extensions/openpower-pels/log_id.cpp \
extensions/openpower-pels/manager.cpp \
extensions/openpower-pels/mru.cpp \
@@ -27,3 +28,47 @@
registrydir = $(datadir)/phosphor-logging/pels/
registry_DATA = extensions/openpower-pels/registry/message_registry.json
+
+bin_PROGRAMS += peltool
+
+peltool_SOURCES = extensions/openpower-pels/tools/peltool.cpp
+
+peltool_LDADD = \
+ extensions/openpower-pels/ascii_string.o \
+ extensions/openpower-pels/bcd_time.o \
+ extensions/openpower-pels/callout.o \
+ extensions/openpower-pels/callouts.o \
+ extensions/openpower-pels/failing_mtms.o \
+ extensions/openpower-pels/fru_identity.o \
+ extensions/openpower-pels/generic.o \
+ extensions/openpower-pels/hexdump.o \
+ extensions/openpower-pels/log_id.o \
+ extensions/openpower-pels/mru.o \
+ extensions/openpower-pels/mtms.o \
+ extensions/openpower-pels/paths.o \
+ extensions/openpower-pels/pce_identity.o \
+ extensions/openpower-pels/pel.o \
+ extensions/openpower-pels/pel_values.o \
+ extensions/openpower-pels/private_header.o \
+ extensions/openpower-pels/registry.o \
+ extensions/openpower-pels/repository.o \
+ extensions/openpower-pels/src.o \
+ extensions/openpower-pels/section_factory.o \
+ extensions/openpower-pels/severity.o \
+ extensions/openpower-pels/user_data.o \
+ extensions/openpower-pels/user_header.o
+
+
+peltool_LDFLAGS = \
+ $(SYSTEMD_LIBS) \
+ $(PHOSPHOR_LOGGING_LIBS) \
+ $(SDBUSPLUS_LIBS) \
+ $(PHOSPHOR_DBUS_INTERFACES_LIBS) \
+ $(SDEVENTPLUS_LIBS) \
+ -lstdc++fs
+
+peltool_CXXFLAGS = \
+ $(SYSTEMD_CFLAGS) \
+ $(SDBUSPLUS_CFLAGS) \
+ $(SDEVENTPLUS_CFLAGS) \
+ $(PHOSPHOR_DBUS_INTERFACES_CFLAGS)
diff --git a/extensions/openpower-pels/pel.cpp b/extensions/openpower-pels/pel.cpp
index 29d86d5..c4156a8 100644
--- a/extensions/openpower-pels/pel.cpp
+++ b/extensions/openpower-pels/pel.cpp
@@ -2,12 +2,15 @@
#include "bcd_time.hpp"
#include "failing_mtms.hpp"
+#include "hexdump.hpp"
#include "log_id.hpp"
+#include "pel_values.hpp"
#include "section_factory.hpp"
#include "src.hpp"
#include "stream.hpp"
#include "user_data_formats.hpp"
+#include <iostream>
#include <phosphor-logging/log.hpp>
namespace openpower
@@ -15,6 +18,7 @@
namespace pels
{
namespace message = openpower::pels::message;
+namespace pv = openpower::pels::pel_values;
PEL::PEL(const message::Entry& entry, uint32_t obmcLogID, uint64_t timestamp,
phosphor::logging::Entry::Level severity,
@@ -171,5 +175,45 @@
}
} // namespace util
+void PEL::printSectionInJSON(Section& section, std::string& buf) const
+{
+ char tmpB[5];
+ if (section.valid())
+ {
+ uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
+ static_cast<uint8_t>(section.header().id)};
+ sprintf(tmpB, "%c%c", id[0], id[1]);
+ std::string sectionID(tmpB);
+ std::string sectionName = pv::sectionTitles.count(sectionID)
+ ? pv::sectionTitles.at(sectionID)
+ : "Unknown Section";
+ buf += "\n\"" + sectionName + "\":[\n ";
+ std::vector<uint8_t> data;
+ Stream s{data};
+ section.flatten(s);
+ std::string dstr = dumpHex(std::data(data), data.size());
+ buf += dstr + "\n],\n";
+ }
+ else
+ {
+ buf += "\n\"Invalid Section \":[\n invalid \n],\n";
+ }
+}
+
+void PEL::toJSON()
+{
+ std::string buf = "{";
+ printSectionInJSON(*(_ph.get()), buf);
+ printSectionInJSON(*(_uh.get()), buf);
+ for (auto& section : this->optionalSections())
+ {
+ printSectionInJSON(*(section.get()), buf);
+ }
+ buf += "}";
+ std::size_t found = buf.rfind(",");
+ if (found != std::string::npos)
+ buf.replace(found, 1, "");
+ std::cout << buf << std::endl;
+}
} // namespace pels
} // namespace openpower
diff --git a/extensions/openpower-pels/pel.hpp b/extensions/openpower-pels/pel.hpp
index 3d1318f..3498ae6 100644
--- a/extensions/openpower-pels/pel.hpp
+++ b/extensions/openpower-pels/pel.hpp
@@ -214,6 +214,11 @@
*/
void assignID();
+ /**
+ * @brief Output a PEL in JSON.
+ */
+ void toJSON();
+
private:
/**
* @brief Builds the section objects from a PEL data buffer
@@ -248,6 +253,13 @@
* @brief Holds all sections by the PH and UH.
*/
std::vector<std::unique_ptr<Section>> _optionalSections;
+
+ /**
+ * @brief helper function for printing PELs.
+ * @param[in] Section& - section object reference
+ * @param[in] std::string - PEL string
+ */
+ void printSectionInJSON(Section& section, std::string& buf) const;
};
namespace util
diff --git a/extensions/openpower-pels/pel_values.cpp b/extensions/openpower-pels/pel_values.cpp
index a3127fb..0cf2a1c 100644
--- a/extensions/openpower-pels/pel_values.cpp
+++ b/extensions/openpower-pels/pel_values.cpp
@@ -190,7 +190,31 @@
});
}
-} // namespace pel_values
+/**
+ * @brief Map for section IDs
+ */
+const std::map<std::string, std::string> sectionTitles = {
+ {"PH", "Private Header"},
+ {"UH", "User Header"},
+ {"PS", "Primary SRC"},
+ {"SS", "Secondary SRC"},
+ {"EH", "Extended User Header"},
+ {"MT", "Failing MTMS"},
+ {"DH", "Dump Location"},
+ {"SW", "Firmware Error"},
+ {"LP", "Impacted Part"},
+ {"LR", "Logical Resource"},
+ {"HM", "HMC ID"},
+ {"EP", "EPOW"},
+ {"IE", "IO Event"},
+ {"MI", "MFG Info"},
+ {"CH", "Call Home"},
+ {"UD", "User Data"},
+ {"EI", "Env Info"},
+ {"ED", "Extended User Data"},
+};
+
+} // namespace pel_values
} // namespace pels
} // namespace openpower
diff --git a/extensions/openpower-pels/pel_values.hpp b/extensions/openpower-pels/pel_values.hpp
index 6092f62..49aa374 100644
--- a/extensions/openpower-pels/pel_values.hpp
+++ b/extensions/openpower-pels/pel_values.hpp
@@ -1,5 +1,6 @@
#pragma once
+#include <map>
#include <string>
#include <tuple>
#include <vector>
@@ -76,6 +77,11 @@
*/
extern const PELValues calloutPriorityValues;
+/**
+ * @brief Map for section IDs
+ */
+extern const std::map<std::string, std::string> sectionTitles;
+
} // namespace pel_values
} // namespace pels
} // namespace openpower
diff --git a/extensions/openpower-pels/tools/peltool.cpp b/extensions/openpower-pels/tools/peltool.cpp
new file mode 100644
index 0000000..f682a42
--- /dev/null
+++ b/extensions/openpower-pels/tools/peltool.cpp
@@ -0,0 +1,64 @@
+#include "../pel.hpp"
+
+#include <CLI/CLI.hpp>
+#include <iostream>
+#include <string>
+
+using namespace phosphor::logging;
+using namespace openpower::pels;
+
+/**
+ * @brief get data form raw PEL file.
+ * @param[in] std::string Name of file with raw PEL
+ * @return std::vector<uint8_t> char vector read from raw PEL file.
+ */
+std::vector<uint8_t> getFileData(std::string name)
+{
+ std::ifstream file(name, std::ifstream::in);
+ if (file.good())
+ {
+ std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
+ std::istreambuf_iterator<char>()};
+ return data;
+ }
+ else
+ {
+ printf("Can't open raw PEL file");
+ return {};
+ }
+}
+
+static void exitWithError(const std::string& help, const char* err)
+{
+ std::cerr << "ERROR: " << err << std::endl << help << std::endl;
+ exit(-1);
+}
+
+int main(int argc, char** argv)
+{
+ CLI::App app{"OpenBMC PEL Tool"};
+ std::string fileName;
+ app.add_option("-f,--file", fileName, "Raw PEL File");
+ CLI11_PARSE(app, argc, argv);
+
+ if (!fileName.empty())
+ {
+ std::vector<uint8_t> data = getFileData(fileName);
+ if (!data.empty())
+ {
+ PEL pel{data};
+ pel.toJSON();
+ }
+ else
+ {
+ exitWithError(app.help("", CLI::AppFormatMode::All),
+ "Raw PEL file can't be read.");
+ }
+ }
+ else
+ {
+ exitWithError(app.help("", CLI::AppFormatMode::All),
+ "Raw PEL file path not specified.");
+ }
+ return 0;
+}