gator: Version 5.21.1
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / EventsXML.cpp
1 /**
2  * Copyright (C) ARM Limited 2013-2015. All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  */
8
9 #include "EventsXML.h"
10
11 #include "CapturedXML.h"
12 #include "Logging.h"
13 #include "OlyUtility.h"
14 #include "SessionData.h"
15
16 class XMLList {
17 public:
18         XMLList(XMLList *const prev, mxml_node_t *const node) : mPrev(prev), mNode(node) {}
19
20         XMLList *getPrev() { return mPrev; }
21         mxml_node_t *getNode() const { return mNode; }
22         void setNode(mxml_node_t *const node) { mNode = node; }
23
24         static void free(XMLList *list) {
25                 while (list != NULL) {
26                         XMLList *prev = list->getPrev();
27                         delete list;
28                         list = prev;
29                 }
30         }
31
32 private:
33         XMLList *const mPrev;
34         mxml_node_t *mNode;
35
36         // Intentionally unimplemented
37         XMLList(const XMLList &);
38         XMLList &operator=(const XMLList &);
39 };
40
41 mxml_node_t *EventsXML::getTree() {
42 #include "events_xml.h" // defines and initializes char events_xml[] and int events_xml_len
43         char path[PATH_MAX];
44         mxml_node_t *xml = NULL;
45         FILE *fl;
46
47         // Avoid unused variable warning
48         (void)events_xml_len;
49
50         // Load the provided or default events xml
51         if (gSessionData->mEventsXMLPath) {
52                 strncpy(path, gSessionData->mEventsXMLPath, PATH_MAX);
53                 fl = fopen(path, "r");
54                 if (fl) {
55                         xml = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
56                         fclose(fl);
57                 }
58         }
59         if (xml == NULL) {
60                 logg->logMessage("Unable to locate events.xml, using default");
61                 xml = mxmlLoadString(NULL, (const char *)events_xml, MXML_NO_CALLBACK);
62         }
63
64         // Append additional events XML
65         if (gSessionData->mEventsXMLAppend) {
66                 fl = fopen(gSessionData->mEventsXMLAppend, "r");
67                 if (fl == NULL) {
68                         logg->logError("Unable to open additional events XML %s", gSessionData->mEventsXMLAppend);
69                         handleException();
70                 }
71                 mxml_node_t *append = mxmlLoadFile(NULL, fl, MXML_NO_CALLBACK);
72                 fclose(fl);
73
74                 mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
75                 if (!events) {
76                         logg->logError("Unable to find <events> node in the events.xml, please ensure the first two lines of events XML starts with:\n"
77                                        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
78                                        "<events>");
79                         handleException();
80                 }
81
82                 XMLList *categoryList = NULL;
83                 XMLList *eventList = NULL;
84                 {
85                         // Make list of all categories in xml
86                         mxml_node_t *node = xml;
87                         while (true) {
88                                 node = mxmlFindElement(node, xml, "category", NULL, NULL, MXML_DESCEND);
89                                 if (node == NULL) {
90                                         break;
91                                 }
92                                 categoryList = new XMLList(categoryList, node);
93                         }
94
95                         // Make list of all events in xml
96                         node = xml;
97                         while (true) {
98                                 node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
99                                 if (node == NULL) {
100                                         break;
101                                 }
102                                 eventList = new XMLList(eventList, node);
103                         }
104                 }
105
106                 // Handle events
107                 for (mxml_node_t *node = mxmlFindElement(append, append, "event", NULL, NULL, MXML_DESCEND),
108                        *next = mxmlFindElement(node, append, "event", NULL, NULL, MXML_DESCEND);
109                      node != NULL;
110                      node = next, next = mxmlFindElement(node, append, "event", NULL, NULL, MXML_DESCEND)) {
111                         const char *const category = mxmlElementGetAttr(mxmlGetParent(node), "name");
112                         const char *const title = mxmlElementGetAttr(node, "title");
113                         const char *const name = mxmlElementGetAttr(node, "name");
114                         if (category == NULL || title == NULL || name == NULL) {
115                                 logg->logError("Not all event XML nodes have the required title and name and parent name attributes");
116                                 handleException();
117                         }
118
119                         // Replace any duplicate events
120                         for (XMLList *event = eventList; event != NULL; event = event->getPrev()) {
121                                 const char *const category2 = mxmlElementGetAttr(mxmlGetParent(event->getNode()), "name");
122                                 const char *const title2 = mxmlElementGetAttr(event->getNode(), "title");
123                                 const char *const name2 = mxmlElementGetAttr(event->getNode(), "name");
124                                 if (category2 == NULL || title2 == NULL || name2 == NULL) {
125                                         logg->logError("Not all event XML nodes have the required title and name and parent name attributes");
126                                         handleException();
127                                 }
128
129                                 if (strcmp(category, category2) == 0 && strcmp(title, title2) == 0 && strcmp(name, name2) == 0) {
130                                         logg->logMessage("Replacing counter %s %s: %s", category, title, name);
131                                         mxml_node_t *parent = mxmlGetParent(event->getNode());
132                                         mxmlDelete(event->getNode());
133                                         mxmlAdd(parent, MXML_ADD_AFTER, MXML_ADD_TO_PARENT, node);
134                                         event->setNode(node);
135                                         break;
136                                 }
137                         }
138                 }
139
140                 // Handle categories
141                 for (mxml_node_t *node = strcmp(mxmlGetElement(append), "category") == 0 ? append : mxmlFindElement(append, append, "category", NULL, NULL, MXML_DESCEND),
142                        *next = mxmlFindElement(node, append, "category", NULL, NULL, MXML_DESCEND);
143                      node != NULL;
144                      node = next, next = mxmlFindElement(node, append, "category", NULL, NULL, MXML_DESCEND)) {
145                         // After replacing duplicate events, a category may be empty
146                         if (mxmlGetFirstChild(node) == NULL) {
147                                 continue;
148                         }
149
150                         const char *const name = mxmlElementGetAttr(node, "name");
151                         if (name == NULL) {
152                                 logg->logError("Not all event XML categories have the required name attribute");
153                                 handleException();
154                         }
155
156                         // Merge identically named categories
157                         bool merged = false;
158                         for (XMLList *category = categoryList; category != NULL; category = category->getPrev()) {
159                                 const char *const name2 = mxmlElementGetAttr(category->getNode(), "name");
160                                 if (name2 == NULL) {
161                                         logg->logError("Not all event XML categories have the required name attribute");
162                                         handleException();
163                                 }
164
165                                 if (strcmp(name, name2) == 0) {
166                                         logg->logMessage("Merging category %s", name);
167                                         while (true) {
168                                                 mxml_node_t *child = mxmlGetFirstChild(node);
169                                                 if (child == NULL) {
170                                                         break;
171                                                 }
172                                                 mxmlAdd(category->getNode(), MXML_ADD_AFTER, mxmlGetLastChild(category->getNode()), child);
173                                         }
174                                         merged = true;
175                                         break;
176                                 }
177                         }
178
179                         if (merged) {
180                                 continue;
181                         }
182
183                         // Add new categories
184                         logg->logMessage("Appending category %s", name);
185                         mxmlAdd(events, MXML_ADD_AFTER, mxmlGetLastChild(events), node);
186                 }
187
188                 XMLList::free(eventList);
189                 XMLList::free(categoryList);
190
191                 mxmlDelete(append);
192         }
193
194         return xml;
195 }
196
197 char *EventsXML::getXML() {
198         mxml_node_t *xml = getTree();
199
200         // Add dynamic events from the drivers
201         mxml_node_t *events = mxmlFindElement(xml, xml, "events", NULL, NULL, MXML_DESCEND);
202         if (!events) {
203                 logg->logError("Unable to find <events> node in the events.xml, please ensure the first two lines of events XML are:\n"
204                                "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
205                                "<events>");
206                 handleException();
207         }
208         for (Driver *driver = Driver::getHead(); driver != NULL; driver = driver->getNext()) {
209                 driver->writeEvents(events);
210         }
211
212         char *string = mxmlSaveAllocString(xml, mxmlWhitespaceCB);
213         mxmlDelete(xml);
214
215         return string;
216 }
217
218 void EventsXML::write(const char *path) {
219         char file[PATH_MAX];
220
221         // Set full path
222         snprintf(file, PATH_MAX, "%s/events.xml", path);
223
224         char *buf = getXML();
225         if (util->writeToDisk(file, buf) < 0) {
226                 logg->logError("Error writing %s\nPlease verify the path.", file);
227                 handleException();
228         }
229
230         free(buf);
231 }