1 /*
2  * \file       snapshot_parser.cpp
3  * \brief      OpenCSD : Snapshot Parser Library
4  *
5  * \copyright  Copyright (c) 2015, ARM Limited. All Rights Reserved.
6  */
7 
8 /*
9  * Redistribution and use in source and binary forms, with or without modification,
10  * are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
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.
18  *
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.
22  *
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.
33  */
34 
35 #include "snapshot_parser.h"
36 
37 #include <memory>
38 #include <algorithm>
39 #include <istream>
40 #include <iostream>
41 #include <string>
42 #include <utility>
43 using namespace std;
44 
45 #include "snapshot_parser_util.h"
46 #include "ini_section_names.h"
47 using namespace Util;
48 using namespace Parser;
49 
50 #include "opencsd.h"
51 
52 /*************************************************************************
53  * Note, this file handles the parsring of the general (device specific)
54  * ini file and the (much smaller) device_list file
55  *************************************************************************/
56 
57 namespace ParserPrivate
58 {
59     //! Handle CRLF terminators and '#' and ';' comments
CleanLine(string & line)60     void CleanLine(string& line)
61     {
62         string::size_type endpos = line.find_first_of("\r;#");
63         if (endpos != string::npos)
64         {
65             line.erase(endpos);
66         }
67     }
68 
69     //! Split foo=bar into pair <foo, bar>
SplitKeyValue(const string & kv)70     pair<string, string> SplitKeyValue(const string& kv)
71     {
72         string::size_type eq(kv.find('='));
73         if (eq == string::npos)
74         {
75             throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Couldn't parse '" + kv + "' as key=value");
76         }
77         return make_pair(Trim(kv.substr(0, eq)), Trim(kv.substr(eq + 1)));
78     }
79 
80     //! Whether line is just tabs and spaces
IsEmpty(const string & line)81     bool IsEmpty(const string& line)
82     {
83         return TrimLeft(line) == "";
84     }
85 
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
89      */
IsSectionHeader(const string & line,string & sectionName)90     bool IsSectionHeader(const string& line, string& sectionName)
91     {
92         string::size_type openBracket(line.find('['));
93         if (openBracket == string::npos)
94         {
95             return false;
96         }
97         string::size_type textStart(openBracket + 1);
98         string::size_type closeBracket(line.find(']', textStart));
99         if (closeBracket == string::npos)
100         {
101             return false;
102         }
103         sectionName.assign(Trim(line.substr(textStart, closeBracket - textStart)));
104         return true;
105     }
106 
107     template <class M, class K, class V>
AddUniqueKey(M & m,const K & key,const V & value,const std::string & keyStr)108     void AddUniqueKey(M& m, const K& key, const V& value, const std::string &keyStr )
109     {
110         if (!m.insert(make_pair(key, value)).second)
111         {
112             throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE,  "Duplicate key: " + keyStr);
113         }
114     }
115 
PreventDupes(bool & store,const string & key,const string & section)116     void PreventDupes(bool& store, const string& key, const string& section)
117     {
118         if (store)
119         {
120             throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE,
121                 "Duplicate " + key + " key found in "
122                 + section + " section");
123         }
124         store = true;
125     }
126 
127 
128     /*! \class Section
129      *  \brief Handle an ini file section begun with a section header ([header])
130      */
131     class Section
132     {
133     public:
~Section()134         virtual ~Section() {}
135 
136         //! Notify a key=value definition
137         virtual void Define(const string& k, const string& v) = 0;
138 
139         //! Notify end of section - we can't handle in dtor because misparses throw.
140         virtual void End() = 0;
141     };
142 
143     //! The initial state
144     class NullSection : public Section
145     {
146     public:
Define(const string & k,const string &)147         void Define(const string& k, const string&)
148         {
149             throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE,  "Definition of '" + k + "' has no section header");
150         }
End()151         void End() {}
152     };
153 
154     //! Silently ignore sections that are undefined
155     class IgnoredSection : public Section
156     {
157     public:
Define(const string &,const string &)158         void Define(const string& , const string&)
159         {
160         }
End()161         void End() {}
162     };
163 
164     //! Handle a [global] section.
165     class GlobalSection : public Section
166     {
167     public:
GlobalSection(Parsed & result)168         GlobalSection(Parsed& result) : m_result(result), m_got_core()
169         {
170             if (m_result.foundGlobal)
171             {
172                 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE,  string("Only one ") + GlobalSectionName + " section allowed");
173             }
174             m_result.foundGlobal = true;
175         }
176 
Define(const string & k,const string & v)177         void Define(const string& k, const string& v)
178         {
179             if (k == CoreKey)
180             {
181                 PreventDupes(m_got_core, CoreKey, GlobalSectionName);
182                 m_result.core.assign(v);
183             }
184             else
185             {
186                 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Unknown global option '" + k + '\'');
187             }
188         }
189 
End()190         void End() {}
191 
192     private:
193         Parsed&     m_result;
194         bool        m_got_core;
195     };
196 
197     //! Handle a [dump] section
198     class DumpSection : public Section
199     {
200     public:
DumpSection(Parsed & result)201         DumpSection(Parsed& result)
202           : m_result(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()
205         {}
206 
Define(const string & k,const string & v)207         void Define(const string& k, const string& v)
208         {
209             if (k == DumpAddressKey)
210             {
211                 PreventDupes(m_got_address, DumpAddressKey, DumpFileSectionPrefix);
212                 m_address = DecodeUnsigned<uint64_t>(v);
213             }
214             else if (k == DumpLengthKey)
215             {
216                 PreventDupes(m_got_length, DumpLengthKey, DumpFileSectionPrefix);
217                 m_length = DecodeUnsigned<size_t>(v);
218             }
219             else if (k == DumpOffsetKey)
220             {
221                 PreventDupes(m_got_offset, DumpOffsetKey, DumpFileSectionPrefix);
222                 m_offset = DecodeUnsigned<size_t>(v);
223             }
224             else if (k == DumpFileKey)
225             {
226                 PreventDupes(m_got_file, DumpFileKey, DumpFileSectionPrefix);
227                 m_file = Trim(v, "\"'"); // strip quotes
228             }
229             else if (k == DumpSpaceKey)
230             {
231                 PreventDupes(m_got_space, DumpSpaceKey, DumpFileSectionPrefix);
232                 m_space = Trim(v, "\"'"); // strip quotes
233             }
234             else
235             {
236                 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE,  "Unknown dump section key '" + k + '\'');
237             }
238         }
239 
End()240         void End()
241         {
242             if (!m_got_address)
243             {
244                 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE,  "Dump section is missing mandatory address definition");
245             }
246             if (!m_got_file)
247             {
248                 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Dump section is missing mandatory file definition");
249             }
250 
251             struct DumpDef add = { m_address, m_file, m_length, m_offset, m_space};
252             m_result.dumpDefs.push_back(add);
253         }
254 
255     private:
256         Parsed&     m_result;
257         bool        m_got_file;
258         bool        m_got_address;
259         bool        m_got_length;
260         bool        m_got_offset;
261         bool        m_got_space;
262         uint64_t      m_address;
263         size_t      m_length;
264         size_t      m_offset;
265         string      m_file;
266         string      m_space;
267     };
268 
269     //! Handle an [extendregs] section.
270     class ExtendRegsSection : public Section
271     {
272     public:
ExtendRegsSection(Parsed & result)273         ExtendRegsSection(Parsed& result) : m_result(result)
274         {}
275 
Define(const string & k,const string & v)276         void Define(const string& k, const string& v)
277         {
278             AddUniqueKey(m_result.extendRegDefs, DecodeUnsigned<uint32_t>(k), DecodeUnsigned<uint32_t>(v),k);
279         }
280 
End()281         void End() {}
282 
283     private:
284         Parsed&     m_result;
285     };
286 
287     // Handle a [regs] section
288     class SymbolicRegsSection : public Section
289     {
290     public:
SymbolicRegsSection(Parsed & result)291         SymbolicRegsSection(Parsed& result) : m_result(result)
292         {}
293 
Define(const string & k,const string & v)294         void Define(const string& k, const string& v)
295         {
296             const string value = Trim(v, "\"'"); // strip quotes
297             AddUniqueKey(m_result.regDefs, k, value,k);
298         }
299 
End()300         void End() {}
301 
302     private:
303         Parsed&     m_result;
304     };
305 
306     // Handle a [device] section
307     class DeviceSection : public Section
308     {
309     public:
DeviceSection(Parsed & result)310         DeviceSection(Parsed& result) : m_result(result), gotName(false),  gotClass(false), gotType(false)
311         {}
312 
Define(const string & k,const string & v)313         void Define(const string& k, const string& v)
314         {
315             if (k == DeviceNameKey)
316             {
317                 PreventDupes(gotName, k, DeviceSectionName);
318                 m_result.deviceName = v;
319             }
320             else if(k == DeviceClassKey)
321             {
322                 PreventDupes(gotClass, k, DeviceSectionName);
323                 m_result.deviceClass = v;
324             }
325             else if(k == DeviceTypeKey)
326             {
327                 PreventDupes(gotType, k, DeviceSectionName);
328                 m_result.deviceTypeName = v;
329             }
330         }
331 
End()332         void End() {}
333 
334     private:
335         Parsed&     m_result;
336         bool        gotName;
337         bool        gotClass;
338         bool        gotType;
339     };
340 
341     //! Instantiate the appropriate handler for the section name
NewSection(const string & sectionName,Parsed & result)342     auto_ptr<Section> NewSection( const string& sectionName, Parsed& result)
343     {
344         LogInfoStr( "Start of " + sectionName + " section\n");
345 
346         if (sectionName == GlobalSectionName)
347         {
348             return auto_ptr<Section>(new GlobalSection(result));
349         }
350         if (sectionName.substr(0,DumpFileSectionLen) == DumpFileSectionPrefix)
351         {
352             return auto_ptr<Section>(new DumpSection(result));
353         }
354         else if (sectionName == ExtendedRegsSectionName)
355         {
356             return auto_ptr<Section>(new ExtendRegsSection(result));
357         }
358         else if (sectionName == SymbolicRegsSectionName)
359         {
360             return auto_ptr<Section>(new SymbolicRegsSection(result));
361         }
362         else if (sectionName == DeviceSectionName)
363         {
364             return auto_ptr<Section>(new DeviceSection(result));
365         }
366         else
367         {
368             LogInfoStr("Unknown section ignored: " + sectionName + "\n");
369             return auto_ptr<Section>(new IgnoredSection);
370         }
371     }
372 
373     /***** Device List file parsing *********************/
374     //! Handle a [device_list] section.
375     class DeviceListSection : public Section
376     {
377     public:
DeviceListSection(ParsedDevices & result)378         DeviceListSection(ParsedDevices& result) : m_result(result), nextId(1)
379         {}
380 
Define(const string &,const string & v)381         void Define(const string& , const string& v)
382         {
383             // throw away supplied key - DTSL wants them monotonically increasing from 1
384             std::ostringstream id;
385             id << nextId++;
386             m_result.deviceList[id.str()] = v;
387         }
388 
End()389         void End() {}
390 
391     private:
392         ParsedDevices&   m_result;
393         uint32_t           nextId;
394     };
395 
396     //! Instantiate the appropriate handler for the section name
NewDeviceList(const string & sectionName,ParsedDevices & result)397     auto_ptr<Section> NewDeviceList(const string& sectionName, ParsedDevices& result)
398     {
399         LogInfoStr("Start of " + sectionName + " section\n");
400 
401         if (sectionName == DeviceListSectionName)
402         {
403             return auto_ptr<Section>(new DeviceListSection(result));
404         }
405         else
406         {
407             // ignore unexpected sections, there may be others like [trace]
408             // which RDDI doesn't care about
409             return auto_ptr<Section>(new NullSection);
410         }
411     }
412 
413     // Handle a [snapshot] section
414     class SnapshotSection : public Section
415     {
416     public:
SnapshotSection(SnapshotInfo & result)417         SnapshotSection(SnapshotInfo& result) : m_result(result), m_gotDescription(false), m_gotVersion(false)
418         {}
419 
Define(const string & k,const string & v)420         void Define(const string& k, const string& v)
421         {
422             if (k == VersionKey)
423             {
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);
429             }
430             else if (k == DescriptionKey)
431             {
432                 PreventDupes(m_gotDescription, k, SnapshotSectionName);
433                 m_result.description = v;
434             }
435         }
getSnapshotInfo()436         SnapshotInfo getSnapshotInfo() { return m_result; }
End()437         void End() {}
438 
439     private:
440         SnapshotInfo &m_result;
441         bool        m_gotDescription;
442         bool        m_gotVersion;
443 
444     };
445 
446     //! Instantiate the appropriate handler for the section name
NewSnapshotInfo(const string & sectionName,ParsedDevices & result)447     auto_ptr<Section> NewSnapshotInfo(const string& sectionName, ParsedDevices& result)
448     {
449         LogInfoStr((std::string)"Start of " + sectionName + (std::string)" section\n");
450 
451         if (sectionName == SnapshotSectionName)
452         {
453             return auto_ptr<Section>(new SnapshotSection(result.snapshotInfo));
454         }
455         else
456         {
457             // ignore unexpected sections, there may be others like [trace]
458             // which RDDI doesn't care about
459             return auto_ptr<Section>(new NullSection);
460         }
461     };
462 
463     class TraceSection : public Section
464     {
465     public:
TraceSection(ParsedDevices & result)466         TraceSection(ParsedDevices& result) : m_result(result), gotName(false)
467         {}
468 
Define(const string & k,const string & v)469         void Define(const string& k, const string& v)
470         {
471             if (k == MetadataKey)
472             {
473                 PreventDupes(gotName, k, TraceSectionName);
474                 m_result.traceMetaDataName = v;
475             }
476         }
477 
End()478         void End() {}
479 
480     private:
481         ParsedDevices&     m_result;
482         bool               gotName;
483     };
484 
485     //! Instantiate the appropriate handler for the section name
NewTraceMetaData(const string & sectionName,ParsedDevices & result)486     auto_ptr<Section> NewTraceMetaData(const string& sectionName, ParsedDevices& result)
487     {
488         LogInfoStr((std::string)"Start of " + sectionName + (std::string)" section\n");
489 
490         if (sectionName == TraceSectionName)
491         {
492             return auto_ptr<Section>(new TraceSection(result));
493         }
494         else
495         {
496             // ignore unexpected sections, there may be others like [trace]
497             // which RDDI doesn't care about
498             return auto_ptr<Section>(new NullSection);
499         }
500     };
501 
502     class TraceBufferListSection : public Section
503     {
504     public:
TraceBufferListSection(ParsedTrace & result)505         TraceBufferListSection(ParsedTrace& result) : m_result(result), gotList(false)
506         {}
507 
Define(const string & k,const string & v)508         void Define(const string& k, const string& v)
509         {
510             if (k == BufferListKey)
511             {
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)
516                 {
517                     m_result.buffer_section_names.push_back(nameList.substr(0,pos));
518                     nameList=nameList.substr(pos+1,std::string::npos);
519                 }
520                 m_result.buffer_section_names.push_back(nameList);
521             }
522         }
523 
End()524         void End() {}
525 
526     private:
527         ParsedTrace&     m_result;
528         bool             gotList;
529     };
530 
531     //! Instantiate the appropriate handler for the section name
532 
533 
534     class TraceBufferSection : public Section
535     {
536     public:
TraceBufferSection(ParsedTrace & result,const std::string & sectionName)537         TraceBufferSection(ParsedTrace& result, const std::string &sectionName) : m_result(result), m_sectionName(sectionName),
538             name(""), file(""), format(""), gotName(false), gotFile(false), gotFormat(false)
539         {}
540 
Define(const string & k,const string & v)541         void Define(const string& k, const string& v)
542         {
543             if (k == BufferNameKey)
544             {
545                 PreventDupes(gotName, k, m_sectionName);
546                 name = v;
547             }
548             else if (k == BufferFileKey)
549             {
550                 PreventDupes(gotFile, k, m_sectionName);
551                 file = v;
552             }
553             else if (k == BufferFormatKey)
554             {
555                 PreventDupes(gotFormat, k, m_sectionName);
556                 format = v;
557             }
558         }
559 
End()560         void End()
561         {
562             if (!gotName)
563             {
564                 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE,  "Trace Buffer section missing required buffer name");
565             }
566             if (!gotFile)
567             {
568                 throw ocsdError(OCSD_ERR_SEV_ERROR, OCSD_ERR_TEST_SNAPSHOT_PARSE, "Trace Buffer section is missing mandatory file definition");
569             }
570 
571             struct TraceBufferInfo info = { name, file, format };
572             m_result.trace_buffers.push_back(info);
573         }
574 
575 
576     private:
577         ParsedTrace&     m_result;
578         std::string m_sectionName;
579         std::string name;
580         bool gotName;
581         std::string file;
582         bool gotFile;
583         std::string format;
584         bool gotFormat;
585 
586     };
587 
588     class TraceSourceBuffersSection : public Section
589     {
590     public:
TraceSourceBuffersSection(ParsedTrace & result)591         TraceSourceBuffersSection(ParsedTrace& result) : m_result(result)
592         {}
593 
Define(const string & k,const string & v)594         void Define(const string& k, const string& v)
595         {
596             // k is the source name, v is the buffer name
597             m_result.source_buffer_assoc[k] = v;
598         }
599 
End()600         void End() {}
601 
602     private:
603         ParsedTrace&     m_result;
604     };
605 
606     class TraceCpuSourceSection : public Section
607     {
608     public:
TraceCpuSourceSection(ParsedTrace & result)609         TraceCpuSourceSection(ParsedTrace& result) : m_result(result)
610         {}
611 
Define(const string & k,const string & v)612         void Define(const string& k, const string& v)
613         {
614             // k is the cpu name, v is the source name
615             m_result.cpu_source_assoc[v] = k;
616         }
617 
End()618         void End() {}
619 
620     private:
621         ParsedTrace&     m_result;
622     };
623 
NewTraceSection(const string & sectionName,ParsedTrace & result)624     auto_ptr<Section> NewTraceSection(const string& sectionName, ParsedTrace& result)
625     {
626         LogInfoStr((std::string)"Start of " + sectionName + (std::string)" section\n");
627 
628         if (sectionName == TraceBuffersSectionName)
629         {
630             return auto_ptr<Section>(new TraceBufferListSection(result));
631         }
632         else if(sectionName == SourceBuffersSectionName)
633         {
634             return auto_ptr<Section>(new TraceSourceBuffersSection(result));
635         }
636         else if(sectionName == CoreSourcesSectionName)
637         {
638             return auto_ptr<Section>(new  TraceCpuSourceSection(result));
639         }
640         else
641         {
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())
646             {
647                 if(sectionName == *it)
648                 {
649                     return auto_ptr<Section>(new TraceBufferSection(result, sectionName));
650                 }
651                 it++;
652             }
653             // ignore unexpected sections,
654             return auto_ptr<Section>(new IgnoredSection);
655         }
656     };
657 
658 
659 }
660 
661 using namespace ParserPrivate;
662 
ParseSingleDevice(istream & in)663 Parser::Parsed Parser::ParseSingleDevice(istream& in)
664 {
665     Parsed result;
666 
667     string line;
668     auto_ptr<Section> section(new NullSection);
669 
670     while (getline(in, line))
671     {
672         CleanLine(line); // remove LF, comments
673         string sectionName;
674 
675         if (IsSectionHeader(line, sectionName))
676         {
677             // Section ends with start of next section...
678             section->End();
679             section = NewSection(sectionName, result);
680         }
681         else if (!IsEmpty(line))
682         {
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);
687             }
688         }
689     }
690     // ... or end of file
691     section->End();
692     return result;
693 }
694 
ParseDeviceList(istream & in)695 Parser::ParsedDevices Parser::ParseDeviceList(istream& in)
696 {
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";
701     string line;
702     auto_ptr<Section> section(new NullSection);
703 
704     while (getline(in, line))
705     {
706         CleanLine(line); // remove LF, comments
707         string sectionName;
708 
709         if (IsSectionHeader(line, sectionName))
710         {
711             // Section ends with start of next section...
712             section->End();
713 
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);
720         }
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
725                     )
726                 )
727         {
728             pair<string, string> kv(SplitKeyValue(line));
729             section->Define(kv.first, kv.second);
730         }
731     }
732     // ... or end of file
733     section->End();
734 
735     return result;
736 }
737 
738 
739 // parse the trace metadata ini file.
ParseTraceMetaData(std::istream & in)740 ParsedTrace Parser::ParseTraceMetaData(std::istream& in)
741 {
742     ParsedTrace result;
743 
744     string line;
745     auto_ptr<Section> section(new NullSection);
746 
747     while (getline(in, line))
748     {
749         CleanLine(line); // remove LF, comments
750         string sectionName;
751 
752         if (IsSectionHeader(line, sectionName))
753         {
754             // Section ends with start of next section...
755             section->End();
756             section = NewTraceSection(sectionName, result);
757         }
758         else if (!IsEmpty(line))
759         {
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);
764             }
765         }
766     }
767     // ... or end of file
768     section->End();
769     return result;
770 }
771 
772     // build a source tree for a single buffer
ExtractSourceTree(const std::string & buffer_name,ParsedTrace & metadata,TraceBufferSourceTree & buffer_data)773 bool Parser::ExtractSourceTree(const std::string &buffer_name, ParsedTrace &metadata, TraceBufferSourceTree &buffer_data)
774 {
775     bool bFoundbuffer = false;
776     std::vector<TraceBufferInfo>::iterator it = metadata.trace_buffers.begin();
777 
778     while((it != metadata.trace_buffers.end()) && !bFoundbuffer)
779     {
780         if(it->bufferName == buffer_name)
781         {
782             bFoundbuffer = true;
783             buffer_data.buffer_info = *it;
784         }
785         it++;
786     }
787 
788     if(bFoundbuffer)
789     {
790         std::map<std::string, std::string>::iterator sbit = metadata.source_buffer_assoc.begin();
791         while(sbit != metadata.source_buffer_assoc.end())
792         {
793             if(sbit->second == buffer_data.buffer_info.bufferName)
794             {
795                 // found a source in this buffer...
796                 buffer_data.source_core_assoc[sbit->first] = metadata.cpu_source_assoc[sbit->first];
797             }
798             sbit++;
799         }
800     }
801     return bFoundbuffer;
802 }
803 
GetBufferNameList(ParsedTrace & metadata)804 std::vector<std::string> Parser::GetBufferNameList(ParsedTrace &metadata)
805 {
806     std::vector<std::string> nameList;
807     std::vector<TraceBufferInfo>::iterator it = metadata.trace_buffers.begin();
808     while(it != metadata.trace_buffers.end())
809     {
810         nameList.push_back(it->bufferName);
811         it++;
812     }
813     return nameList;
814 }
815 
SetIErrorLogger(ITraceErrorLog * i_err_log)816 void Parser::SetIErrorLogger(ITraceErrorLog *i_err_log)
817 {
818     s_pErrorLogger = i_err_log;
819     if(s_pErrorLogger)
820     {
821         s_errlog_handle = s_pErrorLogger->RegisterErrorSource("snapshot_parser");
822     }
823 }
824 
GetIErrorLogger()825 ITraceErrorLog *Parser::GetIErrorLogger()
826 {
827     return s_pErrorLogger;
828 }
829 
LogInfoStr(const std::string & logMsg)830 void Parser::LogInfoStr(const std::string &logMsg)
831 {
832     if(GetIErrorLogger() && s_verbose_logging)
833         GetIErrorLogger()->LogMessage(s_errlog_handle,OCSD_ERR_SEV_INFO,logMsg);
834 }
835 
SetVerboseLogging(bool verbose)836 void Parser::SetVerboseLogging(bool verbose)
837 {
838     s_verbose_logging = verbose;
839 }
840 /* End of File snapshot_parser.cpp */
841