blob: 56d442d23399479a66438d5c98790ea35ef06b1c [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 Spinlerc63e2e82019-12-02 15:50:12 -060019#include "extended_user_header.hpp"
Matt Spinleraa659472019-10-23 09:26:48 -050020#include "failing_mtms.hpp"
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +080021#include "json_utils.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050022#include "log_id.hpp"
Matt Spinlerf1e85e22019-11-01 11:31:31 -050023#include "pel_rules.hpp"
Aatir186ce8c2019-10-20 15:13:39 -050024#include "pel_values.hpp"
Matt Spinler131870c2019-09-25 13:29:04 -050025#include "section_factory.hpp"
Matt Spinlerbd716f02019-10-15 10:54:11 -050026#include "src.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050027#include "stream.hpp"
Matt Spinlerafa857c2019-10-24 13:03:46 -050028#include "user_data_formats.hpp"
Matt Spinlercb6b0592019-07-16 15:58:51 -050029
Matt Spinler5b289b22020-03-26 14:27:19 -050030#include <sys/stat.h>
31#include <unistd.h>
32
Aatir186ce8c2019-10-20 15:13:39 -050033#include <iostream>
Matt Spinler07eefc52019-09-26 11:18:26 -050034#include <phosphor-logging/log.hpp>
35
Matt Spinlercb6b0592019-07-16 15:58:51 -050036namespace openpower
37{
38namespace pels
39{
Matt Spinlerb8323632019-09-20 15:11:04 -050040namespace message = openpower::pels::message;
Aatir186ce8c2019-10-20 15:13:39 -050041namespace pv = openpower::pels::pel_values;
Matt Spinler4bfc9082020-03-24 15:05:54 -050042using namespace phosphor::logging;
Matt Spinlerb8323632019-09-20 15:11:04 -050043
Matt Spinler677381b2020-01-23 10:04:29 -060044constexpr auto unknownValue = "Unknown";
45
Matt Spinler4bfc9082020-03-24 15:05:54 -050046PEL::PEL(const message::Entry& regEntry, uint32_t obmcLogID, uint64_t timestamp,
Matt Spinlerbd716f02019-10-15 10:54:11 -050047 phosphor::logging::Entry::Level severity,
Matt Spinler56ad2a02020-03-26 14:00:52 -050048 const AdditionalData& additionalData, const PelFFDC& ffdcFiles,
Matt Spinleraa659472019-10-23 09:26:48 -050049 const DataInterfaceBase& dataIface)
Matt Spinlerb8323632019-09-20 15:11:04 -050050{
Matt Spinler85f61a62020-06-03 16:28:55 -050051 std::map<std::string, std::vector<std::string>> debugData;
52
Matt Spinler4bfc9082020-03-24 15:05:54 -050053 _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID,
Matt Spinlerb8323632019-09-20 15:11:04 -050054 timestamp);
Matt Spinleraadccc82020-04-10 14:33:42 -050055 _uh = std::make_unique<UserHeader>(regEntry, severity, dataIface);
Matt Spinlerb8323632019-09-20 15:11:04 -050056
Matt Spinler4bfc9082020-03-24 15:05:54 -050057 auto src = std::make_unique<SRC>(regEntry, additionalData, dataIface);
Matt Spinler85f61a62020-06-03 16:28:55 -050058 if (!src->getDebugData().empty())
59 {
60 // Something didn't go as planned
61 debugData.emplace("SRC", src->getDebugData());
62 }
Matt Spinlerc63e2e82019-12-02 15:50:12 -060063
Matt Spinler4bfc9082020-03-24 15:05:54 -050064 auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src);
Matt Spinlerc63e2e82019-12-02 15:50:12 -060065
Matt Spinlerbd716f02019-10-15 10:54:11 -050066 _optionalSections.push_back(std::move(src));
Matt Spinlerc63e2e82019-12-02 15:50:12 -060067 _optionalSections.push_back(std::move(euh));
Matt Spinlerb8323632019-09-20 15:11:04 -050068
Matt Spinleraa659472019-10-23 09:26:48 -050069 auto mtms = std::make_unique<FailingMTMS>(dataIface);
70 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -050071
Matt Spinler4dcd3f42020-01-22 14:55:07 -060072 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
Matt Spinler85f61a62020-06-03 16:28:55 -050073 addUserDataSection(std::move(ud));
Matt Spinler4dcd3f42020-01-22 14:55:07 -060074
Matt Spinler9b7e94f2020-03-24 15:44:41 -050075 // Create a UserData section from AdditionalData.
Matt Spinlerafa857c2019-10-24 13:03:46 -050076 if (!additionalData.empty())
77 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -060078 ud = util::makeADUserDataSection(additionalData);
Matt Spinler85f61a62020-06-03 16:28:55 -050079 addUserDataSection(std::move(ud));
Matt Spinlerafa857c2019-10-24 13:03:46 -050080 }
81
Matt Spinler56ad2a02020-03-26 14:00:52 -050082 // Add any FFDC files into UserData sections
83 for (const auto& file : ffdcFiles)
84 {
85 ud = util::makeFFDCuserDataSection(regEntry.componentID, file);
86 if (!ud)
87 {
Matt Spinler85f61a62020-06-03 16:28:55 -050088 // Add this error into the debug data UserData section
89 std::ostringstream msg;
90 msg << "Could not make PEL FFDC UserData section from file"
91 << std::hex << regEntry.componentID << " " << file.subType
92 << " " << file.version;
93 if (debugData.count("FFDC File"))
94 {
95 debugData.at("FFDC File").push_back(msg.str());
96 }
97 else
98 {
99 debugData.emplace("FFDC File",
100 std::vector<std::string>{msg.str()});
101 }
102
Matt Spinler56ad2a02020-03-26 14:00:52 -0500103 continue;
104 }
105
Matt Spinler85f61a62020-06-03 16:28:55 -0500106 addUserDataSection(std::move(ud));
107 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500108
Matt Spinler85f61a62020-06-03 16:28:55 -0500109 // Store in the PEL any important debug data created while
110 // building the PEL sections.
111 if (!debugData.empty())
112 {
113 nlohmann::json data;
114 data["PEL Internal Debug Data"] = debugData;
115 ud = util::makeJSONUserDataSection(data);
116
117 addUserDataSection(std::move(ud));
118
119 // Also put in the journal for debug
120 for (const auto& [name, data] : debugData)
121 {
122 for (const auto& message : data)
123 {
124 std::string entry = name + ": " + message;
125 log<level::INFO>(entry.c_str());
Matt Spinler56ad2a02020-03-26 14:00:52 -0500126 }
127 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500128 }
129
Matt Spinler97d19b42019-10-29 11:34:03 -0500130 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500131
132 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -0500133}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500134
Matt Spinler07eefc52019-09-26 11:18:26 -0500135PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500136{
137}
138
Matt Spinler07eefc52019-09-26 11:18:26 -0500139PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500140{
Matt Spinler07eefc52019-09-26 11:18:26 -0500141 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500142}
143
Matt Spinler07eefc52019-09-26 11:18:26 -0500144void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500145{
Matt Spinler07eefc52019-09-26 11:18:26 -0500146 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -0500147 _ph = std::make_unique<PrivateHeader>(pelData);
148 if (obmcLogID != 0)
149 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500150 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500151 }
152
153 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -0500154
155 // Use the section factory to create the rest of the objects
156 for (size_t i = 2; i < _ph->sectionCount(); i++)
157 {
158 auto section = section_factory::create(pelData);
159 _optionalSections.push_back(std::move(section));
160 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500161}
162
163bool PEL::valid() const
164{
165 bool valid = _ph->valid();
166
167 if (valid)
168 {
169 valid = _uh->valid();
170 }
171
Matt Spinler131870c2019-09-25 13:29:04 -0500172 if (valid)
173 {
174 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
175 [](const auto& section) { return section->valid(); }))
176 {
177 valid = false;
178 }
179 }
180
Matt Spinlercb6b0592019-07-16 15:58:51 -0500181 return valid;
182}
183
184void PEL::setCommitTime()
185{
186 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500187 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500188}
189
190void PEL::assignID()
191{
Matt Spinler97d19b42019-10-29 11:34:03 -0500192 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500193}
194
Matt Spinler06885452019-11-06 10:35:42 -0600195void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500196{
197 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500198
Matt Spinler07eefc52019-09-26 11:18:26 -0500199 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500200 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500201 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500202 }
203
Matt Spinler07eefc52019-09-26 11:18:26 -0500204 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500205 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500206
207 for (auto& section : _optionalSections)
208 {
209 section->flatten(pelData);
210 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500211}
212
Matt Spinler06885452019-11-06 10:35:42 -0600213std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500214{
Matt Spinler07eefc52019-09-26 11:18:26 -0500215 std::vector<uint8_t> pelData;
216 flatten(pelData);
217 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500218}
219
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600220size_t PEL::size() const
221{
222 size_t size = 0;
223
224 if (_ph)
225 {
226 size += _ph->header().size;
227 }
228
229 if (_uh)
230 {
231 size += _uh->header().size;
232 }
233
234 for (const auto& section : _optionalSections)
235 {
236 size += section->header().size;
237 }
238
239 return size;
240}
241
Matt Spinlerbd716f02019-10-15 10:54:11 -0500242std::optional<SRC*> PEL::primarySRC() const
243{
244 auto src = std::find_if(
245 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
246 return section->header().id ==
247 static_cast<uint16_t>(SectionID::primarySRC);
248 });
249 if (src != _optionalSections.end())
250 {
251 return static_cast<SRC*>(src->get());
252 }
253
254 return std::nullopt;
255}
256
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500257void PEL::checkRulesAndFix()
258{
259 auto [actionFlags, eventType] =
260 pel_rules::check(_uh->actionFlags(), _uh->eventType(), _uh->severity());
261
262 _uh->setActionFlags(actionFlags);
263 _uh->setEventType(eventType);
264}
265
Matt Spinleracb7c102020-01-10 13:49:22 -0600266void PEL::printSectionInJSON(const Section& section, std::string& buf,
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800267 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800268 message::Registry& registry,
269 const std::vector<std::string>& plugins,
270 uint8_t creatorID) const
Aatir186ce8c2019-10-20 15:13:39 -0500271{
272 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500273 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
274 static_cast<uint8_t>(section.header().id)};
275 sprintf(tmpB, "%c%c", id[0], id[1]);
276 std::string sectionID(tmpB);
277 std::string sectionName = pv::sectionTitles.count(sectionID)
278 ? pv::sectionTitles.at(sectionID)
279 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600280
281 // Add a count if there are multiple of this type of section
282 auto count = pluralSections.find(section.header().id);
283 if (count != pluralSections.end())
284 {
285 sectionName += " " + std::to_string(count->second);
286 count->second++;
287 }
288
Aatir186ce8c2019-10-20 15:13:39 -0500289 if (section.valid())
290 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800291 std::optional<std::string> json;
292 if (sectionID == "PS" || sectionID == "SS")
293 {
294 json = section.getJSON(registry);
295 }
296 else if (sectionID == "UD")
297 {
298 std::string subsystem = getNumberString("%c", tolower(creatorID));
299 std::string component =
300 getNumberString("%04x", section.header().componentID);
Harisuddin Mohamed Isace397f72020-08-19 17:48:41 +0800301 if ((std::find(plugins.begin(), plugins.end(),
302 subsystem + component) != plugins.end()) ||
303 pv::creatorIDs.at(getNumberString("%c", creatorID)) == "BMC")
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800304 {
305 json = section.getJSON(creatorID);
306 }
307 }
308 else
309 {
310 json = section.getJSON();
311 }
Matt Spinler4220a152020-03-26 10:18:09 -0500312
313 buf += "\"" + sectionName + "\": {\n";
314
Aatir Manzurad0e0472019-10-07 13:18:37 -0500315 if (json)
316 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800317 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500318 }
319 else
320 {
Matt Spinler4220a152020-03-26 10:18:09 -0500321 jsonInsert(buf, pv::sectionVer,
322 getNumberString("%d", section.header().version), 1);
323 jsonInsert(buf, pv::subSection,
324 getNumberString("%d", section.header().subType), 1);
325 jsonInsert(buf, pv::createdBy,
326 getNumberString("0x%X", section.header().componentID),
327 1);
328
Aatir Manzurad0e0472019-10-07 13:18:37 -0500329 std::vector<uint8_t> data;
330 Stream s{data};
331 section.flatten(s);
Matt Spinler4220a152020-03-26 10:18:09 -0500332 std::string dstr =
333 dumpHex(std::data(data) + SectionHeader::flattenedSize(),
Harisuddin Mohamed Isa097ad122020-06-11 21:19:41 +0800334 data.size() - SectionHeader::flattenedSize(), 2);
Matt Spinler4220a152020-03-26 10:18:09 -0500335 std::string jsonIndent(indentLevel, 0x20);
336 buf += jsonIndent + "\"Data\": [\n";
337 buf += dstr;
338 buf += jsonIndent + "]\n";
339 buf += "},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500340 }
Aatir186ce8c2019-10-20 15:13:39 -0500341 }
342 else
343 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800344 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500345 }
346}
347
Matt Spinleracb7c102020-01-10 13:49:22 -0600348std::map<uint16_t, size_t> PEL::getPluralSections() const
349{
350 std::map<uint16_t, size_t> sectionCounts;
351
352 for (const auto& section : optionalSections())
353 {
354 if (sectionCounts.find(section->header().id) == sectionCounts.end())
355 {
356 sectionCounts[section->header().id] = 1;
357 }
358 else
359 {
360 sectionCounts[section->header().id]++;
361 }
362 }
363
364 std::map<uint16_t, size_t> sections;
365 for (const auto& [id, count] : sectionCounts)
366 {
367 if (count > 1)
368 {
369 // Start with 0 here and printSectionInJSON()
370 // will increment it as it goes.
371 sections.emplace(id, 0);
372 }
373 }
374
375 return sections;
376}
377
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800378void PEL::toJSON(message::Registry& registry,
379 const std::vector<std::string>& plugins) const
Aatir186ce8c2019-10-20 15:13:39 -0500380{
Matt Spinleracb7c102020-01-10 13:49:22 -0600381 auto sections = getPluralSections();
382
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800383 std::string buf = "{\n";
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800384 printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins);
385 printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins);
Aatir186ce8c2019-10-20 15:13:39 -0500386 for (auto& section : this->optionalSections())
387 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800388 printSectionInJSON(*(section.get()), buf, sections, registry, plugins,
389 _ph->creatorID());
Aatir186ce8c2019-10-20 15:13:39 -0500390 }
391 buf += "}";
392 std::size_t found = buf.rfind(",");
393 if (found != std::string::npos)
394 buf.replace(found, 1, "");
395 std::cout << buf << std::endl;
396}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800397
Matt Spinler85f61a62020-06-03 16:28:55 -0500398bool PEL::addUserDataSection(std::unique_ptr<UserData> userData)
399{
400 if (size() + userData->header().size > _maxPELSize)
401 {
402 if (userData->shrink(_maxPELSize - size()))
403 {
404 _optionalSections.push_back(std::move(userData));
405 }
406 else
407 {
408 log<level::WARNING>(
409 "Could not shrink UserData section. Dropping",
410 entry("SECTION_SIZE=%d\n", userData->header().size),
411 entry("COMPONENT_ID=0x%02X", userData->header().componentID),
412 entry("SUBTYPE=0x%X", userData->header().subType),
413 entry("VERSION=0x%X", userData->header().version));
414 return false;
415 }
416 }
417 else
418 {
419 _optionalSections.push_back(std::move(userData));
420 }
421 return true;
422}
423
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600424namespace util
425{
426
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600427std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
428{
429 auto jsonString = json.dump();
430 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
431
432 // Pad to a 4 byte boundary
433 while ((jsonData.size() % 4) != 0)
434 {
435 jsonData.push_back(0);
436 }
437
438 return std::make_unique<UserData>(
439 static_cast<uint16_t>(ComponentID::phosphorLogging),
440 static_cast<uint8_t>(UserDataFormat::json),
441 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
442}
443
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600444std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
445{
446 assert(!ad.empty());
447 nlohmann::json json;
448
449 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
450 if (ad.getValue("ESEL"))
451 {
452 auto newAD = ad;
453 newAD.remove("ESEL");
454 json = newAD.toJSON();
455 }
456 else
457 {
458 json = ad.toJSON();
459 }
460
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600461 return makeJSONUserDataSection(json);
462}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600463
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600464void addProcessNameToJSON(nlohmann::json& json,
465 const std::optional<std::string>& pid,
466 const DataInterfaceBase& dataIface)
467{
Matt Spinler677381b2020-01-23 10:04:29 -0600468 std::string name{unknownValue};
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600469
470 try
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600471 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600472 if (pid)
473 {
474 auto n = dataIface.getProcessName(*pid);
475 if (n)
476 {
477 name = *n;
478 }
479 }
480 }
481 catch (std::exception& e)
482 {
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600483 }
484
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600485 json["Process Name"] = std::move(name);
486}
487
Matt Spinler677381b2020-01-23 10:04:29 -0600488void addBMCFWVersionIDToJSON(nlohmann::json& json,
489 const DataInterfaceBase& dataIface)
490{
491 auto id = dataIface.getBMCFWVersionID();
492 if (id.empty())
493 {
494 id = unknownValue;
495 }
496
497 json["BMC Version ID"] = std::move(id);
498}
499
Matt Spinler4aa23a12020-02-03 15:05:09 -0600500std::string lastSegment(char separator, std::string data)
501{
502 auto pos = data.find_last_of(separator);
503 if (pos != std::string::npos)
504 {
505 data = data.substr(pos + 1);
506 }
507
508 return data;
509}
510
511void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
512{
513 json["BMCState"] = lastSegment('.', dataIface.getBMCState());
514 json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
515 json["HostState"] = lastSegment('.', dataIface.getHostState());
516}
517
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600518std::unique_ptr<UserData>
519 makeSysInfoUserDataSection(const AdditionalData& ad,
520 const DataInterfaceBase& dataIface)
521{
522 nlohmann::json json;
523
524 addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
Matt Spinler677381b2020-01-23 10:04:29 -0600525 addBMCFWVersionIDToJSON(json, dataIface);
Matt Spinler4aa23a12020-02-03 15:05:09 -0600526 addStatesToJSON(json, dataIface);
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600527
528 return makeJSONUserDataSection(json);
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600529}
530
Matt Spinler5b289b22020-03-26 14:27:19 -0500531std::vector<uint8_t> readFD(int fd)
532{
533 std::vector<uint8_t> data;
534
535 // Get the size
536 struct stat s;
537 int r = fstat(fd, &s);
538 if (r != 0)
539 {
540 auto e = errno;
541 log<level::ERR>("Could not get FFDC file size from FD",
542 entry("ERRNO=%d", e));
543 return data;
544 }
545
546 if (0 == s.st_size)
547 {
548 log<level::ERR>("FFDC file is empty");
549 return data;
550 }
551
552 data.resize(s.st_size);
553
554 // Make sure its at the beginning, as maybe another
555 // extension already used it.
556 r = lseek(fd, 0, SEEK_SET);
557 if (r == -1)
558 {
559 auto e = errno;
560 log<level::ERR>("Could not seek to beginning of FFDC file",
561 entry("ERRNO=%d", e));
562 return data;
563 }
564
565 r = read(fd, data.data(), s.st_size);
566 if (r == -1)
567 {
568 auto e = errno;
569 log<level::ERR>("Could not read FFDC file", entry("ERRNO=%d", e));
570 }
571 else if (r != s.st_size)
572 {
573 log<level::WARNING>("Could not read full FFDC file",
574 entry("FILE_SIZE=%d", s.st_size),
575 entry("SIZE_READ=%d", r));
576 }
577
578 return data;
579}
580
Matt Spinler56ad2a02020-03-26 14:00:52 -0500581std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
582 const PelFFDCfile& file)
583{
Matt Spinler5b289b22020-03-26 14:27:19 -0500584 auto data = readFD(file.fd);
585
586 if (data.empty())
587 {
588 return std::unique_ptr<UserData>();
589 }
590
591 // The data needs 4 Byte alignment, and save amount padded for the
592 // CBOR case.
593 uint32_t pad = 0;
594 while (data.size() % 4)
595 {
596 data.push_back(0);
597 pad++;
598 }
599
600 // For JSON, CBOR, and Text use our component ID, subType, and version,
601 // otherwise use the supplied ones.
602 uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging);
603 uint8_t subType{};
604 uint8_t version{};
605
606 switch (file.format)
607 {
608 case UserDataFormat::json:
609 subType = static_cast<uint8_t>(UserDataFormat::json);
610 version = static_cast<uint8_t>(UserDataFormatVersion::json);
611 break;
612 case UserDataFormat::cbor:
613 subType = static_cast<uint8_t>(UserDataFormat::cbor);
614 version = static_cast<uint8_t>(UserDataFormatVersion::cbor);
615
616 // The CBOR parser will fail on the extra pad bytes since they
617 // aren't CBOR. Add the amount we padded to the end and other
618 // code will remove it all before parsing.
619 {
620 data.resize(data.size() + 4);
621 Stream stream{data};
622 stream.offset(data.size() - 4);
623 stream << pad;
624 }
625
626 break;
627 case UserDataFormat::text:
628 subType = static_cast<uint8_t>(UserDataFormat::text);
629 version = static_cast<uint8_t>(UserDataFormatVersion::text);
630 break;
631 case UserDataFormat::custom:
632 default:
633 // Use the passed in values
634 compID = componentID;
635 subType = file.subType;
636 version = file.version;
637 break;
638 }
639
640 return std::make_unique<UserData>(compID, subType, version, data);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500641}
642
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600643} // namespace util
644
Matt Spinlercb6b0592019-07-16 15:58:51 -0500645} // namespace pels
646} // namespace openpower