2 * \file snapshot_parser.cpp
3 * \brief OpenCSD : Snapshot Parser Library
5 * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
9 * Redistribution and use in source and binary forms, with or without modification,
10 * are permitted provided that the following conditions are met:
12 * 1. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * 3. Neither the name of the copyright holder nor the names of its contributors
20 * may be used to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "snapshot_parser.h"
45 #include "snapshot_parser_util.h"
46 #include "ini_section_names.h"
48 using namespace Parser;
52 /*************************************************************************
53 * Note, this file handles the parsring of the general (device specific)
54 * ini file and the (much smaller) device_list file
55 *************************************************************************/
57 namespace ParserPrivate
59 //! Handle CRLF terminators and '#' and ';' comments
60 void CleanLine(string& line)
62 string::size_type endpos = line.find_first_of("\r;#");
63 if (endpos != string::npos)
69 //! Split foo=bar into pair <foo, bar>
70 pair<string, string> SplitKeyValue(const string& kv)
72 string::size_type eq(kv.find('='));
73 if (eq == string::npos)
75 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Couldn't parse '" + kv + "' as key=value");
77 return make_pair(Trim(kv.substr(0, eq)), Trim(kv.substr(eq + 1)));
80 //! Whether line is just tabs and spaces
81 bool IsEmpty(const string& line)
83 return TrimLeft(line) == "";
86 /*! \brief Whether line is of form '[header]'
87 * \param line the line
88 * \param sectionName if function returns true, returns the text between the brackets
90 bool IsSectionHeader(const string& line, string& sectionName)
92 string::size_type openBracket(line.find('['));
93 if (openBracket == string::npos)
97 string::size_type textStart(openBracket + 1);
98 string::size_type closeBracket(line.find(']', textStart));
99 if (closeBracket == string::npos)
103 sectionName.assign(Trim(line.substr(textStart, closeBracket - textStart)));
107 template <class M, class K, class V>
108 void AddUniqueKey(M& m, const K& key, const V& value, const std::string &keyStr )
110 if (!m.insert(make_pair(key, value)).second)
112 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Duplicate key: " + keyStr);
116 void PreventDupes(bool& store, const string& key, const string& section)
120 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE,
121 "Duplicate " + key + " key found in "
122 + section + " section");
129 * \brief Handle an ini file section begun with a section header ([header])
134 virtual ~Section() {}
136 //! Notify a key=value definition
137 virtual void Define(const string& k, const string& v) = 0;
139 //! Notify end of section - we can't handle in dtor because misparses throw.
140 virtual void End() = 0;
143 //! The initial state
144 class NullSection : public Section
147 void Define(const string& k, const string&)
149 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Definition of '" + k + "' has no section header");
154 //! Silently ignore sections that are undefined
155 class IgnoredSection : public Section
158 void Define(const string& , const string&)
164 //! Handle a [global] section.
165 class GlobalSection : public Section
168 GlobalSection(Parsed& result) : m_result(result), m_got_core()
170 if (m_result.foundGlobal)
172 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, string("Only one ") + GlobalSectionName + " section allowed");
174 m_result.foundGlobal = true;
177 void Define(const string& k, const string& v)
181 PreventDupes(m_got_core, CoreKey, GlobalSectionName);
182 m_result.core.assign(v);
186 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Unknown global option '" + k + '\'');
197 //! Handle a [dump] section
198 class DumpSection : public Section
201 DumpSection(Parsed& result)
203 m_got_file(), m_got_address(), m_got_length(), m_got_offset(), m_got_space(),
204 m_address(), m_length(), m_offset(), m_file(), m_space()
207 void Define(const string& k, const string& v)
209 if (k == DumpAddressKey)
211 PreventDupes(m_got_address, DumpAddressKey, DumpFileSectionPrefix);
212 m_address = DecodeUnsigned<uint64_t>(v);
214 else if (k == DumpLengthKey)
216 PreventDupes(m_got_length, DumpLengthKey, DumpFileSectionPrefix);
217 m_length = DecodeUnsigned<size_t>(v);
219 else if (k == DumpOffsetKey)
221 PreventDupes(m_got_offset, DumpOffsetKey, DumpFileSectionPrefix);
222 m_offset = DecodeUnsigned<size_t>(v);
224 else if (k == DumpFileKey)
226 PreventDupes(m_got_file, DumpFileKey, DumpFileSectionPrefix);
227 m_file = Trim(v, "\"'"); // strip quotes
229 else if (k == DumpSpaceKey)
231 PreventDupes(m_got_space, DumpSpaceKey, DumpFileSectionPrefix);
232 m_space = Trim(v, "\"'"); // strip quotes
236 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Unknown dump section key '" + k + '\'');
244 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Dump section is missing mandatory address definition");
248 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Dump section is missing mandatory file definition");
251 struct DumpDef add = { m_address, m_file, m_length, m_offset, m_space};
252 m_result.dumpDefs.push_back(add);
269 //! Handle an [extendregs] section.
270 class ExtendRegsSection : public Section
273 ExtendRegsSection(Parsed& result) : m_result(result)
276 void Define(const string& k, const string& v)
278 AddUniqueKey(m_result.extendRegDefs, DecodeUnsigned<uint32_t>(k), DecodeUnsigned<uint32_t>(v),k);
287 // Handle a [regs] section
288 class SymbolicRegsSection : public Section
291 SymbolicRegsSection(Parsed& result) : m_result(result)
294 void Define(const string& k, const string& v)
296 const string value = Trim(v, "\"'"); // strip quotes
297 AddUniqueKey(m_result.regDefs, k, value,k);
306 // Handle a [device] section
307 class DeviceSection : public Section
310 DeviceSection(Parsed& result) : m_result(result), gotName(false), gotClass(false), gotType(false)
313 void Define(const string& k, const string& v)
315 if (k == DeviceNameKey)
317 PreventDupes(gotName, k, DeviceSectionName);
318 m_result.deviceName = v;
320 else if(k == DeviceClassKey)
322 PreventDupes(gotClass, k, DeviceSectionName);
323 m_result.deviceClass = v;
325 else if(k == DeviceTypeKey)
327 PreventDupes(gotType, k, DeviceSectionName);
328 m_result.deviceTypeName = v;
341 //! Instantiate the appropriate handler for the section name
342 auto_ptr<Section> NewSection( const string& sectionName, Parsed& result)
344 LogInfoStr( "Start of " + sectionName + " section\n");
346 if (sectionName == GlobalSectionName)
348 return auto_ptr<Section>(new GlobalSection(result));
350 if (sectionName.substr(0,DumpFileSectionLen) == DumpFileSectionPrefix)
352 return auto_ptr<Section>(new DumpSection(result));
354 else if (sectionName == ExtendedRegsSectionName)
356 return auto_ptr<Section>(new ExtendRegsSection(result));
358 else if (sectionName == SymbolicRegsSectionName)
360 return auto_ptr<Section>(new SymbolicRegsSection(result));
362 else if (sectionName == DeviceSectionName)
364 return auto_ptr<Section>(new DeviceSection(result));
368 LogInfoStr("Unknown section ignored: " + sectionName + "\n");
369 return auto_ptr<Section>(new IgnoredSection);
373 /***** Device List file parsing *********************/
374 //! Handle a [device_list] section.
375 class DeviceListSection : public Section
378 DeviceListSection(ParsedDevices& result) : m_result(result), nextId(1)
381 void Define(const string& , const string& v)
383 // throw away supplied key - DTSL wants them monotonically increasing from 1
384 std::ostringstream id;
386 m_result.deviceList[id.str()] = v;
392 ParsedDevices& m_result;
396 //! Instantiate the appropriate handler for the section name
397 auto_ptr<Section> NewDeviceList(const string& sectionName, ParsedDevices& result)
399 LogInfoStr("Start of " + sectionName + " section\n");
401 if (sectionName == DeviceListSectionName)
403 return auto_ptr<Section>(new DeviceListSection(result));
407 // ignore unexpected sections, there may be others like [trace]
408 // which RDDI doesn't care about
409 return auto_ptr<Section>(new NullSection);
413 // Handle a [snapshot] section
414 class SnapshotSection : public Section
417 SnapshotSection(SnapshotInfo& result) : m_result(result), m_gotDescription(false), m_gotVersion(false)
420 void Define(const string& k, const string& v)
424 PreventDupes(m_gotVersion, k, SnapshotSectionName);
425 m_result.version = v;
426 // the only valid contents of this are 1.0, as this is the version that introduced the "snapshot" section
427 if (v != "1.0" && v != "1")
428 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Illegal snapshot file version: " + v);
430 else if (k == DescriptionKey)
432 PreventDupes(m_gotDescription, k, SnapshotSectionName);
433 m_result.description = v;
436 SnapshotInfo getSnapshotInfo() { return m_result; }
440 SnapshotInfo &m_result;
441 bool m_gotDescription;
446 //! Instantiate the appropriate handler for the section name
447 auto_ptr<Section> NewSnapshotInfo(const string& sectionName, ParsedDevices& result)
449 LogInfoStr((std::string)"Start of " + sectionName + (std::string)" section\n");
451 if (sectionName == SnapshotSectionName)
453 return auto_ptr<Section>(new SnapshotSection(result.snapshotInfo));
457 // ignore unexpected sections, there may be others like [trace]
458 // which RDDI doesn't care about
459 return auto_ptr<Section>(new NullSection);
463 class TraceSection : public Section
466 TraceSection(ParsedDevices& result) : m_result(result), gotName(false)
469 void Define(const string& k, const string& v)
471 if (k == MetadataKey)
473 PreventDupes(gotName, k, TraceSectionName);
474 m_result.traceMetaDataName = v;
481 ParsedDevices& m_result;
485 //! Instantiate the appropriate handler for the section name
486 auto_ptr<Section> NewTraceMetaData(const string& sectionName, ParsedDevices& result)
488 LogInfoStr((std::string)"Start of " + sectionName + (std::string)" section\n");
490 if (sectionName == TraceSectionName)
492 return auto_ptr<Section>(new TraceSection(result));
496 // ignore unexpected sections, there may be others like [trace]
497 // which RDDI doesn't care about
498 return auto_ptr<Section>(new NullSection);
502 class TraceBufferListSection : public Section
505 TraceBufferListSection(ParsedTrace& result) : m_result(result), gotList(false)
508 void Define(const string& k, const string& v)
510 if (k == BufferListKey)
512 PreventDupes(gotList, k, TraceBuffersSectionName);
513 std::string nameList = v;
514 std::string::size_type pos;
515 while((pos = nameList.find_first_of(',')) != std::string::npos)
517 m_result.buffer_section_names.push_back(nameList.substr(0,pos));
518 nameList=nameList.substr(pos+1,std::string::npos);
520 m_result.buffer_section_names.push_back(nameList);
527 ParsedTrace& m_result;
531 //! Instantiate the appropriate handler for the section name
534 class TraceBufferSection : public Section
537 TraceBufferSection(ParsedTrace& result, const std::string §ionName) : m_result(result), m_sectionName(sectionName),
538 name(""), file(""), format(""), gotName(false), gotFile(false), gotFormat(false)
541 void Define(const string& k, const string& v)
543 if (k == BufferNameKey)
545 PreventDupes(gotName, k, m_sectionName);
548 else if (k == BufferFileKey)
550 PreventDupes(gotFile, k, m_sectionName);
553 else if (k == BufferFormatKey)
555 PreventDupes(gotFormat, k, m_sectionName);
564 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Trace Buffer section missing required buffer name");
568 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Trace Buffer section is missing mandatory file definition");
571 struct TraceBufferInfo info = { name, file, format };
572 m_result.trace_buffers.push_back(info);
577 ParsedTrace& m_result;
578 std::string m_sectionName;
588 class TraceSourceBuffersSection : public Section
591 TraceSourceBuffersSection(ParsedTrace& result) : m_result(result)
594 void Define(const string& k, const string& v)
596 // k is the source name, v is the buffer name
597 m_result.source_buffer_assoc[k] = v;
603 ParsedTrace& m_result;
606 class TraceCpuSourceSection : public Section
609 TraceCpuSourceSection(ParsedTrace& result) : m_result(result)
612 void Define(const string& k, const string& v)
614 // k is the cpu name, v is the source name
615 m_result.cpu_source_assoc[v] = k;
621 ParsedTrace& m_result;
624 auto_ptr<Section> NewTraceSection(const string& sectionName, ParsedTrace& result)
626 LogInfoStr((std::string)"Start of " + sectionName + (std::string)" section\n");
628 if (sectionName == TraceBuffersSectionName)
630 return auto_ptr<Section>(new TraceBufferListSection(result));
632 else if(sectionName == SourceBuffersSectionName)
634 return auto_ptr<Section>(new TraceSourceBuffersSection(result));
636 else if(sectionName == CoreSourcesSectionName)
638 return auto_ptr<Section>(new TraceCpuSourceSection(result));
642 // check the list of buffer sections
643 std::vector<std::string>::iterator it = result.buffer_section_names.begin();
644 bool matchedName = false;
645 while(it != result.buffer_section_names.end())
647 if(sectionName == *it)
649 return auto_ptr<Section>(new TraceBufferSection(result, sectionName));
653 // ignore unexpected sections,
654 return auto_ptr<Section>(new IgnoredSection);
661 using namespace ParserPrivate;
663 Parser::Parsed Parser::ParseSingleDevice(istream& in)
668 auto_ptr<Section> section(new NullSection);
670 while (getline(in, line))
672 CleanLine(line); // remove LF, comments
675 if (IsSectionHeader(line, sectionName))
677 // Section ends with start of next section...
679 section = NewSection(sectionName, result);
681 else if (!IsEmpty(line))
683 if (dynamic_cast<IgnoredSection *>(section.get()) == NULL)
684 { // NOT an ignored section, so process it
685 pair<string, string> kv(SplitKeyValue(line));
686 section->Define(kv.first, kv.second);
690 // ... or end of file
695 Parser::ParsedDevices Parser::ParseDeviceList(istream& in)
697 ParsedDevices result;
698 result.snapshotInfo.description = "";
699 // call the original format 0.0, the device_list format 0.1 and the flexible format (including version) 1.0
700 result.snapshotInfo.version = "0.1";
702 auto_ptr<Section> section(new NullSection);
704 while (getline(in, line))
706 CleanLine(line); // remove LF, comments
709 if (IsSectionHeader(line, sectionName))
711 // Section ends with start of next section...
714 if (sectionName == SnapshotSectionName)
715 section = NewSnapshotInfo(sectionName, result);
716 else if(sectionName == TraceSectionName)
717 section = NewTraceMetaData(sectionName, result);
718 else // else rather than elseif for closer compatibility with old tests
719 section = NewDeviceList(sectionName, result);
721 else if (!IsEmpty(line) &&
722 ( dynamic_cast<DeviceListSection *>(section.get()) != NULL ||
723 dynamic_cast<SnapshotSection *>(section.get()) != NULL ||
724 dynamic_cast<TraceSection *>(section.get()) != NULL
728 pair<string, string> kv(SplitKeyValue(line));
729 section->Define(kv.first, kv.second);
732 // ... or end of file
739 // parse the trace metadata ini file.
740 ParsedTrace Parser::ParseTraceMetaData(std::istream& in)
745 auto_ptr<Section> section(new NullSection);
747 while (getline(in, line))
749 CleanLine(line); // remove LF, comments
752 if (IsSectionHeader(line, sectionName))
754 // Section ends with start of next section...
756 section = NewTraceSection(sectionName, result);
758 else if (!IsEmpty(line))
760 if (dynamic_cast<IgnoredSection *>(section.get()) == NULL)
761 { // NOT an ignored section, so process it
762 pair<string, string> kv(SplitKeyValue(line));
763 section->Define(kv.first, kv.second);
767 // ... or end of file
772 // build a source tree for a single buffer
773 bool Parser::ExtractSourceTree(const std::string &buffer_name, ParsedTrace &metadata, TraceBufferSourceTree &buffer_data)
775 bool bFoundbuffer = false;
776 std::vector<TraceBufferInfo>::iterator it = metadata.trace_buffers.begin();
778 while((it != metadata.trace_buffers.end()) && !bFoundbuffer)
780 if(it->bufferName == buffer_name)
783 buffer_data.buffer_info = *it;
790 std::map<std::string, std::string>::iterator sbit = metadata.source_buffer_assoc.begin();
791 while(sbit != metadata.source_buffer_assoc.end())
793 if(sbit->second == buffer_data.buffer_info.bufferName)
795 // found a source in this buffer...
796 buffer_data.source_core_assoc[sbit->first] = metadata.cpu_source_assoc[sbit->first];
804 std::vector<std::string> Parser::GetBufferNameList(ParsedTrace &metadata)
806 std::vector<std::string> nameList;
807 std::vector<TraceBufferInfo>::iterator it = metadata.trace_buffers.begin();
808 while(it != metadata.trace_buffers.end())
810 nameList.push_back(it->bufferName);
816 void Parser::SetIErrorLogger(ITraceErrorLog *i_err_log)
818 s_pErrorLogger = i_err_log;
821 s_errlog_handle = s_pErrorLogger->RegisterErrorSource("snapshot_parser");
825 ITraceErrorLog *Parser::GetIErrorLogger()
827 return s_pErrorLogger;
830 void Parser::LogInfoStr(const std::string &logMsg)
832 if(GetIErrorLogger() && s_verbose_logging)
833 GetIErrorLogger()->LogMessage(s_errlog_handle,OCSD_ERR_SEV_INFO,logMsg);
836 void Parser::SetVerboseLogging(bool verbose)
838 s_verbose_logging = verbose;
840 /* End of File snapshot_parser.cpp */