blob: 48dff518b6e1a4475abeec22c2de8bdec1bd93a2 [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinlercb6b0592019-07-16 15:58:51 -050016#include "pel.hpp"
17
18#include "bcd_time.hpp"
Matt Spinler386a61e2020-08-13 15:51:12 -050019#include "extended_user_data.hpp"
Matt Spinlerc63e2e82019-12-02 15:50:12 -060020#include "extended_user_header.hpp"
Matt Spinleraa659472019-10-23 09:26:48 -050021#include "failing_mtms.hpp"
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +080022#include "json_utils.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050023#include "log_id.hpp"
Matt Spinlerf1e85e22019-11-01 11:31:31 -050024#include "pel_rules.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050025#include "pel_values.hpp"
Matt Spinler131870c2019-09-25 13:29:04 -050026#include "section_factory.hpp"
Matt Spinlerbd716f02019-10-15 10:54:11 -050027#include "src.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050028#include "stream.hpp"
Matt Spinlerafa857c2019-10-24 13:03:46 -050029#include "user_data_formats.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050030
Matt Spinler5b289b22020-03-26 14:27:19 -050031#include <sys/stat.h>
32#include <unistd.h>
33
Aatir186ce8c2019-10-20 15:13:39 -050034#include <iostream>
Matt Spinler07eefc52019-09-26 11:18:26 -050035#include <phosphor-logging/log.hpp>
36
Matt Spinlercb6b0592019-07-16 15:58:51 -050037namespace openpower
38{
39namespace pels
40{
Matt Spinlerb8323632019-09-20 15:11:04 -050041namespace message = openpower::pels::message;
Aatir186ce8c2019-10-20 15:13:39 -050042namespace pv = openpower::pels::pel_values;
Matt Spinler4bfc9082020-03-24 15:05:54 -050043using namespace phosphor::logging;
Matt Spinlerb8323632019-09-20 15:11:04 -050044
Matt Spinler677381b2020-01-23 10:04:29 -060045constexpr auto unknownValue = "Unknown";
Matt Spinler5a90a952020-08-27 09:39:03 -050046constexpr uint8_t jsonCalloutSubtype = 0xCA;
Matt Spinler677381b2020-01-23 10:04:29 -060047
Matt Spinler4bfc9082020-03-24 15:05:54 -050048PEL::PEL(const message::Entry& regEntry, uint32_t obmcLogID, uint64_t timestamp,
Matt Spinlerbd716f02019-10-15 10:54:11 -050049 phosphor::logging::Entry::Level severity,
Matt Spinler56ad2a02020-03-26 14:00:52 -050050 const AdditionalData& additionalData, const PelFFDC& ffdcFiles,
Matt Spinleraa659472019-10-23 09:26:48 -050051 const DataInterfaceBase& dataIface)
Matt Spinlerb8323632019-09-20 15:11:04 -050052{
Matt Spinler85f61a62020-06-03 16:28:55 -050053 std::map<std::string, std::vector<std::string>> debugData;
Matt Spinler5a90a952020-08-27 09:39:03 -050054 nlohmann::json callouts;
Matt Spinler85f61a62020-06-03 16:28:55 -050055
Matt Spinler4bfc9082020-03-24 15:05:54 -050056 _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID,
Matt Spinlerb8323632019-09-20 15:11:04 -050057 timestamp);
Vijay Lobo6b3f3452021-04-15 23:04:42 -050058 _uh = std::make_unique<UserHeader>(regEntry, severity, additionalData,
59 dataIface);
Matt Spinlerb8323632019-09-20 15:11:04 -050060
Matt Spinler5a90a952020-08-27 09:39:03 -050061 // Extract any callouts embedded in an FFDC file.
62 if (!ffdcFiles.empty())
63 {
64 try
65 {
66 callouts = getCalloutJSON(ffdcFiles);
67 }
68 catch (const std::exception& e)
69 {
70 debugData.emplace("FFDC file JSON callouts error",
71 std::vector<std::string>{e.what()});
72 }
73 }
74
75 auto src =
76 std::make_unique<SRC>(regEntry, additionalData, callouts, dataIface);
77
Matt Spinler85f61a62020-06-03 16:28:55 -050078 if (!src->getDebugData().empty())
79 {
80 // Something didn't go as planned
81 debugData.emplace("SRC", src->getDebugData());
82 }
Matt Spinlerc63e2e82019-12-02 15:50:12 -060083
Matt Spinler4bfc9082020-03-24 15:05:54 -050084 auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src);
Matt Spinlerc63e2e82019-12-02 15:50:12 -060085
Matt Spinlerbd716f02019-10-15 10:54:11 -050086 _optionalSections.push_back(std::move(src));
Matt Spinlerc63e2e82019-12-02 15:50:12 -060087 _optionalSections.push_back(std::move(euh));
Matt Spinlerb8323632019-09-20 15:11:04 -050088
Matt Spinleraa659472019-10-23 09:26:48 -050089 auto mtms = std::make_unique<FailingMTMS>(dataIface);
90 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -050091
Matt Spinler4dcd3f42020-01-22 14:55:07 -060092 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
Matt Spinler85f61a62020-06-03 16:28:55 -050093 addUserDataSection(std::move(ud));
Matt Spinler4dcd3f42020-01-22 14:55:07 -060094
Matt Spinler9b7e94f2020-03-24 15:44:41 -050095 // Create a UserData section from AdditionalData.
Matt Spinlerafa857c2019-10-24 13:03:46 -050096 if (!additionalData.empty())
97 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -060098 ud = util::makeADUserDataSection(additionalData);
Matt Spinler85f61a62020-06-03 16:28:55 -050099 addUserDataSection(std::move(ud));
Matt Spinlerafa857c2019-10-24 13:03:46 -0500100 }
101
Matt Spinler56ad2a02020-03-26 14:00:52 -0500102 // Add any FFDC files into UserData sections
103 for (const auto& file : ffdcFiles)
104 {
105 ud = util::makeFFDCuserDataSection(regEntry.componentID, file);
106 if (!ud)
107 {
Matt Spinler85f61a62020-06-03 16:28:55 -0500108 // Add this error into the debug data UserData section
109 std::ostringstream msg;
110 msg << "Could not make PEL FFDC UserData section from file"
111 << std::hex << regEntry.componentID << " " << file.subType
112 << " " << file.version;
113 if (debugData.count("FFDC File"))
114 {
115 debugData.at("FFDC File").push_back(msg.str());
116 }
117 else
118 {
119 debugData.emplace("FFDC File",
120 std::vector<std::string>{msg.str()});
121 }
122
Matt Spinler56ad2a02020-03-26 14:00:52 -0500123 continue;
124 }
125
Matt Spinler85f61a62020-06-03 16:28:55 -0500126 addUserDataSection(std::move(ud));
127 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500128
Matt Spinler85f61a62020-06-03 16:28:55 -0500129 // Store in the PEL any important debug data created while
130 // building the PEL sections.
131 if (!debugData.empty())
132 {
133 nlohmann::json data;
134 data["PEL Internal Debug Data"] = debugData;
135 ud = util::makeJSONUserDataSection(data);
136
137 addUserDataSection(std::move(ud));
138
139 // Also put in the journal for debug
140 for (const auto& [name, data] : debugData)
141 {
142 for (const auto& message : data)
143 {
144 std::string entry = name + ": " + message;
145 log<level::INFO>(entry.c_str());
Matt Spinler56ad2a02020-03-26 14:00:52 -0500146 }
147 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500148 }
149
Matt Spinler97d19b42019-10-29 11:34:03 -0500150 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500151
152 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -0500153}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500154
Matt Spinler07eefc52019-09-26 11:18:26 -0500155PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500156{
157}
158
Matt Spinler07eefc52019-09-26 11:18:26 -0500159PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500160{
Matt Spinler07eefc52019-09-26 11:18:26 -0500161 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500162}
163
Matt Spinler07eefc52019-09-26 11:18:26 -0500164void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500165{
Matt Spinler07eefc52019-09-26 11:18:26 -0500166 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -0500167 _ph = std::make_unique<PrivateHeader>(pelData);
168 if (obmcLogID != 0)
169 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500170 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500171 }
172
173 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -0500174
175 // Use the section factory to create the rest of the objects
176 for (size_t i = 2; i < _ph->sectionCount(); i++)
177 {
178 auto section = section_factory::create(pelData);
179 _optionalSections.push_back(std::move(section));
180 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500181}
182
183bool PEL::valid() const
184{
185 bool valid = _ph->valid();
186
187 if (valid)
188 {
189 valid = _uh->valid();
190 }
191
Matt Spinler131870c2019-09-25 13:29:04 -0500192 if (valid)
193 {
194 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
195 [](const auto& section) { return section->valid(); }))
196 {
197 valid = false;
198 }
199 }
200
Matt Spinlercb6b0592019-07-16 15:58:51 -0500201 return valid;
202}
203
204void PEL::setCommitTime()
205{
206 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500207 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500208}
209
210void PEL::assignID()
211{
Matt Spinler97d19b42019-10-29 11:34:03 -0500212 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500213}
214
Matt Spinler06885452019-11-06 10:35:42 -0600215void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500216{
217 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500218
Matt Spinler07eefc52019-09-26 11:18:26 -0500219 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500220 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500221 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500222 }
223
Matt Spinler07eefc52019-09-26 11:18:26 -0500224 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500225 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500226
227 for (auto& section : _optionalSections)
228 {
229 section->flatten(pelData);
230 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500231}
232
Matt Spinler06885452019-11-06 10:35:42 -0600233std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500234{
Matt Spinler07eefc52019-09-26 11:18:26 -0500235 std::vector<uint8_t> pelData;
236 flatten(pelData);
237 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500238}
239
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600240size_t PEL::size() const
241{
242 size_t size = 0;
243
244 if (_ph)
245 {
246 size += _ph->header().size;
247 }
248
249 if (_uh)
250 {
251 size += _uh->header().size;
252 }
253
254 for (const auto& section : _optionalSections)
255 {
256 size += section->header().size;
257 }
258
259 return size;
260}
261
Matt Spinlerbd716f02019-10-15 10:54:11 -0500262std::optional<SRC*> PEL::primarySRC() const
263{
264 auto src = std::find_if(
265 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
266 return section->header().id ==
267 static_cast<uint16_t>(SectionID::primarySRC);
268 });
269 if (src != _optionalSections.end())
270 {
271 return static_cast<SRC*>(src->get());
272 }
273
274 return std::nullopt;
275}
276
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500277void PEL::checkRulesAndFix()
278{
Matt Spinler1f93c592020-09-10 10:43:08 -0500279 // Only fix if the action flags are at their default value which
280 // means they weren't specified in the registry. Otherwise
281 // assume the user knows what they are doing.
282 if (_uh->actionFlags() == actionFlagsDefault)
283 {
284 auto [actionFlags, eventType] =
285 pel_rules::check(0, _uh->eventType(), _uh->severity());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500286
Matt Spinler1f93c592020-09-10 10:43:08 -0500287 _uh->setActionFlags(actionFlags);
288 _uh->setEventType(eventType);
289 }
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500290}
291
Matt Spinleracb7c102020-01-10 13:49:22 -0600292void PEL::printSectionInJSON(const Section& section, std::string& buf,
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800293 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800294 message::Registry& registry,
295 const std::vector<std::string>& plugins,
296 uint8_t creatorID) const
Aatir186ce8c2019-10-20 15:13:39 -0500297{
298 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500299 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
300 static_cast<uint8_t>(section.header().id)};
301 sprintf(tmpB, "%c%c", id[0], id[1]);
302 std::string sectionID(tmpB);
303 std::string sectionName = pv::sectionTitles.count(sectionID)
304 ? pv::sectionTitles.at(sectionID)
305 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600306
307 // Add a count if there are multiple of this type of section
308 auto count = pluralSections.find(section.header().id);
309 if (count != pluralSections.end())
310 {
311 sectionName += " " + std::to_string(count->second);
312 count->second++;
313 }
314
Aatir186ce8c2019-10-20 15:13:39 -0500315 if (section.valid())
316 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800317 std::optional<std::string> json;
318 if (sectionID == "PS" || sectionID == "SS")
319 {
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800320 json = section.getJSON(registry, plugins, creatorID);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800321 }
Matt Spinler386a61e2020-08-13 15:51:12 -0500322 else if ((sectionID == "UD") || (sectionID == "ED"))
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800323 {
Harisuddin Mohamed Isa3fdcd4e2020-08-26 11:56:42 +0800324 json = section.getJSON(creatorID, plugins);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800325 }
326 else
327 {
328 json = section.getJSON();
329 }
Matt Spinler4220a152020-03-26 10:18:09 -0500330
331 buf += "\"" + sectionName + "\": {\n";
332
Aatir Manzurad0e0472019-10-07 13:18:37 -0500333 if (json)
334 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800335 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500336 }
337 else
338 {
Matt Spinler4220a152020-03-26 10:18:09 -0500339 jsonInsert(buf, pv::sectionVer,
340 getNumberString("%d", section.header().version), 1);
341 jsonInsert(buf, pv::subSection,
342 getNumberString("%d", section.header().subType), 1);
343 jsonInsert(buf, pv::createdBy,
344 getNumberString("0x%X", section.header().componentID),
345 1);
346
Aatir Manzurad0e0472019-10-07 13:18:37 -0500347 std::vector<uint8_t> data;
348 Stream s{data};
349 section.flatten(s);
Matt Spinler4220a152020-03-26 10:18:09 -0500350 std::string dstr =
351 dumpHex(std::data(data) + SectionHeader::flattenedSize(),
Harisuddin Mohamed Isa097ad122020-06-11 21:19:41 +0800352 data.size() - SectionHeader::flattenedSize(), 2);
Matt Spinler4220a152020-03-26 10:18:09 -0500353 std::string jsonIndent(indentLevel, 0x20);
354 buf += jsonIndent + "\"Data\": [\n";
355 buf += dstr;
356 buf += jsonIndent + "]\n";
357 buf += "},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500358 }
Aatir186ce8c2019-10-20 15:13:39 -0500359 }
360 else
361 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800362 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500363 }
364}
365
Matt Spinleracb7c102020-01-10 13:49:22 -0600366std::map<uint16_t, size_t> PEL::getPluralSections() const
367{
368 std::map<uint16_t, size_t> sectionCounts;
369
370 for (const auto& section : optionalSections())
371 {
372 if (sectionCounts.find(section->header().id) == sectionCounts.end())
373 {
374 sectionCounts[section->header().id] = 1;
375 }
376 else
377 {
378 sectionCounts[section->header().id]++;
379 }
380 }
381
382 std::map<uint16_t, size_t> sections;
383 for (const auto& [id, count] : sectionCounts)
384 {
385 if (count > 1)
386 {
387 // Start with 0 here and printSectionInJSON()
388 // will increment it as it goes.
389 sections.emplace(id, 0);
390 }
391 }
392
393 return sections;
394}
395
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800396void PEL::toJSON(message::Registry& registry,
397 const std::vector<std::string>& plugins) const
Aatir186ce8c2019-10-20 15:13:39 -0500398{
Matt Spinleracb7c102020-01-10 13:49:22 -0600399 auto sections = getPluralSections();
400
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800401 std::string buf = "{\n";
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800402 printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins);
403 printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins);
Aatir186ce8c2019-10-20 15:13:39 -0500404 for (auto& section : this->optionalSections())
405 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800406 printSectionInJSON(*(section.get()), buf, sections, registry, plugins,
407 _ph->creatorID());
Aatir186ce8c2019-10-20 15:13:39 -0500408 }
409 buf += "}";
410 std::size_t found = buf.rfind(",");
411 if (found != std::string::npos)
412 buf.replace(found, 1, "");
413 std::cout << buf << std::endl;
414}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800415
Matt Spinler85f61a62020-06-03 16:28:55 -0500416bool PEL::addUserDataSection(std::unique_ptr<UserData> userData)
417{
418 if (size() + userData->header().size > _maxPELSize)
419 {
420 if (userData->shrink(_maxPELSize - size()))
421 {
422 _optionalSections.push_back(std::move(userData));
423 }
424 else
425 {
426 log<level::WARNING>(
427 "Could not shrink UserData section. Dropping",
428 entry("SECTION_SIZE=%d\n", userData->header().size),
429 entry("COMPONENT_ID=0x%02X", userData->header().componentID),
430 entry("SUBTYPE=0x%X", userData->header().subType),
431 entry("VERSION=0x%X", userData->header().version));
432 return false;
433 }
434 }
435 else
436 {
437 _optionalSections.push_back(std::move(userData));
438 }
439 return true;
440}
441
Matt Spinler5a90a952020-08-27 09:39:03 -0500442nlohmann::json PEL::getCalloutJSON(const PelFFDC& ffdcFiles)
443{
444 nlohmann::json callouts;
445
446 for (const auto& file : ffdcFiles)
447 {
448 if ((file.format == UserDataFormat::json) &&
449 (file.subType == jsonCalloutSubtype))
450 {
451 auto data = util::readFD(file.fd);
452 if (data.empty())
453 {
454 throw std::runtime_error{
455 "Could not get data from JSON callout file descriptor"};
456 }
457
458 std::string jsonString{data.begin(), data.begin() + data.size()};
459
460 callouts = nlohmann::json::parse(jsonString);
461 break;
462 }
463 }
464
465 return callouts;
466}
467
Andrew Geissler44fc3162020-07-09 09:21:31 -0500468bool PEL::isCalloutPresent() const
469{
470 auto pSRC = primarySRC();
471 if (!pSRC)
472 {
473 return false;
474 }
475
476 bool calloutPresent = false;
477 if ((*pSRC)->callouts())
478 {
479 for (auto& i : (*pSRC)->callouts()->callouts())
480 {
481 if (((*i).fruIdentity()))
482 {
483 auto& fruId = (*i).fruIdentity();
484 if ((*fruId).failingComponentType() != 0)
485 {
486 calloutPresent = true;
487 break;
488 }
489 }
490 }
491 }
492
493 return calloutPresent;
494}
495
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600496namespace util
497{
498
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600499std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
500{
501 auto jsonString = json.dump();
502 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
503
504 // Pad to a 4 byte boundary
505 while ((jsonData.size() % 4) != 0)
506 {
507 jsonData.push_back(0);
508 }
509
510 return std::make_unique<UserData>(
511 static_cast<uint16_t>(ComponentID::phosphorLogging),
512 static_cast<uint8_t>(UserDataFormat::json),
513 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
514}
515
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600516std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
517{
518 assert(!ad.empty());
519 nlohmann::json json;
520
521 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
522 if (ad.getValue("ESEL"))
523 {
524 auto newAD = ad;
525 newAD.remove("ESEL");
526 json = newAD.toJSON();
527 }
528 else
529 {
530 json = ad.toJSON();
531 }
532
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600533 return makeJSONUserDataSection(json);
534}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600535
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600536void addProcessNameToJSON(nlohmann::json& json,
537 const std::optional<std::string>& pid,
538 const DataInterfaceBase& dataIface)
539{
Matt Spinler677381b2020-01-23 10:04:29 -0600540 std::string name{unknownValue};
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600541
542 try
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600543 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600544 if (pid)
545 {
546 auto n = dataIface.getProcessName(*pid);
547 if (n)
548 {
549 name = *n;
550 }
551 }
552 }
553 catch (std::exception& e)
554 {
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600555 }
556
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600557 json["Process Name"] = std::move(name);
558}
559
Matt Spinler677381b2020-01-23 10:04:29 -0600560void addBMCFWVersionIDToJSON(nlohmann::json& json,
561 const DataInterfaceBase& dataIface)
562{
563 auto id = dataIface.getBMCFWVersionID();
564 if (id.empty())
565 {
566 id = unknownValue;
567 }
568
569 json["BMC Version ID"] = std::move(id);
570}
571
Matt Spinler4aa23a12020-02-03 15:05:09 -0600572std::string lastSegment(char separator, std::string data)
573{
574 auto pos = data.find_last_of(separator);
575 if (pos != std::string::npos)
576 {
577 data = data.substr(pos + 1);
578 }
579
580 return data;
581}
582
583void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
584{
585 json["BMCState"] = lastSegment('.', dataIface.getBMCState());
586 json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
587 json["HostState"] = lastSegment('.', dataIface.getHostState());
588}
589
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600590std::unique_ptr<UserData>
591 makeSysInfoUserDataSection(const AdditionalData& ad,
592 const DataInterfaceBase& dataIface)
593{
594 nlohmann::json json;
595
596 addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
Matt Spinler677381b2020-01-23 10:04:29 -0600597 addBMCFWVersionIDToJSON(json, dataIface);
Matt Spinler4aa23a12020-02-03 15:05:09 -0600598 addStatesToJSON(json, dataIface);
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600599
600 return makeJSONUserDataSection(json);
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600601}
602
Matt Spinler5b289b22020-03-26 14:27:19 -0500603std::vector<uint8_t> readFD(int fd)
604{
605 std::vector<uint8_t> data;
606
607 // Get the size
608 struct stat s;
609 int r = fstat(fd, &s);
610 if (r != 0)
611 {
612 auto e = errno;
613 log<level::ERR>("Could not get FFDC file size from FD",
614 entry("ERRNO=%d", e));
615 return data;
616 }
617
618 if (0 == s.st_size)
619 {
620 log<level::ERR>("FFDC file is empty");
621 return data;
622 }
623
624 data.resize(s.st_size);
625
626 // Make sure its at the beginning, as maybe another
627 // extension already used it.
628 r = lseek(fd, 0, SEEK_SET);
629 if (r == -1)
630 {
631 auto e = errno;
632 log<level::ERR>("Could not seek to beginning of FFDC file",
633 entry("ERRNO=%d", e));
634 return data;
635 }
636
637 r = read(fd, data.data(), s.st_size);
638 if (r == -1)
639 {
640 auto e = errno;
641 log<level::ERR>("Could not read FFDC file", entry("ERRNO=%d", e));
642 }
643 else if (r != s.st_size)
644 {
645 log<level::WARNING>("Could not read full FFDC file",
646 entry("FILE_SIZE=%d", s.st_size),
647 entry("SIZE_READ=%d", r));
648 }
649
650 return data;
651}
652
Matt Spinler56ad2a02020-03-26 14:00:52 -0500653std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
654 const PelFFDCfile& file)
655{
Matt Spinler5b289b22020-03-26 14:27:19 -0500656 auto data = readFD(file.fd);
657
658 if (data.empty())
659 {
660 return std::unique_ptr<UserData>();
661 }
662
663 // The data needs 4 Byte alignment, and save amount padded for the
664 // CBOR case.
665 uint32_t pad = 0;
666 while (data.size() % 4)
667 {
668 data.push_back(0);
669 pad++;
670 }
671
672 // For JSON, CBOR, and Text use our component ID, subType, and version,
673 // otherwise use the supplied ones.
674 uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging);
675 uint8_t subType{};
676 uint8_t version{};
677
678 switch (file.format)
679 {
680 case UserDataFormat::json:
681 subType = static_cast<uint8_t>(UserDataFormat::json);
682 version = static_cast<uint8_t>(UserDataFormatVersion::json);
683 break;
684 case UserDataFormat::cbor:
685 subType = static_cast<uint8_t>(UserDataFormat::cbor);
686 version = static_cast<uint8_t>(UserDataFormatVersion::cbor);
687
688 // The CBOR parser will fail on the extra pad bytes since they
689 // aren't CBOR. Add the amount we padded to the end and other
690 // code will remove it all before parsing.
691 {
692 data.resize(data.size() + 4);
693 Stream stream{data};
694 stream.offset(data.size() - 4);
695 stream << pad;
696 }
697
698 break;
699 case UserDataFormat::text:
700 subType = static_cast<uint8_t>(UserDataFormat::text);
701 version = static_cast<uint8_t>(UserDataFormatVersion::text);
702 break;
703 case UserDataFormat::custom:
704 default:
705 // Use the passed in values
706 compID = componentID;
707 subType = file.subType;
708 version = file.version;
709 break;
710 }
711
712 return std::make_unique<UserData>(compID, subType, version, data);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500713}
714
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600715} // namespace util
716
Matt Spinlercb6b0592019-07-16 15:58:51 -0500717} // namespace pels
718} // namespace openpower