Add all signatures to PEL FFDC

Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
Change-Id: I5628c9ec7da34c7d9e023ac2e227de72b90626a9
diff --git a/analyzer/create_pel.cpp b/analyzer/create_pel.cpp
index 2871da6..ba6b349 100644
--- a/analyzer/create_pel.cpp
+++ b/analyzer/create_pel.cpp
@@ -9,11 +9,33 @@
 #include <xyz/openbmc_project/Logging/Create/server.hpp>
 #include <xyz/openbmc_project/Logging/Entry/server.hpp>
 
+#include <fstream>
+#include <memory>
+
 namespace LogSvr = sdbusplus::xyz::openbmc_project::Logging::server;
 
 namespace analyzer
 {
 
+//------------------------------------------------------------------------------
+
+enum FfdcSubType_t : uint8_t
+{
+    FFDC_SIGNATURES   = 0x01,
+    FFDC_CAPTURE_DATA = 0x02,
+
+    // For the callout section, the value of '0xCA' is required per the
+    // phosphor-logging openpower-pel extention spec.
+    FFDC_CALLOUTS = 0xCA,
+};
+
+enum FfdcVersion_t : uint8_t
+{
+    FFDC_VERSION1 = 0x01,
+};
+
+//------------------------------------------------------------------------------
+
 bool __isCheckstop(const libhei::IsolationData& i_isoData)
 {
     // Look for any signature with a system checkstop attention.
@@ -27,28 +49,37 @@
 
 //------------------------------------------------------------------------------
 
-void __setSrc(const libhei::Signature& i_rootCause,
-              std::map<std::string, std::string>& io_logData)
+void __getSrc(const libhei::Signature& i_signature, uint32_t& o_word6,
+              uint32_t& o_word7, uint32_t& o_word8)
 {
     // [ 0:15] chip model
     // [16:23] reserved space in chip ID
     // [24:31] chip EC level
-    uint32_t word6 = i_rootCause.getChip().getType();
+    o_word6 = i_signature.getChip().getType();
 
     // [ 0:15] chip position
     // [16:23] unused
     // [24:31] signature attention type
-    auto pos  = util::pdbg::getChipPos(i_rootCause.getChip());
-    auto attn = i_rootCause.getAttnType();
+    auto pos  = util::pdbg::getChipPos(i_signature.getChip());
+    auto attn = i_signature.getAttnType();
 
-    uint32_t word7 = (pos & 0xffff) << 16 | (attn & 0xff);
+    o_word7 = (pos & 0xffff) << 16 | (attn & 0xff);
 
     // [ 0:15] signature ID
     // [16:23] signature instance
     // [24:31] signature bit position
-    uint32_t word8 = i_rootCause.toUint32();
+    o_word8 = i_signature.toUint32();
 
     // Word 9 is currently unused
+}
+
+//------------------------------------------------------------------------------
+
+void __setSrc(const libhei::Signature& i_rootCause,
+              std::map<std::string, std::string>& io_logData)
+{
+    uint32_t word6 = 0, word7 = 0, word8 = 0;
+    __getSrc(i_rootCause, word6, word7, word8);
 
     io_logData["SRC6"] = std::to_string(word6);
     io_logData["SRC7"] = std::to_string(word7);
@@ -60,8 +91,63 @@
 void __captureSignatureList(const libhei::IsolationData& i_isoData,
                             std::vector<util::FFDCFile>& io_userDataFiles)
 {
-    // TODO: Create a user data section that contains the complete list of
-    //       signatures found during isolation.
+    // Create a new entry for this user data section regardless if there are any
+    // signatures in the list.
+    io_userDataFiles.emplace_back(util::FFDCFormat::Custom, FFDC_SIGNATURES,
+                                  FFDC_VERSION1);
+
+    auto list = i_isoData.getSignatureList();
+
+    // The first entry in the buffer will be the number of signatures in the
+    // list.
+    uint32_t numSigs  = list.size();
+    size_t sz_numSigs = sizeof(numSigs);
+
+    // Each signature in the buffer use the same format as the SRC.
+    uint32_t word6 = 0, word7 = 0, word8 = 0;
+    size_t sz_word = sizeof(uint32_t);
+
+    // Allocate the buffer.
+    size_t sz_buffer = sz_numSigs + (numSigs * (3 * sz_word));
+    std::unique_ptr<char[]> buffer{new char[sz_buffer]};
+
+    // Insert the number of signatures.
+    numSigs = htobe32(numSigs);
+    memcpy(&buffer[0], &numSigs, sz_numSigs);
+
+    // Insert each signature.
+    size_t idx = sz_numSigs;
+    for (const auto& sig : list)
+    {
+        __getSrc(sig, word6, word7, word8);
+
+        word6 = htobe32(word6);
+        word7 = htobe32(word7);
+        word8 = htobe32(word8);
+
+        // clang-format off
+        memcpy(&buffer[idx], &word6, sz_word); idx += sz_word;
+        memcpy(&buffer[idx], &word7, sz_word); idx += sz_word;
+        memcpy(&buffer[idx], &word8, sz_word); idx += sz_word;
+        // clang-format on
+    }
+
+    // Open the file for writing.
+    auto path = io_userDataFiles.back().getPath();
+    std::ofstream file{path, std::ios::binary};
+    if (!file.good())
+    {
+        trace::err("Unable to open file: %s", path.string().c_str());
+    }
+    else
+    {
+        // Write the buffer to file.
+        file.write(buffer.get(), sz_buffer);
+        if (!file.good())
+        {
+            trace::err("Unable to write file: %s", path.string().c_str());
+        }
+    }
 }
 
 //------------------------------------------------------------------------------