Support for callout list FFDC

The FFDC contains relevent fields to a callout that otherwise would not
be displayed in the callout user data section.

Signed-off-by: Zane Shelley <zshelle@us.ibm.com>
Change-Id: Iadb71587b7219c4d352fa583ddd86f290de4a747
diff --git a/analyzer/create_pel.cpp b/analyzer/create_pel.cpp
index 558af52..f1c245f 100644
--- a/analyzer/create_pel.cpp
+++ b/analyzer/create_pel.cpp
@@ -27,6 +27,7 @@
 {
     FFDC_SIGNATURES    = 0x01,
     FFDC_REGISTER_DUMP = 0x02,
+    FFDC_CALLOUT_FFDC  = 0x03,
 
     // For the callout section, the value of '0xCA' is required per the
     // phosphor-logging openpower-pel extention spec.
@@ -94,6 +95,20 @@
 
 //------------------------------------------------------------------------------
 
+void __addCalloutFFDC(const ServiceData& i_servData,
+                      std::vector<util::FFDCFile>& io_userDataFiles)
+{
+    // Create a new entry for the user data section containing the FFDC.
+    io_userDataFiles.emplace_back(util::FFDCFormat::Custom, FFDC_CALLOUT_FFDC,
+                                  FFDC_VERSION1);
+
+    // Use a file stream to write the JSON to file.
+    std::ofstream o{io_userDataFiles.back().getPath()};
+    o << i_servData.getCalloutFFDC();
+}
+
+//------------------------------------------------------------------------------
+
 void __captureSignatureList(const libhei::IsolationData& i_isoData,
                             std::vector<util::FFDCFile>& io_userDataFiles)
 {
@@ -264,6 +279,9 @@
     // Add the list of callouts to the PEL.
     __addCalloutList(i_servData, userDataFiles);
 
+    // Add the callout FFDC to the PEL.
+    __addCalloutFFDC(i_servData, userDataFiles);
+
     // Capture the complete signature list.
     __captureSignatureList(i_isoData, userDataFiles);
 
diff --git a/analyzer/resolution.cpp b/analyzer/resolution.cpp
index fe407b6..a20be83 100644
--- a/analyzer/resolution.cpp
+++ b/analyzer/resolution.cpp
@@ -5,6 +5,8 @@
 namespace analyzer
 {
 
+//------------------------------------------------------------------------------
+
 void HardwareCalloutResolution::resolve(ServiceData& io_sd) const
 {
     // Get the chip target from the root cause signature.
@@ -34,7 +36,15 @@
     io_sd.addCallout(callout);
 
     // Add the guard info to the service data.
-    io_sd.addGuard(entityPath, iv_guard);
+    Guard guard = io_sd.addGuard(entityPath, iv_guard);
+
+    // Add the callout FFDC to the service data.
+    nlohmann::json ffdc;
+    ffdc["Callout Type"] = "Hardware Callout";
+    ffdc["Target"]       = entityPath;
+    ffdc["Priority"]     = iv_priority.getRegistryString();
+    ffdc["Guard Type"]   = guard.getString();
+    io_sd.addCalloutFFDC(ffdc);
 }
 
 //------------------------------------------------------------------------------
@@ -46,6 +56,13 @@
     callout["Procedure"] = iv_procedure.getString();
     callout["Priority"]  = iv_priority.getUserDataString();
     io_sd.addCallout(callout);
+
+    // Add the callout FFDC to the service data.
+    nlohmann::json ffdc;
+    ffdc["Callout Type"] = "Procedure Callout";
+    ffdc["Procedure"]    = iv_procedure.getString();
+    ffdc["Priority"]     = iv_priority.getRegistryString();
+    io_sd.addCalloutFFDC(ffdc);
 }
 
 //------------------------------------------------------------------------------
diff --git a/analyzer/service_data.hpp b/analyzer/service_data.hpp
index 3664550..ce9993e 100644
--- a/analyzer/service_data.hpp
+++ b/analyzer/service_data.hpp
@@ -45,6 +45,10 @@
     /** The list of callouts that will be added to a PEL. */
     nlohmann::json iv_calloutList = nlohmann::json::array();
 
+    /** FFDC for callouts that would otherwise not be available in the
+     *  callout list (unit paths, bus types, etc.). */
+    nlohmann::json iv_calloutFFDC = nlohmann::json::array();
+
     /** The list of hardware guard requests. Some information will be added to
      *  the PEL, but the actual guard record will be created after submitting
      *  the PEL. */
@@ -74,11 +78,22 @@
     }
 
     /**
+     * @brief Add FFDC for a callout that would otherwise not be available in
+     *        the callout list (unit paths, bus types, etc.).
+     * @param The JSON object for this callout.
+     */
+    void addCalloutFFDC(const nlohmann::json& i_ffdc)
+    {
+        iv_calloutFFDC.push_back(i_ffdc);
+    }
+
+    /**
      * @brief  Add a guard request to the guard list.
      * @param  i_path  Entity path for the target part.
      * @param  i_guard True, if the part should be guarded. False, otherwise.
+     * @return A reference to the object just added to the guard list.
      */
-    void addGuard(const std::string& i_path, bool i_guard)
+    const Guard& addGuard(const std::string& i_path, bool i_guard)
     {
         Guard::Type guardType = Guard::Type::NONE;
         if (i_guard)
@@ -89,7 +104,7 @@
                 queryCheckstop() ? Guard::Type::FATAL : Guard::Type::NON_FATAL;
         }
 
-        iv_guardList.emplace_back(i_path, guardType);
+        return iv_guardList.emplace_back(i_path, guardType);
     }
 
     /** @brief Accessor to iv_calloutList. */
@@ -98,6 +113,12 @@
         return iv_calloutList;
     }
 
+    /** @brief Accessor to iv_calloutFFDC. */
+    const nlohmann::json& getCalloutFFDC() const
+    {
+        return iv_calloutFFDC;
+    }
+
     /** @brief Accessor to iv_guardList. */
     const std::vector<Guard>& getGuardList() const
     {