blob: 2391e522ec74bcb4246c142dfc94b6301bbc3724 [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";
Matt Spinler5a90a952020-08-27 09:39:03 -050045constexpr uint8_t jsonCalloutSubtype = 0xCA;
Matt Spinler677381b2020-01-23 10:04:29 -060046
Matt Spinler4bfc9082020-03-24 15:05:54 -050047PEL::PEL(const message::Entry& regEntry, uint32_t obmcLogID, uint64_t timestamp,
Matt Spinlerbd716f02019-10-15 10:54:11 -050048 phosphor::logging::Entry::Level severity,
Matt Spinler56ad2a02020-03-26 14:00:52 -050049 const AdditionalData& additionalData, const PelFFDC& ffdcFiles,
Matt Spinleraa659472019-10-23 09:26:48 -050050 const DataInterfaceBase& dataIface)
Matt Spinlerb8323632019-09-20 15:11:04 -050051{
Matt Spinler85f61a62020-06-03 16:28:55 -050052 std::map<std::string, std::vector<std::string>> debugData;
Matt Spinler5a90a952020-08-27 09:39:03 -050053 nlohmann::json callouts;
Matt Spinler85f61a62020-06-03 16:28:55 -050054
Matt Spinler4bfc9082020-03-24 15:05:54 -050055 _ph = std::make_unique<PrivateHeader>(regEntry.componentID, obmcLogID,
Matt Spinlerb8323632019-09-20 15:11:04 -050056 timestamp);
Matt Spinleraadccc82020-04-10 14:33:42 -050057 _uh = std::make_unique<UserHeader>(regEntry, severity, dataIface);
Matt Spinlerb8323632019-09-20 15:11:04 -050058
Matt Spinler5a90a952020-08-27 09:39:03 -050059 // Extract any callouts embedded in an FFDC file.
60 if (!ffdcFiles.empty())
61 {
62 try
63 {
64 callouts = getCalloutJSON(ffdcFiles);
65 }
66 catch (const std::exception& e)
67 {
68 debugData.emplace("FFDC file JSON callouts error",
69 std::vector<std::string>{e.what()});
70 }
71 }
72
73 auto src =
74 std::make_unique<SRC>(regEntry, additionalData, callouts, dataIface);
75
Matt Spinler85f61a62020-06-03 16:28:55 -050076 if (!src->getDebugData().empty())
77 {
78 // Something didn't go as planned
79 debugData.emplace("SRC", src->getDebugData());
80 }
Matt Spinlerc63e2e82019-12-02 15:50:12 -060081
Matt Spinler4bfc9082020-03-24 15:05:54 -050082 auto euh = std::make_unique<ExtendedUserHeader>(dataIface, regEntry, *src);
Matt Spinlerc63e2e82019-12-02 15:50:12 -060083
Matt Spinlerbd716f02019-10-15 10:54:11 -050084 _optionalSections.push_back(std::move(src));
Matt Spinlerc63e2e82019-12-02 15:50:12 -060085 _optionalSections.push_back(std::move(euh));
Matt Spinlerb8323632019-09-20 15:11:04 -050086
Matt Spinleraa659472019-10-23 09:26:48 -050087 auto mtms = std::make_unique<FailingMTMS>(dataIface);
88 _optionalSections.push_back(std::move(mtms));
Matt Spinlerbd716f02019-10-15 10:54:11 -050089
Matt Spinler4dcd3f42020-01-22 14:55:07 -060090 auto ud = util::makeSysInfoUserDataSection(additionalData, dataIface);
Matt Spinler85f61a62020-06-03 16:28:55 -050091 addUserDataSection(std::move(ud));
Matt Spinler4dcd3f42020-01-22 14:55:07 -060092
Matt Spinler9b7e94f2020-03-24 15:44:41 -050093 // Create a UserData section from AdditionalData.
Matt Spinlerafa857c2019-10-24 13:03:46 -050094 if (!additionalData.empty())
95 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -060096 ud = util::makeADUserDataSection(additionalData);
Matt Spinler85f61a62020-06-03 16:28:55 -050097 addUserDataSection(std::move(ud));
Matt Spinlerafa857c2019-10-24 13:03:46 -050098 }
99
Matt Spinler56ad2a02020-03-26 14:00:52 -0500100 // Add any FFDC files into UserData sections
101 for (const auto& file : ffdcFiles)
102 {
103 ud = util::makeFFDCuserDataSection(regEntry.componentID, file);
104 if (!ud)
105 {
Matt Spinler85f61a62020-06-03 16:28:55 -0500106 // Add this error into the debug data UserData section
107 std::ostringstream msg;
108 msg << "Could not make PEL FFDC UserData section from file"
109 << std::hex << regEntry.componentID << " " << file.subType
110 << " " << file.version;
111 if (debugData.count("FFDC File"))
112 {
113 debugData.at("FFDC File").push_back(msg.str());
114 }
115 else
116 {
117 debugData.emplace("FFDC File",
118 std::vector<std::string>{msg.str()});
119 }
120
Matt Spinler56ad2a02020-03-26 14:00:52 -0500121 continue;
122 }
123
Matt Spinler85f61a62020-06-03 16:28:55 -0500124 addUserDataSection(std::move(ud));
125 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500126
Matt Spinler85f61a62020-06-03 16:28:55 -0500127 // Store in the PEL any important debug data created while
128 // building the PEL sections.
129 if (!debugData.empty())
130 {
131 nlohmann::json data;
132 data["PEL Internal Debug Data"] = debugData;
133 ud = util::makeJSONUserDataSection(data);
134
135 addUserDataSection(std::move(ud));
136
137 // Also put in the journal for debug
138 for (const auto& [name, data] : debugData)
139 {
140 for (const auto& message : data)
141 {
142 std::string entry = name + ": " + message;
143 log<level::INFO>(entry.c_str());
Matt Spinler56ad2a02020-03-26 14:00:52 -0500144 }
145 }
Matt Spinler56ad2a02020-03-26 14:00:52 -0500146 }
147
Matt Spinler97d19b42019-10-29 11:34:03 -0500148 _ph->setSectionCount(2 + _optionalSections.size());
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500149
150 checkRulesAndFix();
Matt Spinlerb8323632019-09-20 15:11:04 -0500151}
Matt Spinlercb6b0592019-07-16 15:58:51 -0500152
Matt Spinler07eefc52019-09-26 11:18:26 -0500153PEL::PEL(std::vector<uint8_t>& data) : PEL(data, 0)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500154{
155}
156
Matt Spinler07eefc52019-09-26 11:18:26 -0500157PEL::PEL(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500158{
Matt Spinler07eefc52019-09-26 11:18:26 -0500159 populateFromRawData(data, obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500160}
161
Matt Spinler07eefc52019-09-26 11:18:26 -0500162void PEL::populateFromRawData(std::vector<uint8_t>& data, uint32_t obmcLogID)
Matt Spinlercb6b0592019-07-16 15:58:51 -0500163{
Matt Spinler07eefc52019-09-26 11:18:26 -0500164 Stream pelData{data};
Matt Spinlercb6b0592019-07-16 15:58:51 -0500165 _ph = std::make_unique<PrivateHeader>(pelData);
166 if (obmcLogID != 0)
167 {
Matt Spinler97d19b42019-10-29 11:34:03 -0500168 _ph->setOBMCLogID(obmcLogID);
Matt Spinlercb6b0592019-07-16 15:58:51 -0500169 }
170
171 _uh = std::make_unique<UserHeader>(pelData);
Matt Spinler131870c2019-09-25 13:29:04 -0500172
173 // Use the section factory to create the rest of the objects
174 for (size_t i = 2; i < _ph->sectionCount(); i++)
175 {
176 auto section = section_factory::create(pelData);
177 _optionalSections.push_back(std::move(section));
178 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500179}
180
181bool PEL::valid() const
182{
183 bool valid = _ph->valid();
184
185 if (valid)
186 {
187 valid = _uh->valid();
188 }
189
Matt Spinler131870c2019-09-25 13:29:04 -0500190 if (valid)
191 {
192 if (!std::all_of(_optionalSections.begin(), _optionalSections.end(),
193 [](const auto& section) { return section->valid(); }))
194 {
195 valid = false;
196 }
197 }
198
Matt Spinlercb6b0592019-07-16 15:58:51 -0500199 return valid;
200}
201
202void PEL::setCommitTime()
203{
204 auto now = std::chrono::system_clock::now();
Matt Spinler97d19b42019-10-29 11:34:03 -0500205 _ph->setCommitTimestamp(getBCDTime(now));
Matt Spinlercb6b0592019-07-16 15:58:51 -0500206}
207
208void PEL::assignID()
209{
Matt Spinler97d19b42019-10-29 11:34:03 -0500210 _ph->setID(generatePELID());
Matt Spinlercb6b0592019-07-16 15:58:51 -0500211}
212
Matt Spinler06885452019-11-06 10:35:42 -0600213void PEL::flatten(std::vector<uint8_t>& pelBuffer) const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500214{
215 Stream pelData{pelBuffer};
Matt Spinlerb8323632019-09-20 15:11:04 -0500216
Matt Spinler07eefc52019-09-26 11:18:26 -0500217 if (!valid())
Matt Spinlercb6b0592019-07-16 15:58:51 -0500218 {
Matt Spinler07eefc52019-09-26 11:18:26 -0500219 log<level::WARNING>("Unflattening an invalid PEL");
Matt Spinlercb6b0592019-07-16 15:58:51 -0500220 }
221
Matt Spinler07eefc52019-09-26 11:18:26 -0500222 _ph->flatten(pelData);
Matt Spinlerb8323632019-09-20 15:11:04 -0500223 _uh->flatten(pelData);
Matt Spinler07eefc52019-09-26 11:18:26 -0500224
225 for (auto& section : _optionalSections)
226 {
227 section->flatten(pelData);
228 }
Matt Spinlercb6b0592019-07-16 15:58:51 -0500229}
230
Matt Spinler06885452019-11-06 10:35:42 -0600231std::vector<uint8_t> PEL::data() const
Matt Spinlercb6b0592019-07-16 15:58:51 -0500232{
Matt Spinler07eefc52019-09-26 11:18:26 -0500233 std::vector<uint8_t> pelData;
234 flatten(pelData);
235 return pelData;
Matt Spinlercb6b0592019-07-16 15:58:51 -0500236}
237
Matt Spinlerf1b46ff2020-01-22 14:10:04 -0600238size_t PEL::size() const
239{
240 size_t size = 0;
241
242 if (_ph)
243 {
244 size += _ph->header().size;
245 }
246
247 if (_uh)
248 {
249 size += _uh->header().size;
250 }
251
252 for (const auto& section : _optionalSections)
253 {
254 size += section->header().size;
255 }
256
257 return size;
258}
259
Matt Spinlerbd716f02019-10-15 10:54:11 -0500260std::optional<SRC*> PEL::primarySRC() const
261{
262 auto src = std::find_if(
263 _optionalSections.begin(), _optionalSections.end(), [](auto& section) {
264 return section->header().id ==
265 static_cast<uint16_t>(SectionID::primarySRC);
266 });
267 if (src != _optionalSections.end())
268 {
269 return static_cast<SRC*>(src->get());
270 }
271
272 return std::nullopt;
273}
274
Matt Spinlerf1e85e22019-11-01 11:31:31 -0500275void PEL::checkRulesAndFix()
276{
277 auto [actionFlags, eventType] =
278 pel_rules::check(_uh->actionFlags(), _uh->eventType(), _uh->severity());
279
280 _uh->setActionFlags(actionFlags);
281 _uh->setEventType(eventType);
282}
283
Matt Spinleracb7c102020-01-10 13:49:22 -0600284void PEL::printSectionInJSON(const Section& section, std::string& buf,
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800285 std::map<uint16_t, size_t>& pluralSections,
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800286 message::Registry& registry,
287 const std::vector<std::string>& plugins,
288 uint8_t creatorID) const
Aatir186ce8c2019-10-20 15:13:39 -0500289{
290 char tmpB[5];
Aatir Manzurad0e0472019-10-07 13:18:37 -0500291 uint8_t id[] = {static_cast<uint8_t>(section.header().id >> 8),
292 static_cast<uint8_t>(section.header().id)};
293 sprintf(tmpB, "%c%c", id[0], id[1]);
294 std::string sectionID(tmpB);
295 std::string sectionName = pv::sectionTitles.count(sectionID)
296 ? pv::sectionTitles.at(sectionID)
297 : "Unknown Section";
Matt Spinleracb7c102020-01-10 13:49:22 -0600298
299 // Add a count if there are multiple of this type of section
300 auto count = pluralSections.find(section.header().id);
301 if (count != pluralSections.end())
302 {
303 sectionName += " " + std::to_string(count->second);
304 count->second++;
305 }
306
Aatir186ce8c2019-10-20 15:13:39 -0500307 if (section.valid())
308 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800309 std::optional<std::string> json;
310 if (sectionID == "PS" || sectionID == "SS")
311 {
Harisuddin Mohamed Isac8d6cc62020-08-19 22:47:19 +0800312 json = section.getJSON(registry, plugins, creatorID);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800313 }
314 else if (sectionID == "UD")
315 {
Harisuddin Mohamed Isa3fdcd4e2020-08-26 11:56:42 +0800316 json = section.getJSON(creatorID, plugins);
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800317 }
318 else
319 {
320 json = section.getJSON();
321 }
Matt Spinler4220a152020-03-26 10:18:09 -0500322
323 buf += "\"" + sectionName + "\": {\n";
324
Aatir Manzurad0e0472019-10-07 13:18:37 -0500325 if (json)
326 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800327 buf += *json + "\n},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500328 }
329 else
330 {
Matt Spinler4220a152020-03-26 10:18:09 -0500331 jsonInsert(buf, pv::sectionVer,
332 getNumberString("%d", section.header().version), 1);
333 jsonInsert(buf, pv::subSection,
334 getNumberString("%d", section.header().subType), 1);
335 jsonInsert(buf, pv::createdBy,
336 getNumberString("0x%X", section.header().componentID),
337 1);
338
Aatir Manzurad0e0472019-10-07 13:18:37 -0500339 std::vector<uint8_t> data;
340 Stream s{data};
341 section.flatten(s);
Matt Spinler4220a152020-03-26 10:18:09 -0500342 std::string dstr =
343 dumpHex(std::data(data) + SectionHeader::flattenedSize(),
Harisuddin Mohamed Isa097ad122020-06-11 21:19:41 +0800344 data.size() - SectionHeader::flattenedSize(), 2);
Matt Spinler4220a152020-03-26 10:18:09 -0500345 std::string jsonIndent(indentLevel, 0x20);
346 buf += jsonIndent + "\"Data\": [\n";
347 buf += dstr;
348 buf += jsonIndent + "]\n";
349 buf += "},\n";
Aatir Manzurad0e0472019-10-07 13:18:37 -0500350 }
Aatir186ce8c2019-10-20 15:13:39 -0500351 }
352 else
353 {
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800354 buf += "\n\"Invalid Section\": [\n \"invalid\"\n],\n";
Aatir186ce8c2019-10-20 15:13:39 -0500355 }
356}
357
Matt Spinleracb7c102020-01-10 13:49:22 -0600358std::map<uint16_t, size_t> PEL::getPluralSections() const
359{
360 std::map<uint16_t, size_t> sectionCounts;
361
362 for (const auto& section : optionalSections())
363 {
364 if (sectionCounts.find(section->header().id) == sectionCounts.end())
365 {
366 sectionCounts[section->header().id] = 1;
367 }
368 else
369 {
370 sectionCounts[section->header().id]++;
371 }
372 }
373
374 std::map<uint16_t, size_t> sections;
375 for (const auto& [id, count] : sectionCounts)
376 {
377 if (count > 1)
378 {
379 // Start with 0 here and printSectionInJSON()
380 // will increment it as it goes.
381 sections.emplace(id, 0);
382 }
383 }
384
385 return sections;
386}
387
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800388void PEL::toJSON(message::Registry& registry,
389 const std::vector<std::string>& plugins) const
Aatir186ce8c2019-10-20 15:13:39 -0500390{
Matt Spinleracb7c102020-01-10 13:49:22 -0600391 auto sections = getPluralSections();
392
Harisuddin Mohamed Isaa214ed32020-02-28 15:58:23 +0800393 std::string buf = "{\n";
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800394 printSectionInJSON(*(_ph.get()), buf, sections, registry, plugins);
395 printSectionInJSON(*(_uh.get()), buf, sections, registry, plugins);
Aatir186ce8c2019-10-20 15:13:39 -0500396 for (auto& section : this->optionalSections())
397 {
Harisuddin Mohamed Isaf67bafd2020-07-06 17:51:21 +0800398 printSectionInJSON(*(section.get()), buf, sections, registry, plugins,
399 _ph->creatorID());
Aatir186ce8c2019-10-20 15:13:39 -0500400 }
401 buf += "}";
402 std::size_t found = buf.rfind(",");
403 if (found != std::string::npos)
404 buf.replace(found, 1, "");
405 std::cout << buf << std::endl;
406}
Harisuddin Mohamed Isa600d15a2019-12-20 12:42:26 +0800407
Matt Spinler85f61a62020-06-03 16:28:55 -0500408bool PEL::addUserDataSection(std::unique_ptr<UserData> userData)
409{
410 if (size() + userData->header().size > _maxPELSize)
411 {
412 if (userData->shrink(_maxPELSize - size()))
413 {
414 _optionalSections.push_back(std::move(userData));
415 }
416 else
417 {
418 log<level::WARNING>(
419 "Could not shrink UserData section. Dropping",
420 entry("SECTION_SIZE=%d\n", userData->header().size),
421 entry("COMPONENT_ID=0x%02X", userData->header().componentID),
422 entry("SUBTYPE=0x%X", userData->header().subType),
423 entry("VERSION=0x%X", userData->header().version));
424 return false;
425 }
426 }
427 else
428 {
429 _optionalSections.push_back(std::move(userData));
430 }
431 return true;
432}
433
Matt Spinler5a90a952020-08-27 09:39:03 -0500434nlohmann::json PEL::getCalloutJSON(const PelFFDC& ffdcFiles)
435{
436 nlohmann::json callouts;
437
438 for (const auto& file : ffdcFiles)
439 {
440 if ((file.format == UserDataFormat::json) &&
441 (file.subType == jsonCalloutSubtype))
442 {
443 auto data = util::readFD(file.fd);
444 if (data.empty())
445 {
446 throw std::runtime_error{
447 "Could not get data from JSON callout file descriptor"};
448 }
449
450 std::string jsonString{data.begin(), data.begin() + data.size()};
451
452 callouts = nlohmann::json::parse(jsonString);
453 break;
454 }
455 }
456
457 return callouts;
458}
459
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600460namespace util
461{
462
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600463std::unique_ptr<UserData> makeJSONUserDataSection(const nlohmann::json& json)
464{
465 auto jsonString = json.dump();
466 std::vector<uint8_t> jsonData(jsonString.begin(), jsonString.end());
467
468 // Pad to a 4 byte boundary
469 while ((jsonData.size() % 4) != 0)
470 {
471 jsonData.push_back(0);
472 }
473
474 return std::make_unique<UserData>(
475 static_cast<uint16_t>(ComponentID::phosphorLogging),
476 static_cast<uint8_t>(UserDataFormat::json),
477 static_cast<uint8_t>(UserDataFormatVersion::json), jsonData);
478}
479
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600480std::unique_ptr<UserData> makeADUserDataSection(const AdditionalData& ad)
481{
482 assert(!ad.empty());
483 nlohmann::json json;
484
485 // Remove the 'ESEL' entry, as it contains a full PEL in the value.
486 if (ad.getValue("ESEL"))
487 {
488 auto newAD = ad;
489 newAD.remove("ESEL");
490 json = newAD.toJSON();
491 }
492 else
493 {
494 json = ad.toJSON();
495 }
496
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600497 return makeJSONUserDataSection(json);
498}
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600499
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600500void addProcessNameToJSON(nlohmann::json& json,
501 const std::optional<std::string>& pid,
502 const DataInterfaceBase& dataIface)
503{
Matt Spinler677381b2020-01-23 10:04:29 -0600504 std::string name{unknownValue};
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600505
506 try
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600507 {
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600508 if (pid)
509 {
510 auto n = dataIface.getProcessName(*pid);
511 if (n)
512 {
513 name = *n;
514 }
515 }
516 }
517 catch (std::exception& e)
518 {
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600519 }
520
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600521 json["Process Name"] = std::move(name);
522}
523
Matt Spinler677381b2020-01-23 10:04:29 -0600524void addBMCFWVersionIDToJSON(nlohmann::json& json,
525 const DataInterfaceBase& dataIface)
526{
527 auto id = dataIface.getBMCFWVersionID();
528 if (id.empty())
529 {
530 id = unknownValue;
531 }
532
533 json["BMC Version ID"] = std::move(id);
534}
535
Matt Spinler4aa23a12020-02-03 15:05:09 -0600536std::string lastSegment(char separator, std::string data)
537{
538 auto pos = data.find_last_of(separator);
539 if (pos != std::string::npos)
540 {
541 data = data.substr(pos + 1);
542 }
543
544 return data;
545}
546
547void addStatesToJSON(nlohmann::json& json, const DataInterfaceBase& dataIface)
548{
549 json["BMCState"] = lastSegment('.', dataIface.getBMCState());
550 json["ChassisState"] = lastSegment('.', dataIface.getChassisState());
551 json["HostState"] = lastSegment('.', dataIface.getHostState());
552}
553
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600554std::unique_ptr<UserData>
555 makeSysInfoUserDataSection(const AdditionalData& ad,
556 const DataInterfaceBase& dataIface)
557{
558 nlohmann::json json;
559
560 addProcessNameToJSON(json, ad.getValue("_PID"), dataIface);
Matt Spinler677381b2020-01-23 10:04:29 -0600561 addBMCFWVersionIDToJSON(json, dataIface);
Matt Spinler4aa23a12020-02-03 15:05:09 -0600562 addStatesToJSON(json, dataIface);
Matt Spinler4dcd3f42020-01-22 14:55:07 -0600563
564 return makeJSONUserDataSection(json);
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600565}
566
Matt Spinler5b289b22020-03-26 14:27:19 -0500567std::vector<uint8_t> readFD(int fd)
568{
569 std::vector<uint8_t> data;
570
571 // Get the size
572 struct stat s;
573 int r = fstat(fd, &s);
574 if (r != 0)
575 {
576 auto e = errno;
577 log<level::ERR>("Could not get FFDC file size from FD",
578 entry("ERRNO=%d", e));
579 return data;
580 }
581
582 if (0 == s.st_size)
583 {
584 log<level::ERR>("FFDC file is empty");
585 return data;
586 }
587
588 data.resize(s.st_size);
589
590 // Make sure its at the beginning, as maybe another
591 // extension already used it.
592 r = lseek(fd, 0, SEEK_SET);
593 if (r == -1)
594 {
595 auto e = errno;
596 log<level::ERR>("Could not seek to beginning of FFDC file",
597 entry("ERRNO=%d", e));
598 return data;
599 }
600
601 r = read(fd, data.data(), s.st_size);
602 if (r == -1)
603 {
604 auto e = errno;
605 log<level::ERR>("Could not read FFDC file", entry("ERRNO=%d", e));
606 }
607 else if (r != s.st_size)
608 {
609 log<level::WARNING>("Could not read full FFDC file",
610 entry("FILE_SIZE=%d", s.st_size),
611 entry("SIZE_READ=%d", r));
612 }
613
614 return data;
615}
616
Matt Spinler56ad2a02020-03-26 14:00:52 -0500617std::unique_ptr<UserData> makeFFDCuserDataSection(uint16_t componentID,
618 const PelFFDCfile& file)
619{
Matt Spinler5b289b22020-03-26 14:27:19 -0500620 auto data = readFD(file.fd);
621
622 if (data.empty())
623 {
624 return std::unique_ptr<UserData>();
625 }
626
627 // The data needs 4 Byte alignment, and save amount padded for the
628 // CBOR case.
629 uint32_t pad = 0;
630 while (data.size() % 4)
631 {
632 data.push_back(0);
633 pad++;
634 }
635
636 // For JSON, CBOR, and Text use our component ID, subType, and version,
637 // otherwise use the supplied ones.
638 uint16_t compID = static_cast<uint16_t>(ComponentID::phosphorLogging);
639 uint8_t subType{};
640 uint8_t version{};
641
642 switch (file.format)
643 {
644 case UserDataFormat::json:
645 subType = static_cast<uint8_t>(UserDataFormat::json);
646 version = static_cast<uint8_t>(UserDataFormatVersion::json);
647 break;
648 case UserDataFormat::cbor:
649 subType = static_cast<uint8_t>(UserDataFormat::cbor);
650 version = static_cast<uint8_t>(UserDataFormatVersion::cbor);
651
652 // The CBOR parser will fail on the extra pad bytes since they
653 // aren't CBOR. Add the amount we padded to the end and other
654 // code will remove it all before parsing.
655 {
656 data.resize(data.size() + 4);
657 Stream stream{data};
658 stream.offset(data.size() - 4);
659 stream << pad;
660 }
661
662 break;
663 case UserDataFormat::text:
664 subType = static_cast<uint8_t>(UserDataFormat::text);
665 version = static_cast<uint8_t>(UserDataFormatVersion::text);
666 break;
667 case UserDataFormat::custom:
668 default:
669 // Use the passed in values
670 compID = componentID;
671 subType = file.subType;
672 version = file.version;
673 break;
674 }
675
676 return std::make_unique<UserData>(compID, subType, version, data);
Matt Spinler56ad2a02020-03-26 14:00:52 -0500677}
678
Matt Spinlerc7c3e402020-01-22 15:07:25 -0600679} // namespace util
680
Matt Spinlercb6b0592019-07-16 15:58:51 -0500681} // namespace pels
682} // namespace openpower