blob: f66d98547560dc6d998652df59c16e5ddd8b1264 [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);
Matt Spinleraadccc82020-04-10 14:33:42 -050058 _uh = std::make_unique<UserHeader>(regEntry, severity, dataIface);
Matt Spinlerb8323632019-09-20 15:11:04 -050059
Matt Spinler5a90a952020-08-27 09:39:03 -050060 // Extract any callouts embedded in an FFDC file.
61 if (!ffdcFiles.empty())
62 {
63 try
64 {
65 callouts = getCalloutJSON(ffdcFiles);
66 }
67 catch (const std::exception& e)
68 {
69 debugData.emplace("FFDC file JSON callouts error",
70 std::vector<std::string>{e.what()});
71 }
72 }
73
74 auto src =
75 std::make_unique<SRC>(regEntry, additionalData, callouts, dataIface);
76
Matt Spinler85f61a62020-06-03 16:28:55 -050077 if (!src->getDebugData().empty())
78 {
79 // Something didn't go as planned
80 debugData.emplace("SRC", src->getDebugData());
81 }
Matt Spinlerc63e2e82019-12-02 15:50:12 -060082
Matt Spinler4bfc9082020-03-24 15:05:54 -050083 auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src);
Matt Spinlerc63e2e82019-12-02 15:50:12 -060084
Matt Spinlerbd716f02019-10-15 10:54:11 -050085 _optionalSections.push_back(std::move(src));
Matt Spinlerc63e2e82019-12-02 15:50:12 -060086 _optionalSections.push_back(std::move(euh));
Matt Spinlerb8323632019-09-20 15:11:04 -050087
Matt Spinleraa659472019-10-23 09:26:48 -050088 auto mtms = std::make_unique<FailingMTMS>(dataIface);
89 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -050090
Matt Spinler4dcd3f42020-01-22 14:55:07 -060091 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
Matt Spinler85f61a62020-06-03 16:28:55 -050092 addUserDataSection(std::move(ud));
Matt Spinler4dcd3f42020-01-22 14:55:07 -060093
Matt Spinler9b7e94f2020-03-24 15:44:41 -050094 // Create a UserData section from AdditionalData.
Matt Spinlerafa857c2019-10-24 13:03:46 -050095 if (!additionalData.empty())
96 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -060097 ud = util::makeADUserDataSection(additionalData);
Matt Spinler85f61a62020-06-03 16:28:55 -050098 addUserDataSection(std::move(ud));
Matt Spinlerafa857c2019-10-24 13:03:46 -050099 }
100
Matt Spinler56ad2a02020-03-26 14:00:52 -0500101 // Add any FFDC files into UserData sections
102 for (const auto& file : ffdcFiles)
103 {
104 ud = util::makeFFDCuserDataSection(regEntry.componentID, file);
105 if (!ud)
106 {
Matt Spinler85f61a62020-06-03 16:28:55 -0500107 // Add this error into the debug data UserData section
108 std::ostringstream msg;
109 msg << "Could not make PEL FFDC UserData section from file"
110 << std::hex << regEntry.componentID << " " << file.subType
111 << " " << file.version;
112 if (debugData.count("FFDC File"))
113 {
114 debugData.at("FFDC File").push_back(msg.str());
115 }
116 else
117 {
118 debugData.emplace("FFDC File",
119 std::vector<std::string>{msg.str()});
120 }
121
Matt Spinler56ad2a02020-03-26 14:00:52 -0500122 continue;
123 }
124
Matt Spinler85f61a62020-06-03 16:28:55 -0500125 addUserDataSection(std::move(ud));
126 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500127
Matt Spinler85f61a62020-06-03 16:28:55 -0500128 // Store in the PEL any important debug data created while
129 // building the PEL sections.
130 if (!debugData.empty())
131 {
132 nlohmann::json data;
133 data["PEL Internal Debug Data"] = debugData;
134 ud = util::makeJSONUserDataSection(data);
135
136 addUserDataSection(std::move(ud));
137
138 // Also put in the journal for debug
139 for (const auto& [name, data] : debugData)
140 {
141 for (const auto& message : data)
142 {
143 std::string entry = name + ": " + message;
144 log<level::INFO>(entry.c_str());
Matt Spinler56ad2a02020-03-26 14:00:52 -0500145 }
146 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500147 }
148
Matt Spinler97d19b42019-10-29 11:34:03 -0500149 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500150
151 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -0500152}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500153
Matt Spinler07eefc52019-09-26 11:18:26 -0500154PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500155{
156}
157
Matt Spinler07eefc52019-09-26 11:18:26 -0500158PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500159{
Matt Spinler07eefc52019-09-26 11:18:26 -0500160 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500161}
162
Matt Spinler07eefc52019-09-26 11:18:26 -0500163void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500164{
Matt Spinler07eefc52019-09-26 11:18:26 -0500165 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -0500166 _ph = std::make_unique<PrivateHeader>(pelData);
167 if (obmcLogID != 0)
168 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500169 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500170 }
171
172 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -0500173
174 // Use the section factory to create the rest of the objects
175 for (size_t i = 2; i < _ph->sectionCount(); i++)
176 {
177 auto section = section_factory::create(pelData);
178 _optionalSections.push_back(std::move(section));
179 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500180}
181
182bool PEL::valid() const
183{
184 bool valid = _ph->valid();
185
186 if (valid)
187 {
188 valid = _uh->valid();
189 }
190
Matt Spinler131870c2019-09-25 13:29:04 -0500191 if (valid)
192 {
193 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
194 [](const auto& section) { return section->valid(); }))
195 {
196 valid = false;
197 }
198 }
199
Matt Spinlercb6b0592019-07-16 15:58:51 -0500200 return valid;
201}
202
203void PEL::setCommitTime()
204{
205 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500206 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500207}
208
209void PEL::assignID()
210{
Matt Spinler97d19b42019-10-29 11:34:03 -0500211 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500212}
213
Matt Spinler06885452019-11-06 10:35:42 -0600214void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500215{
216 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500217
Matt Spinler07eefc52019-09-26 11:18:26 -0500218 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500219 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500220 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500221 }
222
Matt Spinler07eefc52019-09-26 11:18:26 -0500223 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500224 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500225
226 for (auto& section : _optionalSections)
227 {
228 section->flatten(pelData);
229 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500230}
231
Matt Spinler06885452019-11-06 10:35:42 -0600232std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500233{
Matt Spinler07eefc52019-09-26 11:18:26 -0500234 std::vector<uint8_t> pelData;
235 flatten(pelData);
236 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500237}
238
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600239size_t PEL::size() const
240{
241 size_t size = 0;
242
243 if (_ph)
244 {
245 size += _ph->header().size;
246 }
247
248 if (_uh)
249 {
250 size += _uh->header().size;
251 }
252
253 for (const auto& section : _optionalSections)
254 {
255 size += section->header().size;
256 }
257
258 return size;
259}
260
Matt Spinlerbd716f02019-10-15 10:54:11 -0500261std::optional<SRC*> PEL::primarySRC() const
262{
263 auto src = std::find_if(
264 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
265 return section->header().id ==
266 static_cast<uint16_t>(SectionID::primarySRC);
267 });
268 if (src != _optionalSections.end())
269 {
270 return static_cast<SRC*>(src->get());
271 }
272
273 return std::nullopt;
274}
275
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500276void PEL::checkRulesAndFix()
277{
Matt Spinler1f93c592020-09-10 10:43:08 -0500278 // Only fix if the action flags are at their default value which
279 // means they weren't specified in the registry. Otherwise
280 // assume the user knows what they are doing.
281 if (_uh->actionFlags() == actionFlagsDefault)
282 {
283 auto [actionFlags, eventType] =
284 pel_rules::check(0, _uh->eventType(), _uh->severity());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500285
Matt Spinler1f93c592020-09-10 10:43:08 -0500286 _uh->setActionFlags(actionFlags);
287 _uh->setEventType(eventType);
288 }
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500289}
290
Matt Spinleracb7c102020-01-10 13:49:22 -0600291void PEL::printSectionInJSON(const Section& section, std::string& buf,
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800292 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800293 message::Registry& registry,
294 const std::vector<std::string>& plugins,
295 uint8_t creatorID) const
Aatir186ce8c2019-10-20 15:13:39 -0500296{
297 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500298 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
299 static_cast<uint8_t>(section.header().id)};
300 sprintf(tmpB, "%c%c", id[0], id[1]);
301 std::string sectionID(tmpB);
302 std::string sectionName = pv::sectionTitles.count(sectionID)
303 ? pv::sectionTitles.at(sectionID)
304 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600305
306 // Add a count if there are multiple of this type of section
307 auto count = pluralSections.find(section.header().id);
308 if (count != pluralSections.end())
309 {
310 sectionName += " " + std::to_string(count->second);
311 count->second++;
312 }
313
Aatir186ce8c2019-10-20 15:13:39 -0500314 if (section.valid())
315 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800316 std::optional<std::string> json;
317 if (sectionID == "PS" || sectionID == "SS")
318 {
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800319 json = section.getJSON(registry, plugins, creatorID);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800320 }
Matt Spinler386a61e2020-08-13 15:51:12 -0500321 else if ((sectionID == "UD") || (sectionID == "ED"))
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800322 {
Harisuddin Mohamed Isa3fdcd4e2020-08-26 11:56:42 +0800323 json = section.getJSON(creatorID, plugins);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800324 }
325 else
326 {
327 json = section.getJSON();
328 }
Matt Spinler4220a152020-03-26 10:18:09 -0500329
330 buf += "\"" + sectionName + "\": {\n";
331
Aatir Manzurad0e0472019-10-07 13:18:37 -0500332 if (json)
333 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800334 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500335 }
336 else
337 {
Matt Spinler4220a152020-03-26 10:18:09 -0500338 jsonInsert(buf, pv::sectionVer,
339 getNumberString("%d", section.header().version), 1);
340 jsonInsert(buf, pv::subSection,
341 getNumberString("%d", section.header().subType), 1);
342 jsonInsert(buf, pv::createdBy,
343 getNumberString("0x%X", section.header().componentID),
344 1);
345
Aatir Manzurad0e0472019-10-07 13:18:37 -0500346 std::vector<uint8_t> data;
347 Stream s{data};
348 section.flatten(s);
Matt Spinler4220a152020-03-26 10:18:09 -0500349 std::string dstr =
350 dumpHex(std::data(data) + SectionHeader::flattenedSize(),
Harisuddin Mohamed Isa097ad122020-06-11 21:19:41 +0800351 data.size() - SectionHeader::flattenedSize(), 2);
Matt Spinler4220a152020-03-26 10:18:09 -0500352 std::string jsonIndent(indentLevel, 0x20);
353 buf += jsonIndent + "\"Data\": [\n";
354 buf += dstr;
355 buf += jsonIndent + "]\n";
356 buf += "},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500357 }
Aatir186ce8c2019-10-20 15:13:39 -0500358 }
359 else
360 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800361 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500362 }
363}
364
Matt Spinleracb7c102020-01-10 13:49:22 -0600365std::map<uint16_t, size_t> PEL::getPluralSections() const
366{
367 std::map<uint16_t, size_t> sectionCounts;
368
369 for (const auto& section : optionalSections())
370 {
371 if (sectionCounts.find(section->header().id) == sectionCounts.end())
372 {
373 sectionCounts[section->header().id] = 1;
374 }
375 else
376 {
377 sectionCounts[section->header().id]++;
378 }
379 }
380
381 std::map<uint16_t, size_t> sections;
382 for (const auto& [id, count] : sectionCounts)
383 {
384 if (count > 1)
385 {
386 // Start with 0 here and printSectionInJSON()
387 // will increment it as it goes.
388 sections.emplace(id, 0);
389 }
390 }
391
392 return sections;
393}
394
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800395void PEL::toJSON(message::Registry& registry,
396 const std::vector<std::string>& plugins) const
Aatir186ce8c2019-10-20 15:13:39 -0500397{
Matt Spinleracb7c102020-01-10 13:49:22 -0600398 auto sections = getPluralSections();
399
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800400 std::string buf = "{\n";
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800401 printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins);
402 printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins);
Aatir186ce8c2019-10-20 15:13:39 -0500403 for (auto& section : this->optionalSections())
404 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800405 printSectionInJSON(*(section.get()), buf, sections, registry, plugins,
406 _ph->creatorID());
Aatir186ce8c2019-10-20 15:13:39 -0500407 }
408 buf += "}";
409 std::size_t found = buf.rfind(",");
410 if (found != std::string::npos)
411 buf.replace(found, 1, "");
412 std::cout << buf << std::endl;
413}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800414
Matt Spinler85f61a62020-06-03 16:28:55 -0500415bool PEL::addUserDataSection(std::unique_ptr<UserData> userData)
416{
417 if (size() + userData->header().size > _maxPELSize)
418 {
419 if (userData->shrink(_maxPELSize - size()))
420 {
421 _optionalSections.push_back(std::move(userData));
422 }
423 else
424 {
425 log<level::WARNING>(
426 "Could not shrink UserData section. Dropping",
427 entry("SECTION_SIZE=%d\n", userData->header().size),
428 entry("COMPONENT_ID=0x%02X", userData->header().componentID),
429 entry("SUBTYPE=0x%X", userData->header().subType),
430 entry("VERSION=0x%X", userData->header().version));
431 return false;
432 }
433 }
434 else
435 {
436 _optionalSections.push_back(std::move(userData));
437 }
438 return true;
439}
440
Matt Spinler5a90a952020-08-27 09:39:03 -0500441nlohmann::json PEL::getCalloutJSON(const PelFFDC& ffdcFiles)
442{
443 nlohmann::json callouts;
444
445 for (const auto& file : ffdcFiles)
446 {
447 if ((file.format == UserDataFormat::json) &&
448 (file.subType == jsonCalloutSubtype))
449 {
450 auto data = util::readFD(file.fd);
451 if (data.empty())
452 {
453 throw std::runtime_error{
454 "Could not get data from JSON callout file descriptor"};
455 }
456
457 std::string jsonString{data.begin(), data.begin() + data.size()};
458
459 callouts = nlohmann::json::parse(jsonString);
460 break;
461 }
462 }
463
464 return callouts;
465}
466
Andrew Geissler44fc3162020-07-09 09:21:31 -0500467bool PEL::isCalloutPresent() const
468{
469 auto pSRC = primarySRC();
470 if (!pSRC)
471 {
472 return false;
473 }
474
475 bool calloutPresent = false;
476 if ((*pSRC)->callouts())
477 {
478 for (auto& i : (*pSRC)->callouts()->callouts())
479 {
480 if (((*i).fruIdentity()))
481 {
482 auto& fruId = (*i).fruIdentity();
483 if ((*fruId).failingComponentType() != 0)
484 {
485 calloutPresent = true;
486 break;
487 }
488 }
489 }
490 }
491
492 return calloutPresent;
493}
494
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600495namespace util
496{
497
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600498std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
499{
500 auto jsonString = json.dump();
501 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
502
503 // Pad to a 4 byte boundary
504 while ((jsonData.size() % 4) != 0)
505 {
506 jsonData.push_back(0);
507 }
508
509 return std::make_unique<UserData>(
510 static_cast<uint16_t>(ComponentID::phosphorLogging),
511 static_cast<uint8_t>(UserDataFormat::json),
512 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
513}
514
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600515std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
516{
517 assert(!ad.empty());
518 nlohmann::json json;
519
520 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
521 if (ad.getValue("ESEL"))
522 {
523 auto newAD = ad;
524 newAD.remove("ESEL");
525 json = newAD.toJSON();
526 }
527 else
528 {
529 json = ad.toJSON();
530 }
531
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600532 return makeJSONUserDataSection(json);
533}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600534
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600535void addProcessNameToJSON(nlohmann::json& json,
536 const std::optional<std::string>& pid,
537 const DataInterfaceBase& dataIface)
538{
Matt Spinler677381b2020-01-23 10:04:29 -0600539 std::string name{unknownValue};
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600540
541 try
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600542 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600543 if (pid)
544 {
545 auto n = dataIface.getProcessName(*pid);
546 if (n)
547 {
548 name = *n;
549 }
550 }
551 }
552 catch (std::exception& e)
553 {
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600554 }
555
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600556 json["Process Name"] = std::move(name);
557}
558
Matt Spinler677381b2020-01-23 10:04:29 -0600559void addBMCFWVersionIDToJSON(nlohmann::json& json,
560 const DataInterfaceBase& dataIface)
561{
562 auto id = dataIface.getBMCFWVersionID();
563 if (id.empty())
564 {
565 id = unknownValue;
566 }
567
568 json["BMC Version ID"] = std::move(id);
569}
570
Matt Spinler4aa23a12020-02-03 15:05:09 -0600571std::string lastSegment(char separator, std::string data)
572{
573 auto pos = data.find_last_of(separator);
574 if (pos != std::string::npos)
575 {
576 data = data.substr(pos + 1);
577 }
578
579 return data;
580}
581
582void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
583{
584 json["BMCState"] = lastSegment('.', dataIface.getBMCState());
585 json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
586 json["HostState"] = lastSegment('.', dataIface.getHostState());
587}
588
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600589std::unique_ptr<UserData>
590 makeSysInfoUserDataSection(const AdditionalData& ad,
591 const DataInterfaceBase& dataIface)
592{
593 nlohmann::json json;
594
595 addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
Matt Spinler677381b2020-01-23 10:04:29 -0600596 addBMCFWVersionIDToJSON(json, dataIface);
Matt Spinler4aa23a12020-02-03 15:05:09 -0600597 addStatesToJSON(json, dataIface);
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600598
599 return makeJSONUserDataSection(json);
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600600}
601
Matt Spinler5b289b22020-03-26 14:27:19 -0500602std::vector<uint8_t> readFD(int fd)
603{
604 std::vector<uint8_t> data;
605
606 // Get the size
607 struct stat s;
608 int r = fstat(fd, &s);
609 if (r != 0)
610 {
611 auto e = errno;
612 log<level::ERR>("Could not get FFDC file size from FD",
613 entry("ERRNO=%d", e));
614 return data;
615 }
616
617 if (0 == s.st_size)
618 {
619 log<level::ERR>("FFDC file is empty");
620 return data;
621 }
622
623 data.resize(s.st_size);
624
625 // Make sure its at the beginning, as maybe another
626 // extension already used it.
627 r = lseek(fd, 0, SEEK_SET);
628 if (r == -1)
629 {
630 auto e = errno;
631 log<level::ERR>("Could not seek to beginning of FFDC file",
632 entry("ERRNO=%d", e));
633 return data;
634 }
635
636 r = read(fd, data.data(), s.st_size);
637 if (r == -1)
638 {
639 auto e = errno;
640 log<level::ERR>("Could not read FFDC file", entry("ERRNO=%d", e));
641 }
642 else if (r != s.st_size)
643 {
644 log<level::WARNING>("Could not read full FFDC file",
645 entry("FILE_SIZE=%d", s.st_size),
646 entry("SIZE_READ=%d", r));
647 }
648
649 return data;
650}
651
Matt Spinler56ad2a02020-03-26 14:00:52 -0500652std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
653 const PelFFDCfile& file)
654{
Matt Spinler5b289b22020-03-26 14:27:19 -0500655 auto data = readFD(file.fd);
656
657 if (data.empty())
658 {
659 return std::unique_ptr<UserData>();
660 }
661
662 // The data needs 4 Byte alignment, and save amount padded for the
663 // CBOR case.
664 uint32_t pad = 0;
665 while (data.size() % 4)
666 {
667 data.push_back(0);
668 pad++;
669 }
670
671 // For JSON, CBOR, and Text use our component ID, subType, and version,
672 // otherwise use the supplied ones.
673 uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging);
674 uint8_t subType{};
675 uint8_t version{};
676
677 switch (file.format)
678 {
679 case UserDataFormat::json:
680 subType = static_cast<uint8_t>(UserDataFormat::json);
681 version = static_cast<uint8_t>(UserDataFormatVersion::json);
682 break;
683 case UserDataFormat::cbor:
684 subType = static_cast<uint8_t>(UserDataFormat::cbor);
685 version = static_cast<uint8_t>(UserDataFormatVersion::cbor);
686
687 // The CBOR parser will fail on the extra pad bytes since they
688 // aren't CBOR. Add the amount we padded to the end and other
689 // code will remove it all before parsing.
690 {
691 data.resize(data.size() + 4);
692 Stream stream{data};
693 stream.offset(data.size() - 4);
694 stream << pad;
695 }
696
697 break;
698 case UserDataFormat::text:
699 subType = static_cast<uint8_t>(UserDataFormat::text);
700 version = static_cast<uint8_t>(UserDataFormatVersion::text);
701 break;
702 case UserDataFormat::custom:
703 default:
704 // Use the passed in values
705 compID = componentID;
706 subType = file.subType;
707 version = file.version;
708 break;
709 }
710
711 return std::make_unique<UserData>(compID, subType, version, data);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500712}
713
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600714} // namespace util
715
Matt Spinlercb6b0592019-07-16 15:58:51 -0500716} // namespace pels
717} // namespace openpower