ETISS 0.11.2
ExtendableTranslatingInstructionSetSimulator(version0.11.2)
Loading...
Searching...
No Matches
Fault.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: BSD-3-Clause
2//
3// This file is part of ETISS. It is licensed under the BSD 3-Clause License; you may not use this file except in
4// compliance with the License. You should have received a copy of the license along with this project. If not, see the
5// LICENSE file.
6
7#ifndef NO_ETISS
8#include "etiss/fault/XML.h"
9#include "etiss/fault/Fault.h"
10#include "etiss/fault/Trigger.h"
11#include "etiss/fault/Action.h"
15#include "pugixml.hpp"
16#include "etiss/Format.h"
17#else
18#include "fault/XML.h"
19#include "fault/Fault.h"
20#include "fault/Trigger.h"
21#include "fault/Action.h"
22#include "fault/Injector.h"
24#include "fault/Stressor.h"
25#include "pugixml.hpp"
26#endif
27
28#if MUTEX_SUPPORTED
29#include <mutex>
30#endif
31
32#if CXX0X_UP_SUPPORTED == 0
33#define static_assert(x, y)
34#endif
35
36namespace etiss
37{
38namespace fault
39{
40
41// Helper for XML parsing and generating
42namespace xml
43{
44
83static bool getAttribute(const pugi::xml_node &node, const std::string &attr_name, std::string &dst, Diagnostics &diag)
84{
85 bool first = true;
86 for (pugi::xml_attribute attr = node.first_attribute(); attr; attr = attr.next_attribute())
87 {
88 if (hasName(attr, attr_name))
89 {
90 if (first)
91 {
92 dst = attr.value();
93 first = false;
94 }
95 else
96 {
97 diag.unexpectedNode(node, std::string("Duplicated attribute: ") + attr_name);
98 }
99 }
100 }
101 return !first;
102}
103static bool setAttribute(pugi::xml_node &node, const std::string &attr_name, const std::string &src, Diagnostics &diag)
104{
105 node.append_attribute(attr_name.c_str()).set_value(src.c_str());
106 return true;
107}
108static bool getAttribute(const pugi::xml_node &node, const std::string &attr_name, int32_t &dst, Diagnostics &diag)
109{
110 std::string val;
111 if (!getAttribute(node, attr_name, val, diag))
112 return false;
113 std::stringstream(val) >> dst;
114 return true;
115}
116static bool setAttribute(pugi::xml_node &node, const std::string &attr_name, const int32_t &src, Diagnostics &diag)
117{
118 static_assert(sizeof(int32_t) <= sizeof(long long),
119 "pugixml cannot handle int32_t natively. custom string conversion required");
120 node.append_attribute(attr_name.c_str()).set_value((long long)src);
121 return true;
122}
123
124template <>
125bool parse<std::vector<etiss::fault::Fault>>(pugi::xml_node node, std::vector<etiss::fault::Fault> &dst,
126 Diagnostics &diag)
127{
128 etiss::log(etiss::VERBOSE, std::string("etiss::fault::xml::parse<std::vector<etiss::fault::Fault") +
129 std::string("> >(node, vector<Fault>, Diagnostics) called. "));
130
131 bool ret = true;
132 for (pugi::xml_node cnode = node.first_child(); cnode; cnode = cnode.next_sibling())
133 {
134 if (hasName(cnode, "fault"))
135 { // handle fault node
136 Fault f;
137 if (parse<etiss::fault::Fault>(cnode, f, diag))
138 {
139 dst.push_back(f);
140 }
141 else
142 {
143 ret = false;
144 }
145 }
146 else
147 {
148 diag.ignoredNode(cnode, "non \"fault\" node in fault list.");
149 }
150 }
151 return ret;
152}
153
154template <>
155bool write<std::vector<etiss::fault::Fault>>(pugi::xml_node node, const std::vector<etiss::fault::Fault> &src,
156 Diagnostics &diag)
157{
158 etiss::log(etiss::VERBOSE, std::string("etiss::fault::xml::write<std::vector<etiss::fault::Fault") +
159 std::string("> >(node, vector<Fault>, Diagnostics) called. "));
160
161 bool ret = true;
162 for (size_t i = 0; i < src.size(); ++i)
163 {
164 ret = ret && write(node.append_child("fault"), src[i], diag);
165 }
166 return ret;
167}
168
169template <>
170bool parse<std::vector<etiss::fault::FaultRef>>(pugi::xml_node node, std::vector<etiss::fault::FaultRef> &dst,
171 Diagnostics &diag)
172{
173 etiss::log(etiss::VERBOSE, std::string("etiss::fault::xml::parse<std::vector<etiss::fault::FaultRef") +
174 std::string("> >(node, vector<FaultRef>, Diagnostics) called. "));
175
176 bool ret = true;
177 for (pugi::xml_node cnode = node.first_child(); cnode; cnode = cnode.next_sibling())
178 {
179 if (hasName(cnode, "fault_ref"))
180 { // handle fault node
181 FaultRef f;
182 if (parse<etiss::fault::FaultRef>(cnode, f, diag))
183 {
184 dst.push_back(f);
185 }
186 else
187 {
188 ret = false;
189 }
190 }
191 else
192 {
193 diag.ignoredNode(cnode, "non \"fault_ref\" node in list.");
194 }
195 }
196 return ret;
197}
198
199template <>
200bool write<std::vector<etiss::fault::FaultRef>>(pugi::xml_node node, const std::vector<etiss::fault::FaultRef> &src,
201 Diagnostics &diag)
202{
203 etiss::log(etiss::VERBOSE, std::string("etiss::fault::xml::write<std::vector<etiss::fault::FaultRef") +
204 std::string("> >(node, vector<FaultRef>, Diagnostics) called. "));
205
206 bool ret = true;
207 for (size_t i = 0; i < src.size(); ++i)
208 {
209 ret = ret && write(node.append_child("fault_ref"), src[i], diag);
210 }
211 return ret;
212}
213
214} // namespace xml
215
216// generates a unique ID for a new Fault
218{
219#if MUTEX_SUPPORTED
220 static std::mutex mu;
221 std::lock_guard<std::mutex> lock(mu);
222#endif
223 static int32_t cid = -1;
224 return cid--;
225}
226
228{
229 etiss::log(etiss::VERBOSE, std::string("etiss::fault::Fault::Fault() called. "));
230}
231
232Fault::Fault(int nullid) : id_(nullid) {}
233
234std::string Fault::toString() const
235{
236
237 pugi::xml_document doc;
238 doc.load_string("<?xml version=\"1.0\"?>");
239
240 etiss::fault::xml::Diagnostics diag;
241
242 etiss::fault::xml::write<etiss::fault::Fault>(doc.append_child("fault"), *this, diag);
243
244 std::stringstream ss;
245
246 doc.save(ss);
247
248 return ss.str();
249}
250
252{
253 etiss::log(etiss::VERBOSE, fmt::format("etiss::fault::Fault::resolveTime(time={:d}) called.", time));
254 for (std::vector<Trigger>::iterator iter = triggers.begin(); iter != triggers.end(); ++iter)
255 {
256 iter->resolveTime(time);
257 }
258}
260{
261 for (std::vector<Trigger>::const_iterator iter = triggers.begin(); iter != triggers.end(); ++iter)
262 {
263 if (!iter->isResolved())
264 return false;
265 }
266 return true;
267}
268
269std::string FaultRef::toString() const
270{
271
272 pugi::xml_document doc;
273 doc.load_string("<?xml version=\"1.0\"?>");
274
275 etiss::fault::xml::Diagnostics diag;
276
277 etiss::fault::xml::write<etiss::fault::FaultRef>(doc.append_child("fault_ref"), *this, diag);
278
279 std::stringstream ss;
280
281 doc.save(ss);
282
283 return ss.str();
284}
285
286bool FaultRef::set_fault_reference(const std::string &identifier)
287{
288 name_ = identifier;
289
290 return (resolve_reference());
291}
292
294{
295 for (auto const &it : Stressor::faults())
296 {
297 if (it.second.name_ == name_)
298 {
299 fault_ = it.second;
300 return true;
301 }
302 }
303
304 return false;
305}
306
307#if ETISS_FAULT_XML
308
309bool parseXML(std::vector<Fault> &vec, const pugi::xml_document &doc, xml::Diagnostics &diag)
310{
311 bool ret = parse(findSingleNode(doc.document_element(), "definitions", diag), vec, diag); // parse document
312
313 return ret;
314}
315
316bool parseXML(std::vector<FaultRef> &vec, const pugi::xml_document &doc, xml::Diagnostics &diag)
317{
318 bool ret = parse(findSingleNode(doc.document_element(), "initial", diag), vec, diag); // parse document
319
320 return ret;
321}
322
323bool writeXML(const std::vector<Fault> &vec, std::ostream &out, std::ostream &diagnostics_out)
324{
325 pugi::xml_document doc;
326
327 doc.load_string("<?xml version=\"1.0\"?>");
328
329 etiss::fault::xml::Diagnostics diag;
330
331 bool ret = write(doc.append_child("faults"), vec, diag); // write document
332
333 doc.save(out);
334
335 diag.print(diagnostics_out);
336
337 return ret;
338}
339
340namespace xml
341{
342
343template <>
344bool parse<etiss::fault::Fault>(pugi::xml_node node, etiss::fault::Fault &f, Diagnostics &diag)
345{
346 etiss::log(etiss::VERBOSE, std::string("etiss::fault::xml::parse<etiss::fault::Fault>") +
347 std::string("(node, Fault, Diagnostics) called. "));
348 bool ret = true;
349 ret = ret && getAttribute(node, "name", f.name_, diag); // non-optional
350 /*ret = ret &*/ getAttribute(node, "id_", f.id_, diag); // optional
351 for (pugi::xml_node cnode = node.first_child(); cnode; cnode = cnode.next_sibling())
352 {
353 if (hasName(cnode, "triggers"))
354 {
355 for (pugi::xml_node ccnode = cnode.first_child(); ccnode; ccnode = ccnode.next_sibling())
356 {
357 if (hasName(ccnode, "trigger"))
358 {
360 if (parse<etiss::fault::Trigger>(ccnode, t, diag))
361 {
362 f.triggers.push_back(t);
363 }
364 else
365 {
366 ret = false;
367 }
368 }
369 else
370 {
371 diag.ignoredNode(ccnode, "\"trigger\" node expected");
372 }
373 }
374 }
375 else if (hasName(cnode, "actions"))
376 {
377 for (pugi::xml_node ccnode = cnode.first_child(); ccnode; ccnode = ccnode.next_sibling())
378 {
379 if (hasName(ccnode, "action"))
380 {
382 if (parse<etiss::fault::Action>(ccnode, t, diag))
383 {
384 f.actions.push_back(t);
385 }
386 else
387 {
388 ret = false;
389 }
390 }
391 else
392 {
393 diag.ignoredNode(ccnode, "\"trigger\" node expected");
394 }
395 }
396 }
397 else
398 {
399 diag.ignoredNode(cnode, "unknown node");
400 }
401 }
402
403 return ret;
404}
405template <>
406bool write<etiss::fault::Fault>(pugi::xml_node node, const etiss::fault::Fault &f, Diagnostics &diag)
407{
408 etiss::log(etiss::VERBOSE, std::string("etiss::fault::xml::write<etiss::fault::Fault>") +
409 std::string("(node, Fault, Diagnostics) called. "));
410 bool ok = true;
411 ok = ok && setAttribute(node, "name", f.name_, diag);
412 ok = ok && setAttribute(node, "id", f.id_, diag);
413 pugi::xml_node triggers = node.append_child("triggers");
414 for (std::vector<etiss::fault::Trigger>::const_iterator iter = f.triggers.begin(); iter != f.triggers.end(); ++iter)
415 {
416 ok = ok && write<etiss::fault::Trigger>(triggers.append_child("trigger"), *iter, diag);
417 }
418 pugi::xml_node actions = node.append_child("actions");
419 for (std::vector<etiss::fault::Action>::const_iterator iter = f.actions.begin(); iter != f.actions.end(); ++iter)
420 {
421 ok = ok && write<etiss::fault::Action>(actions.append_child("action"), *iter, diag);
422 }
423 return ok;
424}
425
426template <>
427bool parse<etiss::fault::FaultRef>(pugi::xml_node node, etiss::fault::FaultRef &fref, Diagnostics &diag)
428{
429 etiss::log(etiss::VERBOSE, std::string("etiss::fault::xml::parse<etiss::fault::Fault>") +
430 std::string("(node, Fault, Diagnostics) called. "));
431 bool ret = true;
432 std::string name;
433 ret = ret && getAttribute(node, "name", name, diag); // non-optional
434 // try to resolve reference, could (and is allowed to) fail in case of injected/ejected fault_ref
435 fref.set_fault_reference(name);
436 return ret;
437}
438
439template <>
440bool write<etiss::fault::FaultRef>(pugi::xml_node node, const etiss::fault::FaultRef &fref, Diagnostics &diag)
441{
442 etiss::log(etiss::VERBOSE, std::string("etiss::fault::xml::write<etiss::fault::Fault>") +
443 std::string("(node, Fault, Diagnostics) called. "));
444 bool ok = true;
445 ok = ok && setAttribute(node, "name", fref.get_name(), diag);
446 return ok;
447}
448
449} // namespace xml
450
451#endif
452
453} // namespace fault
454} // namespace etiss
contains an action class that describes actions associated with a fault
contains the fault container class that stores triggers and actions for fault injection
contains a simple class that represents and resolves injector addresses as used by triggers (
contains the fault injector interface class.
contains the stressor class that loads and activates faults.
contains the Trigger class that defines conditions under which actions of a Fault need to be applied.
contains XML related functions.
static __inline__ uint64_t
Definition arm_cde.h:31
static __inline__ int32_t
Definition arm_mve.h:51
std::string toString() const
operator<< can be used.
Definition Fault.cpp:269
bool set_fault_reference(const std::string &identifier)
Definition Fault.cpp:286
std::string name_
string identifier, used to resolve actual reference via fault_
Definition Fault.h:67
Fault fault_
referenced Fault, needs to be resolved during sim. runtime
Definition Fault.h:66
bool resolve_reference() const
Definition Fault.cpp:293
const std::string & get_name() const
Definition Fault.h:76
bool isResoved() const
check all Triggers if they are resolved.
Definition Fault.cpp:259
Fault()
Constructor: Generates a new Fault with unique ID.
Definition Fault.cpp:227
std::string toString() const
operator<< can be used.
Definition Fault.cpp:234
std::string name_
Definition Fault.h:57
void resolveTime(uint64_t time)
Resolves time for all its Triggers.
Definition Fault.cpp:251
std::vector< Trigger > triggers
contains the triggers for this fault
Definition Fault.h:59
std::vector< Action > actions
contains the actions for this fault
Definition Fault.h:60
static std::map< int32_t, Fault > & faults()
static map with all referencable faults.
Definition Stressor.cpp:48
static bool setAttribute(pugi::xml_node &node, const std::string &attr_name, const std::string &src, Diagnostics &diag)
Definition Fault.cpp:103
static bool getAttribute(const pugi::xml_node &node, const std::string &attr_name, std::string &dst, Diagnostics &diag)
Parser/writer structure:
Definition Fault.cpp:83
static int32_t uniqueFaultId()
Definition Fault.cpp:217
bool writeXML(const std::vector< Fault > &vec, std::ostream &out, std::ostream &diagnostics_out=std::cout)
bool parseXML(pugi::xml_document &doc, std::istream &input, std::ostream &diagnostics_out=std::cout)
parse a XML document held in input stream and return as doc
Definition XML.cpp:257
forwards: include/jit/*
Definition Benchmark.h:17
@ VERBOSE
Definition Misc.h:88
void log(Verbosity level, std::string msg)
write log message at the given level.
Definition Misc.cpp:94