Merge remote-tracking branch 'origin/master' into sampling-wip
Change-Id: Iae5c02be5801d75e8adc55222ccb35c559f7ebf4
This commit is contained in:
+1
-1
@@ -9,7 +9,7 @@ ENABLE_TESTING()
|
||||
|
||||
PROJECT(Fail*)
|
||||
|
||||
set(PROJECT_VERSION "0.0.1" CACHE STRING "Fail* version number")
|
||||
set(PROJECT_VERSION "1.0.1" CACHE INTERNAL "Fail* version number" FORCE)
|
||||
|
||||
#### Put all resulting library files in <your_build_dir>/lib ####
|
||||
SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
FAIL* - FAult Injection Leveraged
|
||||
|
||||
Copyright (c) 2011-2014 Horst Schirmeier <horst.schirmeier@tu-dortmund.de>
|
||||
Copyright (c) 2011-2013 Adrian Böckenkamp <adrian.boeckenkamp@tu-dortmund.de>
|
||||
Copyright (c) 2011-2014 Richard Hellwig <richard.hellwig@tu-dortmund.de>
|
||||
Copyright (c) 2011-2014 Martin Hoffmann <hoffmann@cs.fau.de>
|
||||
Copyright (c) 2012-2013 Martin Unzner <martin.unzner@googlemail.com>
|
||||
Copyright (c) 2013-2014 Christian Dietrich <stettberger@dokucode.de>
|
||||
Copyright (c) 2013-2014 Lars Rademacher <lars.rademacher@udo.edu>
|
||||
Copyright (c) 2012-2014 Christoph Borchert <christoph.borchert@tu-dortmund.de>
|
||||
Copyright (c) 2013-2014 Björn Döbel <bjoern.doebel@gmail.com>
|
||||
Copyright (c) 2012-2013 Tobias Friemel <tobias.friemel@tu-dortmund.de>
|
||||
Copyright (c) 2013-2014 Michael Lenz <michael.lenz@udo.edu>
|
||||
Copyright (c) 2013-2014 Florian Lukas <florian.lukas@gmail.com>
|
||||
Copyright (c) 2012 Robby Zippel <robby.zippel@informatik.stud.uni-erlangen.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
================================================================
|
||||
|
||||
Along the FAIL* source code, the source code of several other open source
|
||||
projects is included in this source tree:
|
||||
|
||||
- Bochs: GPLv2 or later
|
||||
- Gem5: BSD/MIT with some files in LGPL
|
||||
- OpenOCD: GPLv2 or later
|
||||
- elfinfo: GPLv2 or later
|
||||
- gzstream: GPLv2 or later
|
||||
- optionparser: MIT
|
||||
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
@@ -1,6 +0,0 @@
|
||||
This is an import of the old danceos svn repository. The Fail* development
|
||||
started with rev 187, but this git import only contains revisions 956 and newer
|
||||
due to directory structure changes.
|
||||
|
||||
Imported from external gitsvn checkout.
|
||||
http://www.kernel.org/pub/software/scm/git/docs/howto/using-merge-subtree.html
|
||||
@@ -0,0 +1,212 @@
|
||||
FAIL* - FAult Injection Leveraged
|
||||
=======================================
|
||||
|
||||
FAIL* is a fault-injection (FI) framework that provides support for
|
||||
detailed fault-injection campaigns. It provides carefully-chosen
|
||||
abstractions simplifying both the implementation of different
|
||||
simulator/hardware target backends and the reuse of experiment code,
|
||||
while retaining the ability for deep target-state access for
|
||||
specialized FI experiments.
|
||||
|
||||
The FI experiments are expressed with C++ and programmed against the
|
||||
FAIL* API which provides full access to the internal state of the
|
||||
system-under-test. Currently, several hardware/simulator based
|
||||
backends are available:
|
||||
|
||||
- [Bochs](http://bochs.sourceforge.net): Bochs is an x86
|
||||
simulator. FAIL* can run and inject bare-metal system images. This
|
||||
backend is the most mature and well tested one for undertaking large
|
||||
fault-injection campaigns with several millions of injected faults.
|
||||
|
||||
- [Gem5](http://www.gem5.org): Gem5 is a simulator for the ARM
|
||||
platform, which is supported by FAIL. For Gem5, FAIL supports the
|
||||
simulation of the Panda Board, which contains an ARM A9 core.
|
||||
|
||||
- [OpenOCD](http://openocd.org/): The OpenOCD project provides a
|
||||
unified debugging interface for real embedded ARM platforms. FAIL
|
||||
uses this interface to inject faults onto a real hardware
|
||||
platform. Several techniques, like SmartHopping, were developed to
|
||||
make campaigns with real hardware faster and more feasible.
|
||||
|
||||
- Support for other platforms were developed, but are not as mature as
|
||||
the other backends: The Trace32 simulator backend for TriCore; An
|
||||
x86 backend using QEMU.
|
||||
|
||||
During the FI experiment, FAIL provides an interface for triggering
|
||||
actions on certain instructions, instruction ranges, memory
|
||||
reads/writes, interrupts, IO operations and timer events. As well the
|
||||
state of the registers as the main memory of the system-under-test can
|
||||
be manipulated.
|
||||
|
||||
Building FAIL*
|
||||
--------------
|
||||
|
||||
Since FAIL* is a complex research project with many dependencies,
|
||||
which are listed in `doc/how-to-build.txt`, we provide several
|
||||
[Docker.io](http://www.docker.com) images that contain all
|
||||
requirements to build and run a FI campaign with FAIL. After
|
||||
installing and starting docker on your system, you have to type in the
|
||||
root directory of the git archive:
|
||||
|
||||
cd scripts/docker; make
|
||||
|
||||
As a result, you get three docker images:
|
||||
|
||||
- **fail-base**: The docker image contains all requirements to build
|
||||
FAIL*. This docker image is built on top of ubuntu 14.10 and
|
||||
provides access via SSH (User: fail; Password: fail).
|
||||
|
||||
- **fail-generic-tracing**: Upon the fail-base image, this images
|
||||
provides the tooling to generate golden-run traces of the
|
||||
system-under-test. These traces contain all instruction pointer and
|
||||
memory events of the golden run. The FAIL toolchain can record,
|
||||
show, and import those traces to an MySQL database.
|
||||
|
||||
- **fail-demo**: This image contains as well an generic FAIL
|
||||
experiment, a simple system-under-test, and scripts to run an first
|
||||
FI campaign within less than 20 minutes. This image has to be
|
||||
connected to a MySQL docker image.
|
||||
|
||||
Using FAIL*
|
||||
-----------
|
||||
|
||||
After building the docker images, you can run the FAIL demonstration
|
||||
image by typing:
|
||||
|
||||
cd scripts/docker
|
||||
docker pull mysql
|
||||
make run-fail-db
|
||||
make run-fail-demo
|
||||
make ssh-fail-demo
|
||||
|
||||
The last command starts a SSH connection to the demonstration
|
||||
system. Username, as well as password is 'fail'. In the default
|
||||
configuration, no SSH port is exposed to your normal network
|
||||
interface. After the connection, you should start in the
|
||||
`~/fail-targets` directory, which contains a clone of
|
||||
[https://github.com/danceos/fail-targets](https://github.com/danceos/fail-targets).
|
||||
|
||||
The demo system-under test is built and traced with:
|
||||
|
||||
make
|
||||
make trace-main
|
||||
|
||||
The golden run is traced with:
|
||||
|
||||
make import-main
|
||||
|
||||
The fault injection itself is separated into a server process and many
|
||||
injection workers. Both can be started at once with:
|
||||
|
||||
make server-main &
|
||||
make client-main
|
||||
|
||||
The results can be displayed on the console or with an browser-based
|
||||
viewer. By default, port 5000 is exposed to the machine running the
|
||||
docker instance.
|
||||
|
||||
make result-main
|
||||
make resultbrowser
|
||||
|
||||
|
||||
Mailing list
|
||||
------------
|
||||
The Fail* developers, and some of its previous and current users, can be
|
||||
contacted on the
|
||||
[fail@lists.cs.tu-dortmund.de](mailto:fail@lists.cs.tu-dortmund.de)
|
||||
mailing list
|
||||
([subscribe!](https://postamt.cs.uni-dortmund.de/mailman/listinfo/fail)).
|
||||
|
||||
Publications about FAIL*
|
||||
------------------------
|
||||
|
||||
- H. Schirmeier, M. Hoffmann, R. Kapitza, D. Lohmann, and
|
||||
O. Spinczyk. FAIL*: Towards a versatile fault-injection experiment
|
||||
framework. In G. Mühl, J. Richling, and A. Herkersdorf, editors,
|
||||
25th International Conference on Architecture of Computing Systems
|
||||
(ARCS '12), Workshop Proceedings, volume 200 of Lecture Notes in
|
||||
Informatics, pages 201–210. German Society of Informatics,
|
||||
Mar. 2012.
|
||||
[PDF](http://danceos.org/publications/VERFE-2012-Schirmeier.pdf)
|
||||
|
||||
Selected publications using FAIL*
|
||||
---------------------------------
|
||||
|
||||
- M. Hoffmann, F. Lukas, C. Dietrich, and D. Lohmann. dOSEK: The design and
|
||||
implementation of a dependability-oriented static embedded kernel. In
|
||||
Proceedings of the 21st IEEE Real-Time and Embedded Technology and
|
||||
Applications (RTAS '15), Los Alamitos, CA, USA, Apr. 2015. IEEE Computer
|
||||
Society Press.
|
||||
|
||||
- M. Hoffmann, P. Ulbrich, C. Dietrich, H. Schirmeier, D. Lohmann, and W.
|
||||
Schröder-Preikschat. Experiences with software-based soft-error mitigation
|
||||
using AN codes. Software Quality Journal, pages 1–27, 2015.
|
||||
|
||||
- I. Stilkerich, P. Taffner, C. Erhardt, C. Dietrich, C. Wawersich, and
|
||||
M. Stilkerich. Team Up: Cooperative Memory Management in Embedded
|
||||
Systems. In Proceedings of the 2014 Conference on Compilers,
|
||||
Architectures and Synthesis for Embedded Systems (CASES '14). ACM,
|
||||
October 2014.
|
||||
|
||||
- H. Schirmeier, C. Borchert, and O. Spinczyk. Rapid fault-space exploration by
|
||||
evolutionary pruning. In Proceedings of the 33rd International Conference on
|
||||
Computer Safety, Reliability and Security (SAFECOMP '14), Lecture Notes in
|
||||
Computer Science, pages 17–32. Springer-Verlag, Sept. 2014.
|
||||
|
||||
- M. Hoffmann, C. Borchert, C. Dietrich, H. Schirmeier, R. Kapitza, O.
|
||||
Spinczyk, and D. Lohmann. Effectiveness of fault detection mechanisms in
|
||||
static and dynamic operating system designs. In Proceedings of the 17th IEEE
|
||||
International Symposium on Object-Oriented Real-Time Distributed Computing
|
||||
(ISORC '14), pages 230–237. IEEE Computer Society Press, June 2014.
|
||||
|
||||
- H. Schirmeier, L. Rademacher, and O. Spinczyk. Smart-hopping: Highly efficient
|
||||
ISA-level fault injection on real hardware. In Proceedings of the 19th IEEE
|
||||
European Test Symposium (ETS '14), pages 69–74. IEEE Computer Society Press,
|
||||
May 2014.
|
||||
|
||||
- M. Hoffmann, P. Ulbrich, C. Dietrich, H. Schirmeier, D. Lohmann, and W.
|
||||
Schröder-Preikschat. A practitioner's guide to software-based soft-error
|
||||
mitigation using AN-codes. In Proceedings of the 15th IEEE International
|
||||
Symposium on High Assurance Systems Engineering (HASE '14), pages 33–40,
|
||||
Miami, Florida, USA, Jan. 2014. IEEE Computer Society Press.
|
||||
|
||||
- C. Borchert, H. Schirmeier, and O. Spinczyk. Return-address
|
||||
protection in C/C++ code by dependability aspects. In Proceedings of
|
||||
the 2nd GI Workshop on Software-Based Methods for Robust Embedded
|
||||
Systems (SOBRES '13), Lecture Notes in Informatics. German Society
|
||||
of Informatics, Sept. 2013.
|
||||
|
||||
- M. Hoffmann, C. Dietrich, and D. Lohmann. Failure by design:
|
||||
Influence of the RTOS interface on memory fault resilience. In
|
||||
Proceedings of the 2nd GI Workshop on Software-Based Methods for
|
||||
Robust Embedded Systems (SOBRES '13), Lecture Notes in
|
||||
Informatics. German Society of Informatics, Sept. 2013.
|
||||
|
||||
- I. Stilkerich, M. Strotz, C. Erhardt, M. Hoffmann, D. Lohmann, F.
|
||||
Scheler, and W. Schröder-Preikschat. A JVM for Soft-Error-Prone
|
||||
Embedded Systems. In Proceedings of the 2013 ACM SIGPLAN/SIGBED
|
||||
Conference on Languages, Compilers and Tools for Embedded Systems
|
||||
(LCTES '13), pages 21–32, June 2013.
|
||||
|
||||
- C. Borchert, H. Schirmeier, and O. Spinczyk. Generative
|
||||
software-based memory error detection and correction for operating
|
||||
system data structures. In Proceedings of the 43nd IEEE/IFIP
|
||||
International Conference on Dependable Systems and Networks (DSN
|
||||
'13). IEEE Computer Society Press, June 2013.
|
||||
|
||||
- H. Schirmeier, I. Korb, O. Spinczyk, and M. Engel. Efficient online
|
||||
memory error assessment and circumvention for Linux with RAMpage.
|
||||
International Journal of Critical Computer-Based Systems,
|
||||
4(3):227–247, 2013. Special Issue on PRDC 2011 Dependable Architecture
|
||||
and Analysis.
|
||||
|
||||
- B. Döbel, H. Schirmeier, and M. Engel. Investigating the limitations
|
||||
of PVF for realistic program vulnerability assessment. In Proceedings
|
||||
of the 5rd HiPEAC Workshop on Design for Reliability (DFR '13),
|
||||
Berlin, Germany, Jan. 2013.
|
||||
|
||||
- C. Borchert, H. Schirmeier, and O. Spinczyk. Protecting the dynamic
|
||||
dispatch in C++ by dependability aspects. In Proceedings of the 1st
|
||||
GI Workshop on Software-Based Methods for Robust Embedded Systems
|
||||
(SOBRES '12), Lecture Notes in Informatics, pages 521–535. German
|
||||
Society of Informatics, Sept. 2012.
|
||||
+7
-1
@@ -85,10 +85,11 @@ if(BUILD_BOCHS)
|
||||
|
||||
# Use cmake's external project feature to build fail library
|
||||
include(ExternalProject)
|
||||
set_property(DIRECTORY PROPERTY EP_STEP_TARGETS configure)
|
||||
ExternalProject_Add(
|
||||
libfailbochs_external
|
||||
SOURCE_DIR ${bochs_src_dir}
|
||||
CONFIGURE_COMMAND ${bochs_src_dir}/configure ${bochs_configure_params} --prefix=${bochs_install_prefix}
|
||||
CONFIGURE_COMMAND MAKEFLAGS="" ${bochs_src_dir}/configure ${bochs_configure_params} --prefix=${bochs_install_prefix}
|
||||
PREFIX ${bochs_src_dir}
|
||||
BUILD_COMMAND $(MAKE) -C ${bochs_src_dir} ${bochs_build_CXX} ${bochs_build_LIBTOOL} libfailbochs.a
|
||||
## Put install command here, to prevent cmake calling make install
|
||||
@@ -110,7 +111,12 @@ if(BUILD_BOCHS)
|
||||
# FIXME: see FIXME above
|
||||
#target_link_libraries(fail-client libfailbochs fail ${bochs_library_dependencies})
|
||||
target_link_libraries(fail-client ${bochs_src_dir}/libfailbochs.a fail ${bochs_library_dependencies})
|
||||
add_dependencies(libfailbochs_external-configure fail-protoc)
|
||||
add_dependencies(libfailbochs_external libfailbochs_external-configure)
|
||||
add_dependencies(fail-client libfailbochs_external)
|
||||
add_dependencies(fail-sal libfailbochs_external-configure)
|
||||
add_dependencies(fail-comm libfailbochs_external-configure)
|
||||
add_dependencies(fail-util libfailbochs_external-configure)
|
||||
# /FIXME
|
||||
install(TARGETS fail-client RUNTIME DESTINATION bin)
|
||||
|
||||
|
||||
@@ -2,12 +2,17 @@
|
||||
## A cmake configuration call for a FailBochs pruning
|
||||
EXP=$1
|
||||
FAILPATH=$(dirname $0)/..
|
||||
if [ -z $1 ]
|
||||
then
|
||||
echo "Experiment not set. Usage: $0 <experiment name>"
|
||||
echo "Existing experiments:"
|
||||
find ${FAILPATH}/src/experiments -maxdepth 1 -mindepth 1 -type d -printf \-\>\ %P\\n | sort
|
||||
if [ -z $1 ]; then
|
||||
echo "Experiment not set. Usage: $0 <experiment name>"
|
||||
echo "Existing experiments:"
|
||||
find ${FAILPATH}/src/experiments -maxdepth 1 -mindepth 1 -type d -printf \-\>\ %P\\n | sort
|
||||
else
|
||||
|
||||
cmake ${FAILPATH} -DBUILD_BOCHS:BOOL=ON -DBUILD_X86:BOOL=ON -DCONFIG_BOCHS_NO_ABORT:BOOL=ON -DCONFIG_EVENT_BREAKPOINTS:BOOL=ON -DCONFIG_EVENT_BREAKPOINTS_RANGE:BOOL=ON -DCONFIG_EVENT_INTERRUPT:BOOL=ON -DCONFIG_EVENT_IOPORT:BOOL=ON -DCONFIG_EVENT_MEMREAD:BOOL=ON -DCONFIG_EVENT_MEMWRITE:BOOL=ON -DCONFIG_EVENT_TRAP:BOOL=ON -DCONFIG_SR_RESTORE:BOOL=ON -DCONFIG_SR_SAVE:BOOL=ON -D"bochs_configure_params:STRING=--enable-a20-pin;--enable-x86-64;--enable-cpu-level=6;--enable-ne2000;--enable-acpi;--enable-pci;--enable-usb;--enable-trace-cache;--enable-fast-function-calls;--enable-host-specific-asms;--enable-disasm;--enable-readline;--enable-clgd54xx;--enable-fpu;--enable-vmx=2;--enable-monitor-mwait;--enable-cdrom;--enable-sb16=linux;--enable-gdb-stub;--with-nogui" -DEXPERIMENTS_ACTIVATED:STRING=${EXP} -DBUILD_IMPORT_TRACE:BOOL=ON -DBUILD_PRUNE_TRACE:BOOL=ON -DBUILD_LLVM_DISASSEMBLER=ON
|
||||
CONFIG='-DBUILD_BOCHS:BOOL=ON -DBUILD_X86:BOOL=ON -DCONFIG_BOCHS_NO_ABORT:BOOL=ON -DCONFIG_EVENT_BREAKPOINTS:BOOL=ON -DCONFIG_EVENT_BREAKPOINTS_RANGE:BOOL=ON -DCONFIG_EVENT_INTERRUPT:BOOL=ON -DCONFIG_EVENT_IOPORT:BOOL=ON -DCONFIG_EVENT_MEMREAD:BOOL=ON -DCONFIG_EVENT_MEMWRITE:BOOL=ON -DCONFIG_EVENT_TRAP:BOOL=ON -DCONFIG_SR_RESTORE:BOOL=ON -DCONFIG_SR_SAVE:BOOL=ON -Dbochs_configure_params:STRING="--enable-a20-pin;--enable-x86-64;--enable-cpu-level=6;--enable-ne2000;--enable-acpi;--enable-pci;--enable-usb;--enable-trace-cache;--enable-fast-function-calls;--enable-host-specific-asms;--enable-disasm;--enable-readline;--enable-clgd54xx;--enable-fpu;--enable-vmx=2;--enable-monitor-mwait;--enable-cdrom;--enable-sb16=linux;--enable-gdb-stub;--with-nogui" -DEXPERIMENTS_ACTIVATED:STRING='${EXP}' -DBUILD_IMPORT_TRACE:BOOL=ON -DBUILD_PRUNE_TRACE:BOOL=ON -DBUILD_LLVM_DISASSEMBLER=ON'
|
||||
|
||||
if [ -e "${FAILPATH}/src/experiments/${EXP}/config.cmake" ]; then
|
||||
CONFIG="-C ${FAILPATH}/src/experiments/${EXP}/config.cmake -DEXPERIMENTS_ACTIVATED:STRING=${EXP}"
|
||||
fi
|
||||
|
||||
cmake ${CONFIG} ${FAILPATH}
|
||||
fi
|
||||
|
||||
+27
-4
@@ -8,21 +8,27 @@ Required for Fail*:
|
||||
- libprotobuf-dev
|
||||
- libpcl1-dev
|
||||
- libboost-thread-dev libboost-system-dev libboost-regex-dev
|
||||
- libdwarf
|
||||
- libelf
|
||||
- libdwarf-dev
|
||||
- libelf-dev
|
||||
- protobuf-compiler
|
||||
- cmake 2.8.2 (2.8.11 preferred)
|
||||
- cmake-curses-gui
|
||||
- fontconfig1-dev
|
||||
- zlib1g-dev
|
||||
- binutils-dev, on newer systems libiberty-dev
|
||||
- AspectC++ (ag++, ac++): AspectC++ 1.1 or newer is known to work and can be
|
||||
obtained from <http://www.aspectc.org>; nightlies can be downloaded from
|
||||
<http://akut.aspectc.org>. Make sure you use the 64-bit version if running
|
||||
in a 64-bit environment.
|
||||
- optional:
|
||||
* LLVM 3.3 (needed for several importers in tools/import-trace)
|
||||
* LLVM 3.3 or 3.4 (needed for several importers in tools/import-trace)
|
||||
(compiles/links with 3.1 or 3.2, but fails to properly import information
|
||||
from ELF binaries not compiled with -ffunction-sections)
|
||||
- built with "make REQUIRES_RTTI=1" (the Debian/Ubuntu packages already
|
||||
come built this way)
|
||||
- details below
|
||||
* a MySQL 5.0+ or MariaDB 5.1+ (MariaDB 5.5 recommended) server
|
||||
- optional: cmake-curses-gui
|
||||
|
||||
|
||||
|
||||
Required for the Bochs simulator backend:
|
||||
@@ -268,3 +274,20 @@ Database backend setup: MySQL / MariaDB
|
||||
<http://dev.mysql.com/doc/refman/5.5/en/create-database.html>
|
||||
<http://dev.mysql.com/doc/refman/5.5/en/grant.html>
|
||||
<http://dev.mysql.com/doc/refman/5.5/en/adding-users.html>
|
||||
|
||||
=========================================================================================
|
||||
Building LLVM from sources
|
||||
=========================================================================================
|
||||
If your Linux distribution does not provide a library package for LLVM 3.3 or
|
||||
newer, and you need LLVM support in Fail*, you may need to build LLVM from the
|
||||
sources and install it, e.g., locally in your home.
|
||||
|
||||
1. Download the source tarball of LLVM 3.4 from http://llvm.org (or use the git
|
||||
repository http://llvm.org/git/llvm.git and checkout release_34)
|
||||
2. Configure as needed. On mixed 32/64-bit systems (userland/kernel),
|
||||
prefixing with "linux32" may be necessary:
|
||||
$ linux32 ./configure --prefix=$(echo ~/localroot/usr) --enable-optimized --disable-assertions --disable-werror
|
||||
If you have an old version of clang installed, you may need to convince the
|
||||
configure script to use gcc/g++ instead:
|
||||
$ CC=gcc CXX=g++ ./configure --prefix=...
|
||||
3. Build with "make REQUIRES_RTTI=1", install.
|
||||
|
||||
@@ -53,6 +53,34 @@ based on the "${PREFIX}/share/doc/bochs/bochsrc-sample.txt" template (or
|
||||
Example experiments and code snippets
|
||||
=========================================================================================
|
||||
|
||||
Experiment "weather-monitor":
|
||||
**********************************************************************
|
||||
An example of a DatabaseCampaign with separate experiment.
|
||||
1. Add "weather-monitor" to EXPERIMENTS_ACTIVATED,
|
||||
add "tracing" to PLUGINS_ACTIVATED
|
||||
2. Enable BUILD_IMPORT_TRACE, BUILD_PRUNE_TRACE, CONFIG_EVENT_BREAKPOINTS,
|
||||
CONFIG_EVENT_BREAKPOINTS_RANGE, CONFIG_EVENT_GUESTSYS, CONFIG_EVENT_MEMREAD,
|
||||
CONFIG_EVENT_MEMWRITE, CONFIG_EVENT_TRAP, CONFIG_SR_RESTORE and CONFIG_SR_SAVE
|
||||
The options BUILD_BOCHS, BUILD_X86 are needed as well, but are defaults.
|
||||
3. In weather-monitor/experimentInfo.hpp set "PREREQUISITES" to 1 and build
|
||||
Fail*/Bochs using e.g. fail/scripts/rebuild-bochs.sh (-> how-to-build.txt).
|
||||
Upon minor changes (i.e. not e.g. to aspects), append " -" to the call to
|
||||
the script. This will rebuild only parts that changed.
|
||||
4. Enter experiment_targets/weathermonitor and run:
|
||||
find . -name "*.bz2" -execdir bunzip2 -k {} +
|
||||
This extracts all the bzipped files in place while keeping the archives.
|
||||
5. In order to record a trace, run the following:
|
||||
fail-client -q -Wf,--benchmark=weather -Wf,--variant=vanilla
|
||||
"variant" is used to find the .elf/.vmi inside oostubs/!
|
||||
The resulting trace thereafter lies within prerequisites/, it's name
|
||||
being VARIANT.trace
|
||||
6. Use "import-trace" (using correct -b & -v, -t is VARIANT.trace) to get the
|
||||
trace into the database and "prune-trace" to (obviously) prune the data.
|
||||
7. Change PREREQUISITES (see 5) back to "0" and rebuild Fail*/Bochs.
|
||||
8. Run the "weather-monitor-server" (Don't forget -v & -b!) and "fail-client -q"
|
||||
from within experiment_targets/weathermonitor/.
|
||||
You'll need several clients to finish the campaign.
|
||||
|
||||
Experiment "hsc-simple":
|
||||
**********************************************************************
|
||||
A simple standalone experiment (without a separate campaign). To compile this
|
||||
@@ -169,6 +197,37 @@ instantiating the generic DatabaseCampaign. The general workflow is as follows:
|
||||
created result table with columns corresponding to the fields in the Result
|
||||
group of the protobuf message.
|
||||
|
||||
Experiment "weather-monitor" with gem5:
|
||||
**********************************************************************
|
||||
This experiment simulates a simple weather-station.
|
||||
To compile this experiment, the following steps are required:
|
||||
|
||||
1. Adapt fail/src/experiments/weather-monitor/experimentInfo.hpp
|
||||
2. Enter ${FAIL_DIR}/build/
|
||||
3. Add "weather-monitor" to ccmake's EXPERIMENTS_ACTIVATED.
|
||||
4. Add "tracing" to ccmake's PLUGINS_ACTIVATED.
|
||||
5. Enable BUILD_ARM, BUILD_GEM5, BUILD_IMPORT_TRACE, BUILD_PRUNE_TRACE,
|
||||
CONFIG_EVENT_BREAKPOINTS, CONFIG_EVENT_BREAKPOINTS_RANGE, CONFIG_EVENT_GUESTSYS,
|
||||
CONFIG_EVENT_MEMREAD, CONFIG_EVENT_MEMWRITE, CONFIG_EVENT_TRAP, CONFIG_SR_RESTORE
|
||||
and CONFIG_SR_SAVE.
|
||||
6. Enable STEP1 in fail/src/experiments/weather-monitor/experiment.cc
|
||||
7. Build Fail* and gem5, see "how-to-build.txt" for details.
|
||||
8. Start the gem5-fail-client by typing
|
||||
"../scripts/run-gem5.sh ../../experiment_targets/weathermonitor_arm/weather.elf
|
||||
weathermonitor_arm/weather.elf"
|
||||
9. Import the trace with
|
||||
"import-trace -t trace.tc.weather -d YOUR_DB -v baseline -b weather -i
|
||||
BasicImporter -e ../../experiment_targets/weathermonitor_arm/weather.elf
|
||||
--faultspace-rightmargin W"
|
||||
10. Prune the trace with
|
||||
"prune-trace -d YOUR_DB -v baseline -b weather"
|
||||
11. Enable STEP3 in fail/src/experiments/weather-monitor/experiment.cc
|
||||
12. Build Fail* and gem5, see "how-to-build.txt" for details.
|
||||
13. Start the campaign-server
|
||||
"bin/weather-monitor-server -v baseline -b weather"
|
||||
14. Start the gem5-fail-client by typing
|
||||
"../scripts/run-gem5.sh ../../experiment_targets/weathermonitor_arm/weather.elf
|
||||
|
||||
=========================================================================================
|
||||
Parallelization
|
||||
=========================================================================================
|
||||
@@ -206,6 +265,7 @@ themselves, they contain some documentation):
|
||||
- multiple-clients.sh: Is run on an experiment host by runcampaign.sh,
|
||||
starts several instances of client.sh in a tmux session.
|
||||
- client.sh: (Repeatedly) Runs a single fail-client instance.
|
||||
- run-gem5.sh: Runs a single gem5-fail-client instance.
|
||||
|
||||
|
||||
Some useful things to note:
|
||||
@@ -240,6 +300,11 @@ Steps to run an experiment with gem5:
|
||||
4. Run gem5 in $FAIL_DIR/simulators/gem5/ with:
|
||||
$ M5_PATH=$SYSTEM build/ARM/gem5.debug configs/example/fs.py --bare-metal --kernel kernelname
|
||||
|
||||
Step 4 has been encapsulated in a shell script:
|
||||
1. Enter ${FAIL_DIR}/build/
|
||||
2. Run the run-gem5.sh script with the path of the elf-binary
|
||||
../scripts/run-gem5.sh path-to-elf-binary
|
||||
|
||||
=========================================================================================
|
||||
Steps to run an experiment with the pandaboard/openocd backend:
|
||||
=========================================================================================
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
!*/Makefile
|
||||
+1
-1
@@ -51,7 +51,7 @@ do
|
||||
#nice -n 19 ./bochs -q 2>&1 | tee log.$$.txt | fgrep Result
|
||||
#nice -n 18 ./bochs -q 2>&1 | fgrep Result
|
||||
nice -n 18 ./fail-client -q >/dev/null 2>&1
|
||||
if [ $? -eq 1 ]
|
||||
if [ $? -gt 0 ] # exit on any error
|
||||
then
|
||||
break
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
all:
|
||||
docker build -t danceos/fail-base fail-base
|
||||
docker build -t danceos/fail-generic-tracing fail-generic-tracing
|
||||
docker build -t danceos/fail-demo fail-demo
|
||||
|
||||
|
||||
run-fail-db:
|
||||
docker run --name fail-db \
|
||||
-e MYSQL_ROOT_PASSWORD=fail \
|
||||
-e MYSQL_USER=fail \
|
||||
-e MYSQL_PASSWORD=fail \
|
||||
-e MYSQL_DATABASE=fail \
|
||||
-d mysql
|
||||
|
||||
run-fail-demo:
|
||||
docker run --name fail-demo -p 127.0.0.1:5000:5000 --link fail-db:mysql -d danceos/fail-demo
|
||||
|
||||
ssh-fail-demo:
|
||||
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no fail@$$(docker inspect --format "{{ .NetworkSettings.IPAddress }}" fail-demo)
|
||||
@@ -0,0 +1,59 @@
|
||||
# Set the base image to Ubuntu Utopic (14.10)
|
||||
FROM ubuntu:utopic
|
||||
|
||||
MAINTAINER Christian Dietrich <stettberger@dokucode.de>
|
||||
|
||||
# Install Packages required to build FAIL*
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y \
|
||||
binutils-dev \
|
||||
build-essential \
|
||||
cmake \
|
||||
git \
|
||||
libboost-regex-dev \
|
||||
libboost-system-dev \
|
||||
libboost-thread-dev \
|
||||
libdwarf-dev \
|
||||
libelf-dev \
|
||||
libfontconfig1-dev \
|
||||
libiberty-dev \
|
||||
libmysqlclient-dev \
|
||||
libpcl1-dev \
|
||||
libprotobuf-dev \
|
||||
libsvga1-dev \
|
||||
llvm-3.4-dev \
|
||||
screen \
|
||||
protobuf-compiler \
|
||||
wget \
|
||||
openssh-server \
|
||||
vim \
|
||||
zlib1g-dev
|
||||
|
||||
# Add a user for compiling FAIL*
|
||||
RUN useradd fail; mkdir /home/fail; chown fail /home/fail
|
||||
RUN echo 'fail:fail' | chpasswd; chsh fail --shell /bin/bash
|
||||
RUN adduser fail sudo
|
||||
|
||||
# SSH login fix. Otherwise user is kicked off after login
|
||||
RUN mkdir /var/run/sshd
|
||||
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
|
||||
|
||||
ENV NOTVISIBLE "in users profile"
|
||||
RUN echo "export VISIBLE=now" >> /etc/profile
|
||||
|
||||
USER fail
|
||||
ENV HOME /home/fail
|
||||
WORKDIR /home/fail
|
||||
|
||||
# Get AspectC++ v1.2 for 64 Bit
|
||||
RUN wget http://www.aspectc.org/releases/1.2/ac-bin-linux-x86-64bit-1.2.tar.gz
|
||||
RUN tar xvzf ac-bin-linux-x86-64bit-1.2.tar.gz; mkdir bin; mv aspectc++/ac++ aspectc++/ag++ bin/; rm -rf aspectc++
|
||||
ENV PATH /home/fail/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
|
||||
# Clone FAIL*
|
||||
RUN git clone https://github.com/danceos/fail.git
|
||||
WORKDIR fail
|
||||
|
||||
USER root
|
||||
EXPOSE 22
|
||||
CMD ["/usr/sbin/sshd", "-D"]
|
||||
@@ -0,0 +1,45 @@
|
||||
# Inherit from docker container that has the fail source code
|
||||
# prepared, including all tools which are needed to build FAIL*. The
|
||||
# generic-tracing experiment was already built and the binaries are in
|
||||
# place (~fail/bin/*)
|
||||
|
||||
FROM danceos/fail-generic-tracing
|
||||
MAINTAINER Christian Dietrich <stettberger@dokucode.de>
|
||||
|
||||
# Install Additional Packages
|
||||
RUN apt-get install -y \
|
||||
python-minimal \
|
||||
grub-common \
|
||||
xorriso \
|
||||
grub-pc-bin \
|
||||
mysql-client \
|
||||
python-flask \
|
||||
python-mysqldb \
|
||||
python-yaml
|
||||
|
||||
|
||||
# Passwort for MySQL Daemon
|
||||
ADD my.cnf /home/fail/.my.cnf
|
||||
RUN chown fail /home/fail/.my.cnf
|
||||
|
||||
USER fail
|
||||
WORKDIR /home/fail
|
||||
RUN echo 'export PATH=$HOME/bin:$PATH' >> ~/.profile;\
|
||||
echo 'cd $HOME/fail-targets' >> ~/.profile
|
||||
|
||||
RUN git clone https://github.com/danceos/fail-targets.git
|
||||
|
||||
WORKDIR fail
|
||||
RUN mkdir build; cd build; ../configurations/x86_pruning.sh generic-experiment
|
||||
WORKDIR build
|
||||
|
||||
# Make FAIL*
|
||||
RUN make -j$(getconf _NPROCESSORS_ONLN) || make -j$(getconf _NPROCESSORS_ONLN)
|
||||
RUN ln -s /home/fail/fail/build/bin/fail-client /home/fail/bin/generic-experiment-client; \
|
||||
ln -s /home/fail/fail/build/bin/generic-experiment-server /home/fail/bin/; \
|
||||
ln -s /home/fail/fail/tools/analysis/resultbrowser/run.py /home/fail/bin/resultbrowser
|
||||
|
||||
# For the resultbrowser, we expose port 5000 to the outside world.
|
||||
EXPOSE 5000
|
||||
|
||||
USER root
|
||||
@@ -0,0 +1,5 @@
|
||||
[client]
|
||||
host=mysql
|
||||
user=fail
|
||||
password=fail
|
||||
database=fail
|
||||
@@ -0,0 +1,25 @@
|
||||
# Inherit from docker container that has the fail source code prepared,
|
||||
# including all tools which are needed to build FAIL*
|
||||
FROM danceos/fail-base
|
||||
MAINTAINER Christian Dietrich <stettberger@dokucode.de>
|
||||
|
||||
USER fail
|
||||
|
||||
# Configure the Weather Monitor Experiment
|
||||
ENV PATH /home/fail/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
WORKDIR /home/fail/fail
|
||||
RUN mkdir build-tracer; cd build-tracer; ../configurations/x86_pruning.sh generic-tracing
|
||||
WORKDIR build-tracer
|
||||
|
||||
# Make FAIL*
|
||||
RUN make -j$(getconf _NPROCESSORS_ONLN) || make -j$(getconf _NPROCESSORS_ONLN)
|
||||
|
||||
RUN ln -s /home/fail/fail/build-tracer/bin/fail-client /home/fail/bin/fail-x86-tracing; \
|
||||
ln -s /home/fail/fail/build-tracer/bin/import-trace /home/fail/bin/; \
|
||||
ln -s /home/fail/fail/build-tracer/bin/prune-trace /home/fail/bin/; \
|
||||
ln -s /home/fail/fail/build-tracer/bin/dump-trace /home/fail/bin/; \
|
||||
ln -s /home/fail/fail/build-tracer/bin/convert-trace /home/fail/bin/; \
|
||||
cp /home/fail/fail/tools/bochs-experiment-runner/bochs-experiment-runner.py /home/fail/bin/bochs-experiment-runner.py; \
|
||||
chmod a+x /home/fail/bin/bochs-experiment-runner.py;
|
||||
|
||||
USER root
|
||||
Executable
+149
@@ -0,0 +1,149 @@
|
||||
#!/bin/bash
|
||||
|
||||
#
|
||||
# This script removes dangling rows from the database, for example 'trace'
|
||||
# entries with a variant_id not mentioned in the 'variants' table, or result
|
||||
# rows referencing a nonexistent 'fsppilot' entry. IOW, this script enforces
|
||||
# referential integrity as it would be maintained by foreign key constraints
|
||||
# (that can only be used with InnoDB tables).
|
||||
#
|
||||
|
||||
if [ -z "$1" -o -z "$2" ]
|
||||
then
|
||||
echo "usage: $0 dbname resulttable" >&2
|
||||
exit 1
|
||||
fi
|
||||
DB=$1
|
||||
RESULT=$2
|
||||
MYSQL=mysql
|
||||
|
||||
function table_exists()
|
||||
{
|
||||
N=$(echo "SHOW TABLES LIKE '$1'" | $MYSQL $DB | wc -l)
|
||||
[ $N -gt 0 ]
|
||||
return
|
||||
}
|
||||
|
||||
if table_exists trace
|
||||
then
|
||||
echo -n "removing widowed entries in trace ..."
|
||||
echo " "$(
|
||||
$MYSQL $DB <<EOT
|
||||
DELETE FROM trace
|
||||
WHERE variant_id NOT IN
|
||||
(SELECT id FROM variant);
|
||||
SELECT ROW_COUNT() AS "deleted rows:";
|
||||
EOT
|
||||
)
|
||||
fi
|
||||
|
||||
if table_exists fsppilot
|
||||
then
|
||||
echo -n "removing widowed entries in fsppilot ..."
|
||||
echo " "$(
|
||||
$MYSQL $DB <<EOT
|
||||
DELETE p FROM fsppilot p
|
||||
LEFT JOIN trace t
|
||||
ON p.variant_id = t.variant_id
|
||||
AND p.instr2 = t.instr2
|
||||
AND p.data_address = t.data_address
|
||||
WHERE t.variant_id IS NULL;
|
||||
SELECT ROW_COUNT() AS "deleted rows:";
|
||||
EOT
|
||||
)
|
||||
fi
|
||||
|
||||
if table_exists fspgroup
|
||||
then
|
||||
echo -n "removing widowed entries in fspgroup ..."
|
||||
echo " "$(
|
||||
$MYSQL $DB <<EOT
|
||||
DELETE g FROM fspgroup g
|
||||
LEFT JOIN fsppilot p
|
||||
ON g.pilot_id = p.id
|
||||
WHERE p.id IS NULL;
|
||||
SELECT ROW_COUNT() AS "deleted rows:";
|
||||
EOT
|
||||
)
|
||||
fi
|
||||
|
||||
if table_exists $RESULT
|
||||
then
|
||||
echo -n "removing widowed entries in $RESULT ..."
|
||||
echo " "$(
|
||||
$MYSQL $DB <<EOT
|
||||
DELETE r FROM $RESULT r
|
||||
LEFT JOIN fsppilot p
|
||||
ON r.pilot_id = p.id
|
||||
WHERE p.id IS NULL;
|
||||
SELECT ROW_COUNT() AS "deleted rows:";
|
||||
EOT
|
||||
)
|
||||
fi
|
||||
|
||||
if table_exists objdump
|
||||
then
|
||||
echo -n "removing widowed entries in objdump ..."
|
||||
echo " "$(
|
||||
$MYSQL $DB <<EOT
|
||||
DELETE FROM objdump
|
||||
WHERE variant_id NOT IN
|
||||
(SELECT id FROM variant);
|
||||
SELECT ROW_COUNT() AS "deleted rows:";
|
||||
EOT
|
||||
)
|
||||
fi
|
||||
|
||||
if table_exists fulltrace
|
||||
then
|
||||
echo -n "removing widowed entries in fulltrace ..."
|
||||
echo " "$(
|
||||
$MYSQL $DB <<EOT
|
||||
DELETE FROM fulltrace
|
||||
WHERE variant_id NOT IN
|
||||
(SELECT id FROM variant);
|
||||
SELECT ROW_COUNT() AS "deleted rows:";
|
||||
EOT
|
||||
)
|
||||
fi
|
||||
|
||||
if table_exists dbg_source
|
||||
then
|
||||
echo -n "removing widowed entries in dbg_source ..."
|
||||
echo " "$(
|
||||
$MYSQL $DB <<EOT
|
||||
DELETE FROM dbg_source
|
||||
WHERE variant_id NOT IN
|
||||
(SELECT id FROM variant);
|
||||
SELECT ROW_COUNT() AS "deleted rows:";
|
||||
EOT
|
||||
)
|
||||
fi
|
||||
|
||||
if table_exists dbg_filename
|
||||
then
|
||||
echo -n "removing widowed entries in dbg_filename ..."
|
||||
echo " "$(
|
||||
$MYSQL $DB <<EOT
|
||||
DELETE FROM dbg_filename
|
||||
WHERE variant_id NOT IN
|
||||
(SELECT id FROM variant);
|
||||
SELECT ROW_COUNT() AS "deleted rows:";
|
||||
EOT
|
||||
)
|
||||
fi
|
||||
|
||||
if table_exists dbg_mapping
|
||||
then
|
||||
echo -n "removing widowed entries in dbg_mapping ..."
|
||||
echo " "$(
|
||||
$MYSQL $DB <<EOT
|
||||
DELETE FROM dbg_mapping
|
||||
WHERE variant_id NOT IN
|
||||
(SELECT id FROM variant);
|
||||
SELECT ROW_COUNT() AS "deleted rows:";
|
||||
EOT
|
||||
)
|
||||
fi
|
||||
|
||||
echo "done. Consider running \`mysqloptimize $DB' now."
|
||||
@@ -195,9 +195,138 @@ const struct BxDisasmOpcodeInfo_t
|
||||
|
||||
//DanceOS
|
||||
// workaround for include file clash with cpu/instr.h in conjunction with AspectC++
|
||||
|
||||
#undef Apw
|
||||
#undef Apd
|
||||
#undef AL_Reg
|
||||
#undef CL_Reg
|
||||
#undef AX_Reg
|
||||
#undef DX_Reg
|
||||
|
||||
#undef EAX_Reg
|
||||
#undef RAX_Reg
|
||||
|
||||
#undef CS
|
||||
#undef DS
|
||||
#undef ES
|
||||
#undef SS
|
||||
#undef FS
|
||||
#undef GS
|
||||
|
||||
#undef Sw
|
||||
|
||||
#undef Td
|
||||
|
||||
#undef Cd
|
||||
#undef Cq
|
||||
|
||||
#undef Dd
|
||||
#undef Dq
|
||||
|
||||
#undef Reg8
|
||||
#undef RX
|
||||
#undef ERX
|
||||
#undef RRX
|
||||
|
||||
#undef Eb
|
||||
#undef Ew
|
||||
#undef Ed
|
||||
#undef Eq
|
||||
#undef Ey
|
||||
#undef Ebd
|
||||
#undef Ewd
|
||||
|
||||
#undef Gb
|
||||
#undef Gw
|
||||
#undef Gd
|
||||
#undef Gq
|
||||
#undef Gy
|
||||
|
||||
#undef I1
|
||||
#undef Ib
|
||||
#undef Iw
|
||||
#undef Id
|
||||
#undef Iq
|
||||
#undef Iw
|
||||
#undef Ib
|
||||
|
||||
#undef IbIb
|
||||
#undef IwIb
|
||||
|
||||
#undef sIbw
|
||||
#undef sIbd
|
||||
#undef sIbq
|
||||
#undef sIdq
|
||||
|
||||
#undef ST0
|
||||
#undef STi
|
||||
|
||||
#undef Rw
|
||||
#undef Rd
|
||||
#undef Rq
|
||||
#undef Ry
|
||||
|
||||
#undef Pq
|
||||
#undef Qd
|
||||
#undef Qq
|
||||
#undef Nq
|
||||
|
||||
#undef Vq
|
||||
#undef Vdq
|
||||
#undef Vss
|
||||
#undef Vsd
|
||||
#undef Vps
|
||||
#undef Vpd
|
||||
|
||||
#undef Ups
|
||||
#undef Upd
|
||||
#undef Udq
|
||||
|
||||
#undef Ww
|
||||
#undef Wd
|
||||
#undef Wq
|
||||
#undef Wdq
|
||||
#undef Wss
|
||||
#undef Wsd
|
||||
#undef Wps
|
||||
#undef Wpd
|
||||
|
||||
#undef Ob
|
||||
#undef Ow
|
||||
#undef Od
|
||||
#undef Oq
|
||||
|
||||
#undef Ma
|
||||
#undef Mp
|
||||
#undef Ms
|
||||
#undef Mx
|
||||
#undef Mb
|
||||
#undef Mw
|
||||
#undef Md
|
||||
#undef Mq
|
||||
#undef Mt
|
||||
#undef Mdq
|
||||
#undef Mps
|
||||
#undef Mpd
|
||||
#undef Mss
|
||||
#undef Msd
|
||||
|
||||
#undef Xb
|
||||
#undef Xw
|
||||
#undef Xd
|
||||
#undef Xq
|
||||
|
||||
#undef Yb
|
||||
#undef Yw
|
||||
#undef Yd
|
||||
#undef Yq
|
||||
|
||||
#undef sYq
|
||||
#undef sYdq
|
||||
|
||||
#undef Jb
|
||||
#undef Jw
|
||||
#undef Jd
|
||||
|
||||
#undef XX
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+3
-1
@@ -7,7 +7,9 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/core)
|
||||
# protoc imports refer to the same root path. Otherwise the generated
|
||||
# protoc headers are not comptabile.
|
||||
SET(PROTOBUF_GENERATE_CPP_APPEND_PATH FALSE)
|
||||
SET(PROTOBUF_IMPORT_DIRS "/usr/include;${CMAKE_CURRENT_SOURCE_DIR}/core/comm")
|
||||
SET(PROTOBUF_IMPORT_DIRS "/usr/include;${CMAKE_CURRENT_SOURCE_DIR}/core/comm"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/core/comm")
|
||||
|
||||
|
||||
# Note: CMAKE_CURRENT_BINARY_DIR is needed to find "FailConfig.hpp", which
|
||||
# is generated by CMake from config/FailConfig.hpp.in and stored in
|
||||
|
||||
@@ -30,9 +30,11 @@ find_package(Protobuf REQUIRED)
|
||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# Let protobuf compiler find defined file (DatabaseCampaignMessage) in binary tree
|
||||
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
|
||||
# The PROTOBUF_IMPORT_DIRS is set in src/CMakeLists.txt
|
||||
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${PROTOS})
|
||||
|
||||
add_custom_target(fail-protoc
|
||||
DEPENDS ${PROTO_SRCS} ${PROTO_HDRS}
|
||||
)
|
||||
add_library(fail-comm ${SRCS} ${PROTO_SRCS} ${PROTO_HDRS})
|
||||
target_link_libraries(fail-comm ${PROTOBUF_LIBRARY})
|
||||
|
||||
@@ -21,4 +21,10 @@ message DatabaseCampaignMessage {
|
||||
required string benchmark = 9 [(sql_ignore) = true];
|
||||
|
||||
required InjectionPointMessage injection_point = 10 [(sql_ignore) = true];
|
||||
}
|
||||
}
|
||||
|
||||
message DatabaseExperimentMessage {
|
||||
required uint32 bitoffset = 1 [(sql_primary_key) = true];
|
||||
required uint32 original_value = 2;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,31 +2,31 @@
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/VariantConfig.hpp.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/VariantConfig.hpp)
|
||||
|
||||
OPTION(CONFIG_EVENT_BREAKPOINTS "Event source: Breakpoints" OFF)
|
||||
OPTION(CONFIG_EVENT_BREAKPOINTS_RANGE "Event source: Range Breakpoints" OFF)
|
||||
OPTION(CONFIG_EVENT_MEMREAD "Event source: Memory reads" OFF)
|
||||
OPTION(CONFIG_EVENT_MEMWRITE "Event source: Memory writes" OFF)
|
||||
OPTION(CONFIG_EVENT_GUESTSYS "Event source: Outbound guest-system communication" OFF)
|
||||
OPTION(CONFIG_EVENT_IOPORT "Event source: I/O port communication" OFF)
|
||||
OPTION(CONFIG_EVENT_INTERRUPT "Event source: Interrupts" OFF)
|
||||
OPTION(CONFIG_EVENT_TRAP "Event source: Traps" OFF)
|
||||
OPTION(CONFIG_EVENT_BREAKPOINTS "Event source: Breakpoints" ON)
|
||||
OPTION(CONFIG_EVENT_BREAKPOINTS_RANGE "Event source: Range Breakpoints" ON)
|
||||
OPTION(CONFIG_EVENT_MEMREAD "Event source: Memory reads" ON)
|
||||
OPTION(CONFIG_EVENT_MEMWRITE "Event source: Memory writes" ON)
|
||||
OPTION(CONFIG_EVENT_GUESTSYS "Event source: Outbound guest-system communication" ON)
|
||||
OPTION(CONFIG_EVENT_IOPORT "Event source: I/O port communication" ON)
|
||||
OPTION(CONFIG_EVENT_INTERRUPT "Event source: Interrupts" ON)
|
||||
OPTION(CONFIG_EVENT_TRAP "Event source: Traps" ON)
|
||||
OPTION(CONFIG_EVENT_JUMP "Event source: Branch instructions" OFF)
|
||||
OPTION(CONFIG_SR_RESTORE "Target backend: State restore" OFF)
|
||||
OPTION(CONFIG_SR_SAVE "Target backend: State saving" OFF)
|
||||
OPTION(CONFIG_SR_REBOOT "Target backend: Reboot" OFF)
|
||||
OPTION(CONFIG_SR_RESTORE "Target backend: State restore" ON)
|
||||
OPTION(CONFIG_SR_SAVE "Target backend: State saving" ON)
|
||||
OPTION(CONFIG_SR_REBOOT "Target backend: Reboot" ON)
|
||||
OPTION(CONFIG_BOCHS_NON_VERBOSE "Misc: Reduced verbosity (a lot faster for large campaigns)" OFF)
|
||||
OPTION(CONFIG_BOCHS_NO_ABORT "Misc: Do not abort or ask the user in case the simulator stumbles on unexpected events (e.g., panics)" ON)
|
||||
OPTION(CONFIG_BOCHS_COMPRESS_STATE "Misc: Reduce Bochs save/restore size by compressing memory images" OFF)
|
||||
OPTION(CONFIG_SUPPRESS_INTERRUPTS "Target backend: Suppress interrupts" OFF)
|
||||
OPTION(CONFIG_FIRE_INTERRUPTS "Target backend: Fire interrupts" OFF)
|
||||
OPTION(CONFIG_BOCHS_COMPRESS_STATE "Misc: Reduce Bochs save/restore size by compressing memory images" ON)
|
||||
OPTION(CONFIG_SUPPRESS_INTERRUPTS "Target backend: Suppress interrupts" ON)
|
||||
OPTION(CONFIG_FIRE_INTERRUPTS "Target backend: Fire interrupts" ON)
|
||||
OPTION(CONFIG_DISABLE_KEYB_INTERRUPTS "Target backend: Suppress keyboard interrupts" OFF)
|
||||
OPTION(SERVER_PERFORMANCE_MEASURE "Performance measurement in job-server" OFF)
|
||||
OPTION(CONFIG_FAST_BREAKPOINTS "Enable fast breakpoints (requires breakpoint events to be enabled)" OFF)
|
||||
OPTION(CONFIG_FAST_WATCHPOINTS "Enable fast watchpoints (requires memory access events to be enabled)" OFF)
|
||||
OPTION(CONFIG_FAST_BREAKPOINTS "Enable fast breakpoints (requires breakpoint events to be enabled)" ON)
|
||||
OPTION(CONFIG_FAST_WATCHPOINTS "Enable fast watchpoints (requires memory access events to be enabled)" ON)
|
||||
OPTION(CONFIG_INJECTIONPOINT_HOPS "Enable hop chain trace navigation to injection point" OFF)
|
||||
SET(SERVER_COMM_HOSTNAME "localhost" CACHE STRING "Job-server hostname or IP")
|
||||
SET(SERVER_COMM_TCP_PORT "1111" CACHE STRING "Job-server TCP port")
|
||||
SET(SERVER_OUT_QUEUE_SIZE "0" CACHE STRING "Queue size for outbound jobs (0 = unlimited)")
|
||||
SET(SERVER_OUT_QUEUE_SIZE "0" CACHE STRING "Queue size for outbound jobs (0 = unlimited)")
|
||||
SET(SERVER_PERF_LOG_PATH "perf.log" CACHE STRING "A file name for storing the server's performance log (CSV)")
|
||||
SET(SERVER_PERF_STEPPING_SEC "1" CACHE STRING "Stepping of performance measurements in seconds")
|
||||
SET(CLIENT_RAND_BACKOFF_TSTART "3" CACHE STRING "Lower limit of client's backoff phase in seconds")
|
||||
|
||||
@@ -114,12 +114,15 @@ bool DatabaseCampaign::run() {
|
||||
boost::thread collect_thread(&DatabaseCampaign::collect_result_thread, this);
|
||||
#endif
|
||||
|
||||
load_completed_pilots();
|
||||
|
||||
std::vector<Database::Variant> variantlist =
|
||||
db->get_variants(variants, variants_exclude, benchmarks, benchmarks_exclude);
|
||||
|
||||
// Which Pilots were already processed?
|
||||
load_completed_pilots(variantlist);
|
||||
|
||||
for (std::vector<Database::Variant>::const_iterator it = variantlist.begin();
|
||||
it != variantlist.end(); ++it) {
|
||||
// Push all other variants to the queue
|
||||
if (!run_variant(*it)) {
|
||||
log_send << "run_variant failed for " << it->variant << "/" << it->benchmark <<std::endl;
|
||||
return false;
|
||||
@@ -165,7 +168,7 @@ void DatabaseCampaign::collect_result_thread() {
|
||||
|
||||
bool DatabaseCampaign::run_variant(Database::Variant variant) {
|
||||
/* Gather jobs */
|
||||
int experiment_count;
|
||||
unsigned long experiment_count;
|
||||
std::stringstream ss;
|
||||
std::string sql_select = "SELECT p.id, p.injection_instr, p.injection_instr_absolute, p.data_address, p.data_width, t.instr1, t.instr2 ";
|
||||
ss << " FROM fsppilot p "
|
||||
@@ -252,14 +255,29 @@ bool DatabaseCampaign::run_variant(Database::Variant variant) {
|
||||
|
||||
}
|
||||
|
||||
void DatabaseCampaign::load_completed_pilots()
|
||||
void DatabaseCampaign::load_completed_pilots(std::vector<Database::Variant> &variants)
|
||||
{
|
||||
// If no variants were given, do nothing
|
||||
if (variants.size() == 0)
|
||||
return;
|
||||
|
||||
// load list of partially or completely finished pilots
|
||||
std::stringstream variant_str;
|
||||
bool comma = false;
|
||||
for (std::vector<Database::Variant>::const_iterator it = variants.begin();
|
||||
it != variants.end(); ++it) {
|
||||
if (comma) variant_str << ", ";
|
||||
variant_str << it->id;
|
||||
comma = true; // Next time we need a comma
|
||||
}
|
||||
log_send << "loading completed pilot IDs ..." << std::endl;
|
||||
|
||||
std::stringstream sql;
|
||||
sql << "SELECT pilot_id, COUNT(*) FROM " << db_connect.result_table()
|
||||
sql << "SELECT pilot_id, COUNT(*) FROM fsppilot p"
|
||||
<< " JOIN " << db_connect.result_table() << " r ON r.pilot_id = p.id"
|
||||
<< " WHERE variant_id in (" << variant_str.str() << ")"
|
||||
<< " GROUP BY pilot_id ";
|
||||
MYSQL_RES *ids = db->query_stream(sql.str().c_str());
|
||||
log_send << "loading completed pilot IDs ..." << std::endl;
|
||||
MYSQL_ROW row;
|
||||
unsigned rowcount = 0;
|
||||
while ((row = mysql_fetch_row(ids)) != 0) {
|
||||
|
||||
@@ -29,7 +29,7 @@ class DatabaseCampaign : public Campaign {
|
||||
int fspmethod_id; // !< Which fspmethod should be put out to the clients
|
||||
|
||||
void collect_result_thread();
|
||||
void load_completed_pilots();
|
||||
void load_completed_pilots(std::vector<fail::Database::Variant> &);
|
||||
unsigned existing_results_for_pilot(unsigned pilot_id);
|
||||
|
||||
#ifndef __puma
|
||||
|
||||
@@ -4,10 +4,12 @@ set(SRCS
|
||||
ExperimentFlow.hpp
|
||||
JobClient.hpp
|
||||
JobClient.cc
|
||||
DatabaseExperiment.hpp
|
||||
DatabaseExperiment.cc
|
||||
)
|
||||
|
||||
add_library(fail-efw ${SRCS})
|
||||
add_dependencies(fail-efw fail-comm)
|
||||
add_dependencies(fail-efw fail-protoc)
|
||||
target_link_libraries(fail-efw fail-comm)
|
||||
target_link_libraries(fail-efw fail-util) # WallclockTimer
|
||||
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "sal/SALConfig.hpp"
|
||||
#include "sal/Memory.hpp"
|
||||
#include "sal/Listener.hpp"
|
||||
#include "efw/DatabaseExperiment.hpp"
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/message.h>
|
||||
#include "comm/DatabaseCampaignMessage.pb.h"
|
||||
#include "sal/bochs/BochsListener.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace fail;
|
||||
using namespace google::protobuf;
|
||||
|
||||
// Check if configuration dependencies are satisfied:
|
||||
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE)
|
||||
#error This experiment needs: breakpoints, restore. Enable these in the configuration.
|
||||
#endif
|
||||
|
||||
DatabaseExperiment::~DatabaseExperiment() {
|
||||
delete this->m_jc;
|
||||
}
|
||||
|
||||
unsigned DatabaseExperiment::injectBitFlip(address_t data_address, unsigned bitpos){
|
||||
unsigned int value, injectedval;
|
||||
|
||||
value = m_mm.getByte(data_address);
|
||||
injectedval = value ^ (1 << bitpos);
|
||||
m_mm.setByte(data_address, injectedval);
|
||||
|
||||
m_log << "INJECTION at: 0x" << hex<< setw(2) << setfill('0') << data_address
|
||||
<< " value: 0x" << setw(2) << setfill('0') << value << " -> 0x"
|
||||
<< setw(2) << setfill('0') << (unsigned) m_mm.getByte(data_address) << endl;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T * protobufFindSubmessageByTypename(Message *msg, const std::string &name) {
|
||||
T * submessage = 0;
|
||||
const Descriptor *msg_type = msg->GetDescriptor();
|
||||
const Message::Reflection *ref = msg->GetReflection();
|
||||
const Descriptor *database_desc =
|
||||
DescriptorPool::generated_pool()->FindMessageTypeByName(name);
|
||||
assert(database_desc != 0);
|
||||
|
||||
size_t count = msg_type->field_count();
|
||||
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
const FieldDescriptor *field = msg_type->field(i);
|
||||
assert(field != 0);
|
||||
if (field->message_type() == database_desc) {
|
||||
submessage = dynamic_cast<T*>(ref->MutableMessage(msg, field));
|
||||
assert(submessage != 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return submessage;
|
||||
}
|
||||
|
||||
|
||||
bool DatabaseExperiment::run()
|
||||
{
|
||||
m_log << "STARTING EXPERIMENT" << endl;
|
||||
|
||||
if (!this->cb_start_experiment()) {
|
||||
m_log << "Initialization failed. Exiting." << endl;
|
||||
simulator.terminate(1);
|
||||
}
|
||||
|
||||
unsigned executed_jobs = 0;
|
||||
|
||||
while (executed_jobs < 25 || m_jc->getNumberOfUndoneJobs() > 0) {
|
||||
m_log << "asking jobserver for parameters" << endl;
|
||||
ExperimentData * param = this->cb_allocate_experiment_data();
|
||||
if (!m_jc->getParam(*param)){
|
||||
m_log << "Dying." << endl; // We were told to die.
|
||||
simulator.terminate(1);
|
||||
}
|
||||
m_current_param = param;
|
||||
|
||||
DatabaseCampaignMessage * fsppilot =
|
||||
protobufFindSubmessageByTypename<DatabaseCampaignMessage>(¶m->getMessage(), "DatabaseCampaignMessage");
|
||||
assert (fsppilot != 0);
|
||||
|
||||
unsigned injection_instr = fsppilot->injection_instr();
|
||||
address_t data_address = fsppilot->data_address();
|
||||
unsigned width = fsppilot->data_width();
|
||||
|
||||
for (unsigned bit_offset = 0; bit_offset < width * 8; ++bit_offset) {
|
||||
// 8 results in one job
|
||||
Message *outer_result = cb_new_result(param);
|
||||
m_current_result = outer_result;
|
||||
DatabaseExperimentMessage *result =
|
||||
protobufFindSubmessageByTypename<DatabaseExperimentMessage>(outer_result, "DatabaseExperimentMessage");
|
||||
result->set_bitoffset(bit_offset);
|
||||
m_log << "restoring state" << endl;
|
||||
// Restore to the image, which starts at address(main)
|
||||
simulator.restore(cb_state_directory());
|
||||
executed_jobs ++;
|
||||
|
||||
m_log << "Trying to inject @ instr #" << dec << injection_instr << endl;
|
||||
|
||||
simulator.clearListeners();
|
||||
|
||||
// Generate an experiment listener, that matches on any IP
|
||||
// event. It is used to forward to the injection
|
||||
// point. The +1 is needed, since even for the zeroth
|
||||
// dynamic instruction we need at least one breakpoint
|
||||
// event.
|
||||
BPSingleListener bp;
|
||||
bp.setWatchInstructionPointer(ANY_ADDR);
|
||||
bp.setCounter(injection_instr + 1);
|
||||
simulator.addListener(&bp);
|
||||
|
||||
if (!this->cb_before_fast_forward()) {
|
||||
continue;
|
||||
}
|
||||
fail::BaseListener * listener;
|
||||
while (true) {
|
||||
listener = simulator.resume();
|
||||
if (listener == &bp) {
|
||||
break;
|
||||
} else {
|
||||
bool should_continue = this->cb_during_fast_forward(listener);
|
||||
if (!should_continue)
|
||||
break; // Stop fast forwarding
|
||||
}
|
||||
}
|
||||
if (!this->cb_after_fast_forward(listener)) {
|
||||
continue; // Continue to next injection experiment
|
||||
}
|
||||
|
||||
address_t injection_instr_absolute = fsppilot->injection_instr_absolute();
|
||||
bool found_eip;
|
||||
for (int i = 0; i < BX_SMP_PROCESSORS; i++) {
|
||||
address_t eip = simulator.getCPU(i).getInstructionPointer();
|
||||
if (eip == injection_instr_absolute) {
|
||||
found_eip = true;
|
||||
}
|
||||
}
|
||||
if (!found_eip) {
|
||||
m_log << "Invalid Injection address != 0x" << injection_instr_absolute << std::endl;
|
||||
simulator.terminate(1);
|
||||
}
|
||||
|
||||
simulator.clearListeners();
|
||||
|
||||
/// INJECT BITFLIP:
|
||||
result->set_original_value(injectBitFlip(data_address, bit_offset));
|
||||
|
||||
if (!this->cb_before_resume()) {
|
||||
continue; // Continue to next experiment
|
||||
}
|
||||
|
||||
m_log << "Resuming till the crash" << std::endl;
|
||||
// resume and wait for results
|
||||
while (true) {
|
||||
listener = simulator.resume();
|
||||
bool should_continue = this->cb_during_resume(listener);
|
||||
if (!should_continue)
|
||||
break;
|
||||
}
|
||||
m_log << "Resume done" << std::endl;
|
||||
this->cb_after_resume(listener);
|
||||
|
||||
simulator.clearListeners();
|
||||
}
|
||||
m_jc->sendResult(*param);
|
||||
this->cb_free_experiment_data(param);
|
||||
}
|
||||
// Explicitly terminate, or the simulator will continue to run.
|
||||
simulator.terminate();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
#ifndef __DATABASE_EXPERIMENT_HPP__
|
||||
#define __DATABASE_EXPERIMENT_HPP__
|
||||
|
||||
#include <google/protobuf/message.h>
|
||||
#include "efw/ExperimentFlow.hpp"
|
||||
#include "efw/JobClient.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace fail {
|
||||
class ExperimentData;
|
||||
|
||||
class DatabaseExperiment : public fail::ExperimentFlow {
|
||||
fail::JobClient *m_jc;
|
||||
|
||||
unsigned injectBitFlip(fail::address_t data_address, unsigned bitpos);
|
||||
|
||||
/**
|
||||
The current experiment data as returned by the job client. This
|
||||
allocated by cb_allocate_experiment_data()
|
||||
*/
|
||||
ExperimentData *m_current_param;
|
||||
google::protobuf::Message *m_current_result;
|
||||
|
||||
public:
|
||||
DatabaseExperiment(const std::string &name)
|
||||
: m_log(name, false), m_mm(fail::simulator.getMemoryManager()) {
|
||||
|
||||
/* The fail server can be set with an environent variable,
|
||||
otherwise the JOBSERVER configured by cmake ist used */
|
||||
char *server_host = getenv("FAIL_SERVER_HOST");
|
||||
if (server_host != NULL){
|
||||
this->m_jc = new fail::JobClient(std::string(server_host));
|
||||
} else {
|
||||
this->m_jc = new fail::JobClient();
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~DatabaseExperiment();
|
||||
|
||||
bool run();
|
||||
|
||||
|
||||
protected:
|
||||
fail::Logger m_log;
|
||||
fail::MemoryManager& m_mm;
|
||||
|
||||
/** Returns the currently running experiment message as returned
|
||||
* by the job client
|
||||
*/
|
||||
ExperimentData * get_current_experiment_data() { return m_current_param; }
|
||||
|
||||
/** Returns the currently result message, that was allocated by
|
||||
* cb_allocate_new_result.
|
||||
*/
|
||||
google::protobuf::Message * get_current_result() { return m_current_result; }
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Can be overwritten by experiment
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Get path to the state directory
|
||||
*/
|
||||
virtual std::string cb_state_directory() { return "state"; }
|
||||
|
||||
/**
|
||||
* Callback that is called, before the actual experiment
|
||||
* starts. Simulation is terminated on false.
|
||||
* @param The current result message
|
||||
* @return \c true on success, \c false otherwise
|
||||
*/
|
||||
virtual bool cb_start_experiment() { return true; };
|
||||
|
||||
/**
|
||||
* Allocate enough space to hold the incoming ExperimentData
|
||||
* message. The can be accessed during the experiment through
|
||||
* get_current_experiment_data()
|
||||
*/
|
||||
virtual ExperimentData* cb_allocate_experiment_data() = 0;
|
||||
virtual void cb_free_experiment_data(ExperimentData *) {};
|
||||
|
||||
|
||||
/**
|
||||
* Allocate a new result slot in the given experiment data. The
|
||||
* returned pointer can be obtained by calling
|
||||
* get_current_result()
|
||||
*/
|
||||
virtual google::protobuf::Message* cb_new_result(ExperimentData*) = 0;
|
||||
|
||||
/**
|
||||
* Callback that is called before the fast forward is done. This
|
||||
* can be used to add additional event listeners during the fast
|
||||
* forward phase. If returning false, the experiment is canceled.
|
||||
* @return \c true on success, \c false otherwise
|
||||
*/
|
||||
virtual bool cb_before_fast_forward() { return true; };
|
||||
|
||||
/**
|
||||
* Callback that is called during the fast forward, when an event
|
||||
* has triggered, but it was not the fast forward listener. This
|
||||
* can be used to collect additional information during the fast
|
||||
* forward If returning false, the fast forwarding is stopped.
|
||||
*
|
||||
* @return \c true on should continue, \c false stop ff
|
||||
*/
|
||||
virtual bool cb_during_fast_forward(fail::BaseListener *) { return false; };
|
||||
|
||||
/**
|
||||
* Callback that is called after the fast forward, with the last
|
||||
* triggered event forward If returning false, the experiment is
|
||||
* canceled.
|
||||
*
|
||||
* @return \c true on success, \c false otherwise
|
||||
*/
|
||||
virtual bool cb_after_fast_forward(fail::BaseListener *) { return true; };
|
||||
|
||||
/**
|
||||
* Callback that is called before the resuming till crash has
|
||||
* started. This is called after the fault was injected. Here the
|
||||
* end listeners should be installed. Returns true on
|
||||
* success. Otherwise the experiment is canceled.
|
||||
|
||||
* @return \c true on success, \c false otherwise
|
||||
*/
|
||||
virtual bool cb_before_resume() = 0;
|
||||
|
||||
/**
|
||||
* Callback that is called during the resume-till-crash phase,
|
||||
* when an event has triggered, This can be used to collect
|
||||
* additional information during the resuming phse. If returning
|
||||
* false, the resuming has finished and the experiment has stopped.
|
||||
*
|
||||
* @return \c true on should continue ff, \c false stop ff
|
||||
*/
|
||||
virtual bool cb_during_resume(fail::BaseListener *) { return false; };
|
||||
|
||||
/**
|
||||
* Callback that is called after the resume-till-crash phase with
|
||||
* the last triggered listener. This callback should collect all data and
|
||||
*
|
||||
*/
|
||||
virtual void cb_after_resume(fail::BaseListener *) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // __DATABASE_EXPERIMENT_HPP__
|
||||
@@ -749,9 +749,20 @@ public:
|
||||
void setId(timer_id_t id) { m_Data.setId(id); }
|
||||
/**
|
||||
* Retrieves the timer's timeout value.
|
||||
* @return the timout in microseconds
|
||||
* @return the timeout in microseconds
|
||||
*/
|
||||
unsigned getTimeout() const { return m_Timeout; }
|
||||
/**
|
||||
* Set the timeout value. Returns the old timeout value. Be aware,
|
||||
* that this method might have no effects, after the listener was added.
|
||||
* @return the old timeout in microseconds
|
||||
*/
|
||||
unsigned setTimeout(unsigned timeout) {
|
||||
unsigned tmp = m_Timeout;
|
||||
m_Timeout = timeout;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end-of-namespace: fail
|
||||
|
||||
@@ -12,29 +12,33 @@
|
||||
#include "../SALInst.hpp"
|
||||
#include "BochsHelpers.hpp"
|
||||
|
||||
// TODO: ATM only capturing bytewise output (most common, I suppose)
|
||||
// FIXME ATM only capturing the first byte of a multi-byte in/out
|
||||
|
||||
aspect IOPortCom {
|
||||
pointcut outInstruction() = "% ...::bx_cpu_c::OUT_DXAL(...)";
|
||||
pointcut devices_outp() = "% ...::bx_devices_c::outp(...)";
|
||||
|
||||
advice execution (outInstruction()) : after ()
|
||||
advice call (devices_outp()) && within ("...::bx_cpu_c") : before ()
|
||||
{
|
||||
unsigned rDX = getCPU(tjp->that())->gen_reg[2].word.rx; // port number
|
||||
unsigned char rAL = getCPU(tjp->that())->gen_reg[0].word.byte.rl; // data
|
||||
|
||||
// Detect the CPU that triggered the change:
|
||||
unsigned port = *(tjp->arg<0>());
|
||||
unsigned data = *(tjp->arg<1>());
|
||||
|
||||
// detect the CPU that triggered the access
|
||||
fail::ConcreteCPU& triggerCPU = fail::simulator.detectCPU(getCPU(tjp->that()));
|
||||
fail::simulator.onIOPort(&triggerCPU, rAL, rDX, true);
|
||||
// forward to SimulatorController
|
||||
fail::simulator.onIOPort(&triggerCPU, data, port, true);
|
||||
}
|
||||
|
||||
pointcut inInstruction() = "% ...::bx_cpu_c::IN_ALDX(...)";
|
||||
pointcut devices_inp() = "% ...::bx_devices_c::inp(...)";
|
||||
|
||||
advice execution (inInstruction()) : after ()
|
||||
advice call (devices_inp()) && within ("...::bx_cpu_c") : after ()
|
||||
{
|
||||
unsigned rDX = getCPU(tjp->that())->gen_reg[2].word.rx; // port number
|
||||
unsigned char rAL = getCPU(tjp->that())->gen_reg[0].word.byte.rl; // data
|
||||
unsigned port = *(tjp->arg<0>());
|
||||
unsigned data = *(tjp->result());
|
||||
|
||||
// detect the CPU that triggered the access
|
||||
fail::ConcreteCPU& triggerCPU = fail::simulator.detectCPU(getCPU(tjp->that()));
|
||||
fail::simulator.onIOPort(&triggerCPU, rAL, rDX, false);
|
||||
// forward to SimulatorController
|
||||
fail::simulator.onIOPort(&triggerCPU, data, port, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -91,4 +91,5 @@ target_link_libraries(memorymap-test fail-util)
|
||||
add_test(NAME memorymap-test WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/testing COMMAND memorymap-test)
|
||||
|
||||
add_executable(sumtree-test testing/SumTreeTest.cc)
|
||||
target_link_libraries(sumtree-test fail-util)
|
||||
add_test(NAME sumtree-test WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/testing COMMAND sumtree-test)
|
||||
|
||||
@@ -43,8 +43,13 @@ bool CommandLine::parse() {
|
||||
option::Descriptor desc = {0, 0, 0, 0, 0, 0};
|
||||
this->options.push_back(desc);
|
||||
|
||||
// Generate the options stats
|
||||
option::Stats stats(this->options.data(), argv.size(), argv.data());
|
||||
// Copy argv to preserve original argument order
|
||||
// (for proper re-parsing after adding more options)
|
||||
argv_reordered = argv;
|
||||
|
||||
// Generate the options stats (GNU mode)
|
||||
option::Stats stats(true, this->options.data(),
|
||||
argv_reordered.size(), argv_reordered.data());
|
||||
|
||||
if (parsed_options)
|
||||
delete[] parsed_options;
|
||||
@@ -56,9 +61,9 @@ bool CommandLine::parse() {
|
||||
parsed_options = new option::Option[stats.options_max];
|
||||
parsed_buffer = new option::Option[stats.buffer_max];
|
||||
|
||||
m_parser = new option::Parser(this->options.data(), argv.size(), argv.data(),
|
||||
parsed_options, parsed_buffer);
|
||||
|
||||
m_parser = new option::Parser(true, this->options.data(),
|
||||
argv_reordered.size(), argv_reordered.data(),
|
||||
parsed_options, parsed_buffer);
|
||||
|
||||
// Pop the terminating entry
|
||||
this->options.pop_back();
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
private:
|
||||
static CommandLine m_instance;
|
||||
|
||||
std::vector<const char *> argv;
|
||||
std::vector<const char *> argv, argv_reordered;
|
||||
std::vector<option::Descriptor> options;
|
||||
option::Option *parsed_options, *parsed_buffer;
|
||||
option::Parser *m_parser;
|
||||
|
||||
@@ -133,9 +133,11 @@ void DatabaseProtobufAdapter::TypeBridge_string::bind(MYSQL_BIND *bind, const go
|
||||
/* Handle the NULL case */
|
||||
if (insert_null(bind, msg)) return;
|
||||
|
||||
buffer = ref->GetString(*msg, desc);
|
||||
|
||||
bind->buffer_type = MYSQL_TYPE_STRING;
|
||||
bind->buffer = (void *) ref->GetString(*msg, desc).c_str();
|
||||
bind->buffer_length = ref->GetString(*msg, desc).length();
|
||||
bind->buffer = (void *) buffer.c_str();
|
||||
bind->buffer_length = buffer.length();
|
||||
}
|
||||
void DatabaseProtobufAdapter::TypeBridge_enum::bind(MYSQL_BIND *bind, const google::protobuf::Message *msg) {
|
||||
const google::protobuf::Reflection *ref = msg->GetReflection();
|
||||
|
||||
@@ -80,7 +80,7 @@ class DatabaseProtobufAdapter {
|
||||
TypeBridge_uint32(const google::protobuf::FieldDescriptor *desc)
|
||||
: TypeBridge(desc){};
|
||||
|
||||
virtual std::string sql_type() { return "INT"; };
|
||||
virtual std::string sql_type() { return "INT UNSIGNED"; };
|
||||
virtual int element_size() { return 4; };
|
||||
virtual void copy_to(const google::protobuf::Message *msg, int i, void *);
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
@@ -101,7 +101,7 @@ class DatabaseProtobufAdapter {
|
||||
TypeBridge_uint64(const google::protobuf::FieldDescriptor *desc)
|
||||
: TypeBridge(desc){};
|
||||
|
||||
virtual std::string sql_type() { return "BIGINT"; };
|
||||
virtual std::string sql_type() { return "BIGINT UNSIGNED"; };
|
||||
virtual int element_size() { return 8; };
|
||||
virtual void copy_to(const google::protobuf::Message *msg, int i, void *);
|
||||
virtual void bind(MYSQL_BIND *bind, const google::protobuf::Message *msg);
|
||||
@@ -138,6 +138,7 @@ class DatabaseProtobufAdapter {
|
||||
};
|
||||
|
||||
struct TypeBridge_string : TypeBridge {
|
||||
std::string buffer;
|
||||
TypeBridge_string(const google::protobuf::FieldDescriptor *desc)
|
||||
: TypeBridge(desc){};
|
||||
virtual std::string sql_type() { return "TEXT"; };
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <map>
|
||||
|
||||
#include "DwarfReader.hpp"
|
||||
#include "libdwarf.h"
|
||||
@@ -128,8 +130,10 @@ bool DwarfReader::read_source_files(const std::string& fileName,std::list<std::s
|
||||
while (dwarf_next_cu_header(dbg,0,0,0,0,&header,0)==DW_DLV_OK) {
|
||||
// Access the die
|
||||
Dwarf_Die die;
|
||||
if (dwarf_siblingof(dbg,0,&die,0)!=DW_DLV_OK)
|
||||
if (dwarf_siblingof(dbg,0,&die,0)!=DW_DLV_OK) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the source lines
|
||||
Dwarf_Line* lineBuffer;
|
||||
@@ -140,17 +144,25 @@ bool DwarfReader::read_source_files(const std::string& fileName,std::list<std::s
|
||||
// Store them
|
||||
for (int index=0;index<lineCount;index++) {
|
||||
Dwarf_Unsigned lineNo;
|
||||
if (dwarf_lineno(lineBuffer[index],&lineNo,0)!=DW_DLV_OK)
|
||||
if (dwarf_lineno(lineBuffer[index],&lineNo,0)!=DW_DLV_OK){
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
char* lineSource;
|
||||
if (dwarf_linesrc(lineBuffer[index],&lineSource,0)!=DW_DLV_OK)
|
||||
if (dwarf_linesrc(lineBuffer[index],&lineSource,0)!=DW_DLV_OK){
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
Dwarf_Bool isCode;
|
||||
if (dwarf_linebeginstatement(lineBuffer[index],&isCode,0)!=DW_DLV_OK)
|
||||
if (dwarf_linebeginstatement(lineBuffer[index],&isCode,0)!=DW_DLV_OK){
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
Dwarf_Addr addr;
|
||||
if (dwarf_lineaddr(lineBuffer[index],&addr,0)!=DW_DLV_OK)
|
||||
if (dwarf_lineaddr(lineBuffer[index],&addr,0)!=DW_DLV_OK){
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lineNo&&isCode) {
|
||||
//LOG << "lineNo: " << lineNo << " addr: " << reinterpret_cast<void*>(addr) << " line source:" << normalize(lineSource) << endl;
|
||||
@@ -171,14 +183,20 @@ bool DwarfReader::read_source_files(const std::string& fileName,std::list<std::s
|
||||
lines.unique();
|
||||
|
||||
// Shut down libdwarf
|
||||
if (dwarf_finish(dbg,0)!=DW_DLV_OK)
|
||||
if (dwarf_finish(dbg,0)!=DW_DLV_OK) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DwarfReader::read_mapping(std::string fileName, std::list<addrToLine>& addrToLineList) {
|
||||
bool DwarfReader::read_mapping(std::string fileName, std::list<DwarfLineMapping>& lineMapping) {
|
||||
// temporary mapping of instruction address to (file, line)
|
||||
// => static instruction addresses are sorted ascendingly for the whole binary
|
||||
// (i.e. all instructions from all CUs!)
|
||||
std::map<unsigned, SourceLine> instr_to_sourceline;
|
||||
|
||||
// Open The file
|
||||
int fd=open(fileName.c_str(),O_RDONLY);
|
||||
@@ -200,10 +218,13 @@ bool DwarfReader::read_mapping(std::string fileName, std::list<addrToLine>& addr
|
||||
|
||||
// Iterator over the headers
|
||||
Dwarf_Unsigned header;
|
||||
// iterate compilation unit headers
|
||||
while (dwarf_next_cu_header(dbg,0,0,0,0,&header,0)==DW_DLV_OK) {
|
||||
// Access the die
|
||||
Dwarf_Die die;
|
||||
// XXX: "if there are no sibling headers, die" | semantics unclear!
|
||||
if (dwarf_siblingof(dbg,0,&die,0)!=DW_DLV_OK) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -211,6 +232,7 @@ bool DwarfReader::read_mapping(std::string fileName, std::list<addrToLine>& addr
|
||||
Dwarf_Line* lineBuffer;
|
||||
Dwarf_Signed lineCount;
|
||||
if (dwarf_srclines(die,&lineBuffer,&lineCount,0)!=DW_DLV_OK) {
|
||||
close(fd);
|
||||
continue; //return false;
|
||||
}
|
||||
|
||||
@@ -218,24 +240,30 @@ bool DwarfReader::read_mapping(std::string fileName, std::list<addrToLine>& addr
|
||||
for (int index=0;index<lineCount;index++) {
|
||||
Dwarf_Unsigned lineNo;
|
||||
if (dwarf_lineno(lineBuffer[index],&lineNo,0)!=DW_DLV_OK) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
char* lineSource;
|
||||
if (dwarf_linesrc(lineBuffer[index],&lineSource,0)!=DW_DLV_OK) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
Dwarf_Bool isCode;
|
||||
if (dwarf_linebeginstatement(lineBuffer[index],&isCode,0)!=DW_DLV_OK) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
Dwarf_Addr addr;
|
||||
if (dwarf_lineaddr(lineBuffer[index],&addr,0)!=DW_DLV_OK) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lineNo&&isCode) {
|
||||
struct addrToLine newLine = { (int) addr, (int) lineNo, normalize(lineSource) };
|
||||
addrToLineList.push_back(newLine);
|
||||
// wrap line_number and source_file into an object
|
||||
SourceLine tmp_sl(normalize(lineSource), lineNo);
|
||||
// store SourceLine object with static instr in the map
|
||||
instr_to_sourceline.insert(std::make_pair(addr, tmp_sl));
|
||||
}
|
||||
|
||||
dwarf_dealloc(dbg,lineSource,DW_DLA_STRING);
|
||||
@@ -250,9 +278,30 @@ bool DwarfReader::read_mapping(std::string fileName, std::list<addrToLine>& addr
|
||||
|
||||
// Shut down libdwarf
|
||||
if (dwarf_finish(dbg,0)!=DW_DLV_OK) {
|
||||
close(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
// iterate instr_to_sourceline to determine the "line_range_size" for mapping
|
||||
std::map<unsigned, SourceLine>::iterator it;
|
||||
for (it = instr_to_sourceline.begin(); it != instr_to_sourceline.end(); it++) {
|
||||
unsigned addr = it->first;
|
||||
SourceLine sl = it->second;
|
||||
|
||||
/* Default the linetable's address range (->"size") to the maximum
|
||||
* possible value. This results in the last linetable entry having
|
||||
* maximum range. This entry will either be a dummy or a function's
|
||||
* epilogue, both of which are irrelevant for our (current) use cases.
|
||||
* All other entries' sizes are set properly. */
|
||||
DwarfLineMapping mapping(addr, (std::numeric_limits<unsigned>::max() - addr),
|
||||
sl.line_number, sl.source_file);
|
||||
if (!lineMapping.empty()) {
|
||||
DwarfLineMapping& back = lineMapping.back();
|
||||
back.line_range_size = addr - back.absolute_addr;
|
||||
}
|
||||
lineMapping.push_back(mapping);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,26 @@
|
||||
|
||||
namespace fail {
|
||||
|
||||
// temporary wrapper object for (file, linenumber)
|
||||
class SourceLine {
|
||||
public:
|
||||
std::string source_file;
|
||||
unsigned line_number;
|
||||
|
||||
SourceLine(std::string source, unsigned line) : source_file(source), line_number(line) {}
|
||||
};
|
||||
|
||||
// wrapper object for insertion into DB
|
||||
class DwarfLineMapping {
|
||||
public:
|
||||
unsigned absolute_addr;
|
||||
unsigned line_range_size;
|
||||
unsigned line_number;
|
||||
std::string line_source;
|
||||
|
||||
DwarfLineMapping(unsigned addr, unsigned size, unsigned number, std::string src)
|
||||
: absolute_addr(addr), line_range_size(size), line_number(number), line_source(src){}
|
||||
};
|
||||
|
||||
/**
|
||||
* This source code is based on bcov 0.2.
|
||||
@@ -15,23 +35,16 @@ namespace fail {
|
||||
* GNU GENERAL PUBLIC LICENSE
|
||||
*/
|
||||
|
||||
struct addrToLine {
|
||||
int absoluteAddr;
|
||||
int lineNumber;
|
||||
std::string lineSource;
|
||||
};
|
||||
|
||||
/**
|
||||
* \class DwarfReader
|
||||
* ToDO
|
||||
*/
|
||||
|
||||
class DwarfReader {
|
||||
/**
|
||||
* \class DwarfReader
|
||||
* ToDO
|
||||
*/
|
||||
class DwarfReader {
|
||||
|
||||
public:
|
||||
|
||||
bool read_source_files(const std::string& fileName, std::list<std::string>& lines);
|
||||
bool read_mapping(std::string fileName, std::list<addrToLine>& addrToLineList);
|
||||
bool read_mapping(std::string fileName, std::list<DwarfLineMapping>& lineMapping);
|
||||
};
|
||||
|
||||
} // end-of-namespace fail
|
||||
|
||||
@@ -19,11 +19,15 @@ bool MemoryMap::readFromFile(char const * const filename)
|
||||
unsigned count = 0;
|
||||
|
||||
while (getline(file, buf)) {
|
||||
std::string addr, len;
|
||||
std::stringstream ss(buf, std::ios::in);
|
||||
ss >> guest_addr >> guest_len;
|
||||
ss >> addr >> len;
|
||||
guest_addr = strtoul(addr.c_str(), NULL, 0);
|
||||
guest_len = strtoul(len.c_str(), NULL, 0);
|
||||
add(guest_addr, guest_len);
|
||||
count++;
|
||||
}
|
||||
|
||||
// assertion kept from original code; usually something's fishy if the file
|
||||
// contains no entries
|
||||
assert(count > 0);
|
||||
|
||||
@@ -11,8 +11,7 @@ set(SRCS
|
||||
|
||||
include(FindLLVM)
|
||||
|
||||
# compiling without -fno-rtti fails even when LLVM is not built with that flag
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_CXX_FLAGS} -fno-rtti" )
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_CXX_FLAGS}" )
|
||||
|
||||
add_library(fail-llvmdisassembler ${SRCS})
|
||||
target_link_libraries(fail-llvmdisassembler fail-sal)
|
||||
|
||||
@@ -49,7 +49,10 @@ LLVMtoFailTranslator* LLVMtoFailTranslator::createFromBinary(const std::string e
|
||||
llvm::InitializeAllDisassemblers();
|
||||
|
||||
OwningPtr<Binary> binary;
|
||||
assert(createBinary(elf_path, binary) == 0);
|
||||
llvm::error_code ret = createBinary(elf_path, binary);
|
||||
assert (ret == 0);
|
||||
(void) ret; // unused in release builds
|
||||
assert (binary.get() != NULL);
|
||||
|
||||
#ifndef __puma
|
||||
LLVMDisassembler disas(dyn_cast<ObjectFile>(binary.get()));
|
||||
@@ -57,4 +60,4 @@ LLVMtoFailTranslator* LLVMtoFailTranslator::createFromBinary(const std::string e
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#ifndef __puma
|
||||
#include "../LLVMDisassembler.hpp"
|
||||
|
||||
using namespace llvm;
|
||||
@@ -69,4 +68,3 @@ int main(int argc, char* argv[]) {
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#include "util/SumTree.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#define LOG std::cerr
|
||||
|
||||
using std::endl;
|
||||
|
||||
fail::Logger LOG("SumTreeTest");
|
||||
|
||||
struct Pilot {
|
||||
uint32_t id;
|
||||
uint32_t instr2;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <stdlib.h>
|
||||
#include "util/MemoryMap.hpp"
|
||||
|
||||
using namespace fail;
|
||||
@@ -16,6 +17,7 @@ uint32_t outside[] = { 0, 10, 16, 1, 20, 1, 25, 10 };
|
||||
void test_failed(std::string msg)
|
||||
{
|
||||
cerr << "MemoryMap test failed (" << msg << ")!" << endl;
|
||||
abort();
|
||||
}
|
||||
|
||||
// pass by value intentional
|
||||
@@ -98,6 +100,7 @@ int main()
|
||||
char const *filename_tmp = "tmp.memorymap";
|
||||
char const *filename_test1 = "test1.memorymap";
|
||||
char const *filename_test2 = "test2.memorymap";
|
||||
char const *filename_test3 = "test3.memorymap";
|
||||
|
||||
for (unsigned i = 0; i < LEN(inside); i += 2) {
|
||||
mm.add(inside[i], inside[i+1]);
|
||||
@@ -125,4 +128,8 @@ int main()
|
||||
mm.clear();
|
||||
mm.readFromFile(filename_test2);
|
||||
test(mm);
|
||||
|
||||
mm.clear();
|
||||
mm.readFromFile(filename_test3);
|
||||
test(mm);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
012 0x6
|
||||
0x11 3
|
||||
21 0x4
|
||||
@@ -0,0 +1,37 @@
|
||||
set(EXPERIMENT_NAME cored-tester)
|
||||
set(EXPERIMENT_TYPE CoredTester)
|
||||
configure_file(../instantiate-experiment.ah.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY
|
||||
)
|
||||
|
||||
## Setup desired protobuf descriptions HERE ##
|
||||
set(MY_PROTOS
|
||||
cored-tester.proto
|
||||
)
|
||||
|
||||
set(MY_CAMPAIGN_SRCS
|
||||
experiment.hpp
|
||||
experiment.cc
|
||||
campaign.hpp
|
||||
campaign.cc
|
||||
)
|
||||
|
||||
#### PROTOBUFS ####
|
||||
find_package(Protobuf REQUIRED)
|
||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm)
|
||||
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
|
||||
|
||||
## Build library
|
||||
add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS})
|
||||
add_dependencies(fail-${EXPERIMENT_NAME} fail-comm)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} fail-comm)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY} fail-llvmdisassembler)
|
||||
|
||||
## This is the example's campaign server distributing experiment parameters
|
||||
add_executable(${EXPERIMENT_NAME}-server main.cc)
|
||||
target_link_libraries(${EXPERIMENT_NAME}-server -Wl,--start-group fail-${EXPERIMENT_NAME} fail-sal fail-util fail-cpn fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} ${Boost_SYSTEM_LIBRARY} -lmysqlclient -Wl,--end-group)
|
||||
install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin)
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "campaign.hpp"
|
||||
#include "cpn/CampaignManager.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include "util/ElfReader.hpp"
|
||||
#include "util/ProtoStream.hpp"
|
||||
#include "sal/SALConfig.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace fail;
|
||||
using namespace google::protobuf;
|
||||
|
||||
void CoredTesterCampaign::cb_send_pilot(DatabaseCampaignMessage pilot) {
|
||||
CoredTesterExperimentData *data = new CoredTesterExperimentData;
|
||||
data->msg.mutable_fsppilot()->CopyFrom(pilot);
|
||||
campaignmanager.addParam(data);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef __DCIAOCAMPAIGN_HPP__
|
||||
#define __DCIAOCAMPAIGN_HPP__
|
||||
|
||||
#include "cpn/DatabaseCampaign.hpp"
|
||||
#include "comm/ExperimentData.hpp"
|
||||
#include "cored-tester.pb.h"
|
||||
#include "util/ElfReader.hpp"
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
class CoredTesterExperimentData : public fail::ExperimentData {
|
||||
public:
|
||||
CoredTesterProtoMsg msg;
|
||||
CoredTesterExperimentData() : fail::ExperimentData(&msg) {}
|
||||
};
|
||||
|
||||
class CoredTesterCampaign : public fail::DatabaseCampaign {
|
||||
virtual const google::protobuf::Descriptor * cb_result_message()
|
||||
{ return google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("CoredTesterProtoMsg"); }
|
||||
|
||||
virtual void cb_send_pilot(DatabaseCampaignMessage pilot);
|
||||
virtual int expected_number_of_results(std::string variant, std::string benchmark) {
|
||||
if (benchmark.find("jump") != std::string::npos)
|
||||
return 1;
|
||||
else
|
||||
return 8;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif // __KESOREFCAMPAIGN_HPP__
|
||||
@@ -0,0 +1,39 @@
|
||||
import "DatabaseCampaignMessage.proto";
|
||||
|
||||
message CoredTesterProtoMsg {
|
||||
required DatabaseCampaignMessage fsppilot = 1;
|
||||
|
||||
repeated group Result = 2 {
|
||||
enum ResultType {
|
||||
/* Test did the right thing */
|
||||
OK = 1;
|
||||
OK_DETECTED_ERROR = 3;
|
||||
|
||||
/* Test did the wrong thing */
|
||||
SDC_WRONG_RESULT = 4;
|
||||
|
||||
/* Test detected the error */
|
||||
ERR_TRAP = 5;
|
||||
ERR_TIMEOUT = 6;
|
||||
|
||||
ERR_ASSERT_UNKOWN = 7;
|
||||
ERR_ASSERT_SYSTEM_STATE = 8;
|
||||
ERR_ASSERT_CFG_REGION = 9;
|
||||
ERR_ASSERT_SPURIOUS = 10;
|
||||
|
||||
UNKNOWN = 20;
|
||||
NOINJECTION = 21;
|
||||
}
|
||||
|
||||
required int32 bitoffset = 1 [(sql_primary_key) = true];
|
||||
required ResultType resulttype = 2;
|
||||
required uint32 experiment_number = 3;
|
||||
|
||||
/* At which point in time did the crash occur */
|
||||
optional uint64 time_crash = 4;
|
||||
|
||||
optional uint32 original_value = 5;
|
||||
|
||||
optional string details = 6;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,586 @@
|
||||
#undef NDEBUG
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "experiment.hpp"
|
||||
#include "sal/SALConfig.hpp"
|
||||
#include "sal/SALInst.hpp"
|
||||
#include "sal/Memory.hpp"
|
||||
#include "sal/Listener.hpp"
|
||||
|
||||
#include "sal/bochs/BochsListener.hpp"
|
||||
#include "sal/bochs/BochsMemory.hpp"
|
||||
#include "sal/bochs/BochsCPU.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
|
||||
#include "util/llvmdisassembler/LLVMtoFailTranslator.hpp"
|
||||
#include "util/llvmdisassembler/LLVMtoFailBochs.hpp"
|
||||
|
||||
#include "campaign.hpp"
|
||||
#include "cored-tester.pb.h"
|
||||
|
||||
#include "../plugins/randomgenerator/RandomGenerator.hpp"
|
||||
#include "../plugins/checkpoint/Checkpoint.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace fail;
|
||||
|
||||
#define SAFESTATE (1)
|
||||
|
||||
// Check if configuration dependencies are satisfied:
|
||||
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \
|
||||
!defined(CONFIG_SR_SAVE)
|
||||
#error This experiment needs: breakpoints, traps, save, and restore. Enable these in the configuration.
|
||||
#endif
|
||||
#if !defined(CONFIG_EVENT_MEMREAD) || !defined(CONFIG_EVENT_MEMWRITE)
|
||||
#error This experiment needs: MemRead and MemWrite. Enable these in the configuration.
|
||||
#endif
|
||||
|
||||
void CoredTester::redecodeCurrentInstruction() {
|
||||
/* Flush Instruction Caches and Prefetch queue */
|
||||
BX_CPU_C *cpu_context = simulator.getCPUContext();
|
||||
cpu_context->invalidate_prefetch_q();
|
||||
cpu_context->iCache.flushICacheEntries();
|
||||
|
||||
|
||||
guest_address_t pc = simulator.getCPU(0).getInstructionPointer();
|
||||
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
|
||||
//unsigned length_in_bytes = currInstr->ilen();
|
||||
|
||||
m_log << "REDECODE INSTRUCTION @ IP 0x" << std::hex << pc << endl;
|
||||
|
||||
Bit32u eipBiased = pc + cpu_context->eipPageBias;
|
||||
Bit8u instr_plain[15];
|
||||
|
||||
MemoryManager& mm = simulator.getMemoryManager();
|
||||
for(unsigned i=0; i<sizeof(instr_plain); i++) {
|
||||
if(!mm.isMapped(pc+i)) {
|
||||
m_log << "REDECODE: 0x" << std::hex << pc+i << "UNMAPPED" << endl;
|
||||
// TODO: error?
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mm.getBytes(pc, sizeof(instr_plain), instr_plain);
|
||||
|
||||
unsigned remainingInPage = cpu_context->eipPageWindowSize - eipBiased;
|
||||
int ret;
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (cpu_context->cpu_mode == BX_MODE_LONG_64)
|
||||
ret = cpu_context->fetchDecode64(instr_plain, currInstr, remainingInPage);
|
||||
else
|
||||
#endif
|
||||
ret = cpu_context->fetchDecode32(instr_plain, currInstr, remainingInPage);
|
||||
if (ret < 0) {
|
||||
// handle instrumentation callback inside boundaryFetch
|
||||
cpu_context->boundaryFetch(instr_plain, remainingInPage, currInstr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned CoredTester::injectBitFlip(address_t data_address, unsigned data_width, unsigned bitpos) {
|
||||
/* First 32 Registers, this might neeed adaption */
|
||||
if (data_address < (32 << 8)) {
|
||||
LLVMtoFailTranslator::reginfo_t reginfo = LLVMtoFailTranslator::reginfo_t::fromDataAddress(data_address, data_width);
|
||||
|
||||
unsigned int value, injectedval;
|
||||
|
||||
value = m_ltof->getRegisterContent(simulator.getCPU(0), reginfo);
|
||||
injectedval = value ^ (1 << bitpos);
|
||||
m_ltof->setRegisterContent(simulator.getCPU(0), reginfo, injectedval);
|
||||
|
||||
m_log << "INJECTING register (" << dec << reginfo.id
|
||||
<< " offset " << (int) reginfo.offset
|
||||
<< ") bitpos: " << bitpos
|
||||
<< " value: 0x" << hex << setw(2) << setfill('0') << value << " -> 0x" << setw(2) << setfill('0') << injectedval
|
||||
<< dec << endl;
|
||||
if (reginfo.id == RID_PC)
|
||||
redecodeCurrentInstruction();
|
||||
|
||||
return value;
|
||||
} else {
|
||||
unsigned int value, injectedval;
|
||||
|
||||
MemoryManager& mm = simulator.getMemoryManager();
|
||||
if(!mm.isMapped(data_address)) {
|
||||
m_log << "DATA_ADDRESS NOT MAPPED" << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = mm.getByte(data_address);
|
||||
injectedval = value ^ (1 << bitpos);
|
||||
mm.setByte(data_address, injectedval);
|
||||
|
||||
m_log << "INJECTION at: 0x" << hex << setw(2) << setfill('0') << data_address
|
||||
<< " value: 0x" << setw(2) << setfill('0') << value << " -> 0x" << setw(2) << setfill('0') << injectedval << endl;
|
||||
|
||||
/* If it is the current instruction redecode it */
|
||||
guest_address_t pc = simulator.getCPU(0).getInstructionPointer();
|
||||
m_log << "IP: 0x" << std::hex << pc << std::endl;
|
||||
bxInstruction_c *currInstr = simulator.getCurrentInstruction();
|
||||
assert(currInstr != NULL && "FATAL ERROR: current instruction was NULL (not expected)!");
|
||||
unsigned length_in_bytes = currInstr->ilen();
|
||||
|
||||
if (currInstr == NULL || (pc <= data_address && data_address <= (pc + currInstr->ilen()))) {
|
||||
redecodeCurrentInstruction();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handleEvent(CoredTesterProtoMsg_Result& result, CoredTesterProtoMsg_Result_ResultType restype, const std::string &msg) {
|
||||
cout << msg << endl;
|
||||
result.set_resulttype(restype);
|
||||
result.set_details(msg);
|
||||
}
|
||||
|
||||
|
||||
std::string handleMemoryAccessEvent(fail::MemAccessListener* l_mem) {
|
||||
stringstream sstr;
|
||||
|
||||
sstr << "mem access (";
|
||||
switch (l_mem->getTriggerAccessType()) {
|
||||
case MemAccessEvent::MEM_READ:
|
||||
sstr << "r";
|
||||
break;
|
||||
case MemAccessEvent::MEM_WRITE:
|
||||
sstr << "w";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
sstr << ") @ 0x" << hex << l_mem->getTriggerAddress();
|
||||
sstr << "; ip @ 0x" << hex << l_mem->getTriggerInstructionPointer();
|
||||
|
||||
return sstr.str();
|
||||
}
|
||||
|
||||
|
||||
const ElfSymbol& CoredTester::getELFSymbol(const std::string name) {
|
||||
const ElfSymbol &symbol = m_elf.getSymbol(name);
|
||||
if (!symbol.isValid()) {
|
||||
m_log << "Couldn't find symbol: " << name << std::endl;
|
||||
simulator.terminate(1);
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
|
||||
bool CoredTester::run() {
|
||||
m_log << "STARTING EXPERIMENT" << endl;
|
||||
|
||||
// seed random number generator
|
||||
timeval start;
|
||||
gettimeofday(&start, NULL);
|
||||
srand(start.tv_usec);
|
||||
|
||||
// get symbols
|
||||
const ElfSymbol &s_trace_end_marker = getELFSymbol("test_finish");
|
||||
BPSingleListener l_trace_end_marker(s_trace_end_marker.getAddress());
|
||||
|
||||
const ElfSymbol &s_stext_app = getELFSymbol("_stext_application");
|
||||
const ElfSymbol &s_etext_app = getELFSymbol("_etext_application");
|
||||
|
||||
const ElfSymbol &s_panic_handler = getELFSymbol("irq_handler_2");
|
||||
|
||||
const ElfSymbol &s_fail_trace = getELFSymbol("fail_trace");
|
||||
MemAccessListener l_fail_trace(s_fail_trace.getAddress());
|
||||
|
||||
const ElfSymbol &s_random_source = m_elf.getSymbol("random_source");
|
||||
|
||||
const ElfSymbol &s_color_assert_port = m_elf.getSymbol("color_assert_port");
|
||||
MemAccessListener l_color_assert_port(s_color_assert_port, MemAccessEvent::MEM_WRITE);
|
||||
|
||||
// allowed regions
|
||||
address_t text_tasks_start = s_stext_app.getAddress();
|
||||
address_t text_tasks_end = s_etext_app.getAddress();
|
||||
|
||||
m_log << "not injecting in application: " << std::hex << text_tasks_start << " -- " << text_tasks_end << std::endl;
|
||||
|
||||
// listeners for traps, code region
|
||||
//InterruptListener l_interrupt(2); // NMI interrupt
|
||||
//TrapListener l_trap(2); // NMI trap?
|
||||
BPSingleListener l_panic(s_panic_handler.getAddress());
|
||||
m_log << "PANIC handler @ " << std::hex << s_panic_handler.getAddress() << std::endl;
|
||||
|
||||
unsigned i_timeout = 50 * 1000;
|
||||
TimerListener l_timeout(i_timeout); // 1s in microseconds
|
||||
TimerListener l_timeout_hard(1 * 1000 * 1000); // 1s in microseconds
|
||||
|
||||
// initialize LLVM disassembler
|
||||
m_ltof = LLVMtoFailTranslator::createFromBinary(m_elf.getFilename());
|
||||
|
||||
// memory manager
|
||||
MemoryManager& mm = simulator.getMemoryManager();
|
||||
|
||||
// job client with environment parameters
|
||||
char* server = getenv("FAIL_SERVER_HOST");
|
||||
if(server == NULL) server = (char*) SERVER_COMM_HOSTNAME;
|
||||
char* cport = getenv("FAIL_SERVER_PORT");
|
||||
int port = (cport != NULL) ? atoi(cport) : SERVER_COMM_TCP_PORT;
|
||||
fail::JobClient jobclient(server, port);
|
||||
|
||||
// execute jobs
|
||||
unsigned executed_jobs = 0;
|
||||
while (executed_jobs < 25 || jobclient.getNumberOfUndoneJobs() > 0) {
|
||||
// get next parameters from jobserver
|
||||
m_log << "asking jobserver for parameters" << endl;
|
||||
CoredTesterExperimentData param;
|
||||
if(!jobclient.getParam(param)){
|
||||
m_log << "Dying." << endl; // We were told to die.
|
||||
simulator.terminate(0);
|
||||
}
|
||||
|
||||
// extract parameters
|
||||
unsigned injection_instr = param.msg.fsppilot().injection_instr();
|
||||
address_t data_address = param.msg.fsppilot().data_address();
|
||||
unsigned data_width = param.msg.fsppilot().data_width();
|
||||
|
||||
// detect wheter we should inject the PC
|
||||
bool pc_injection = param.msg.fsppilot().benchmark().find("jump") != std::string::npos;
|
||||
|
||||
// setup experiments
|
||||
int experiments = pc_injection ? 1 : 8;
|
||||
|
||||
// run experiments
|
||||
for (int experiment_id = 0; experiment_id < experiments; ++experiment_id) {
|
||||
CoredTesterProtoMsg_Result *result = 0;
|
||||
|
||||
// restore to the image
|
||||
m_log << "restoring state" << endl;
|
||||
simulator.clearListeners(this);
|
||||
simulator.restore("state");
|
||||
m_log << "state restored" << endl;
|
||||
executed_jobs++;
|
||||
|
||||
// Check for Read Only Memory
|
||||
if (0x100000 <= data_address && data_address < 0x200000) {
|
||||
result = param.msg.add_result();
|
||||
handleEvent(*result, result->NOINJECTION, "ROM");
|
||||
|
||||
result->set_experiment_number(0);
|
||||
result->set_bitoffset(experiment_id);
|
||||
result->set_original_value(0);
|
||||
continue; // Produce experiments results
|
||||
}
|
||||
|
||||
// Extract stack ranges for checkpoint plugin
|
||||
Checkpoint::range_vector check_ranges;
|
||||
ElfReader::symbol_iterator it = m_elf.sym_begin();
|
||||
for( ; it != m_elf.sym_end(); ++it) {
|
||||
const std::string name = it->getName();
|
||||
|
||||
size_t pos = name.rfind("_stack");
|
||||
if((pos == std::string::npos) || (pos != (name.size() - 6))) continue;
|
||||
|
||||
const ElfSymbol &s_end = m_elf.getSymbol(name); // *it ?
|
||||
const std::string ptr_name = "OS_" + name + "ptr";
|
||||
stringstream ptrstr;
|
||||
ptrstr << "_ZN4arch";
|
||||
ptrstr << ptr_name.size();
|
||||
ptrstr << ptr_name;
|
||||
ptrstr << "E";
|
||||
const ElfSymbol &s_sptr = m_elf.getSymbol(ptrstr.str());
|
||||
if(!s_sptr.isValid()) {
|
||||
m_log << "no stack end symbol for " << name << " (" << ptrstr.str() << "), skipping!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
m_log << "found task stack symbol: " << name << std::endl;
|
||||
|
||||
Checkpoint::indirectable_address_t start = std::make_pair(s_sptr.getAddress(), true);
|
||||
Checkpoint::indirectable_address_t end = std::make_pair(s_end.getEnd(), false);
|
||||
check_ranges.push_back(std::make_pair(start, end));
|
||||
}
|
||||
|
||||
// Init Plugins
|
||||
Checkpoint cpoint(check_ranges, "checkpoint.trace");
|
||||
|
||||
RandomGenerator* rgen;
|
||||
if (s_random_source.isValid()) {
|
||||
const unsigned seed = 12342;
|
||||
rgen = new RandomGenerator(s_random_source, seed);
|
||||
simulator.addFlow(rgen);
|
||||
}
|
||||
|
||||
// fast forward to injection address
|
||||
m_log << "Trying to inject @ instr #" << dec << injection_instr << endl;
|
||||
simulator.clearListeners(this);
|
||||
simulator.addListener(&l_fail_trace);
|
||||
|
||||
BPSingleListener bp;
|
||||
bp.setWatchInstructionPointer(ANY_ADDR);
|
||||
// TODO: why does this need a +1?
|
||||
bp.setCounter(injection_instr+1);
|
||||
simulator.addListener(&bp);
|
||||
|
||||
fail::BaseListener * listener = simulator.resume();
|
||||
bool ok = true;
|
||||
|
||||
while ( ok && (listener == &l_fail_trace) ) {
|
||||
// m_log << "CP IP 0x" << std::hex << simulator.getCPU(0).getInstructionPointer() << std::endl;
|
||||
ok = cpoint.check(s_fail_trace, l_fail_trace.getTriggerInstructionPointer()) == Checkpoint::IDENTICAL;
|
||||
if(ok) listener = simulator.addListenerAndResume(&l_fail_trace);
|
||||
}
|
||||
|
||||
unsigned experiment_number = cpoint.getCount();
|
||||
|
||||
if(!ok) {
|
||||
result = param.msg.add_result();
|
||||
handleEvent(*result, result->NOINJECTION, "CHECKPOINT FAIL BEFORE INJECTION?!");
|
||||
|
||||
result->set_experiment_number((unsigned int) experiment_number);
|
||||
result->set_bitoffset(experiment_id);
|
||||
result->set_original_value(0);
|
||||
|
||||
break;
|
||||
}
|
||||
if (listener != &bp) {
|
||||
result = param.msg.add_result();
|
||||
handleEvent(*result, result->NOINJECTION, "WTF");
|
||||
|
||||
result->set_experiment_number((unsigned int) experiment_number);
|
||||
result->set_bitoffset(experiment_id);
|
||||
result->set_original_value(0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// program counter sanity check
|
||||
if (param.msg.fsppilot().has_injection_instr_absolute()) {
|
||||
address_t PC = param.msg.fsppilot().injection_instr_absolute();
|
||||
if (simulator.getCPU(0).getInstructionPointer() != PC) {
|
||||
m_log << "Invalid injection address EIP=0x"
|
||||
<< std::hex << simulator.getCPU(0).getInstructionPointer()
|
||||
<< " != injection_instr_absolute=0x" << PC << std::endl;
|
||||
simulator.terminate(1);
|
||||
}
|
||||
}
|
||||
|
||||
m_log << "Trace " << std::dec << experiment_number << std::endl;
|
||||
result = param.msg.add_result();
|
||||
result->set_experiment_number((unsigned int) experiment_number);
|
||||
result->set_bitoffset(experiment_id);
|
||||
result->set_original_value(0);
|
||||
|
||||
// abort if outside targeted region
|
||||
address_t PC = simulator.getCPU(0).getInstructionPointer();
|
||||
//if(PC < min_code || PC > max_code) {
|
||||
if(PC < text_tasks_end && PC >= text_tasks_start) {
|
||||
std::stringstream ss;
|
||||
ss << "0x" << hex << PC;
|
||||
ss << " inside task text: ";
|
||||
ss << "0x" << hex << text_tasks_start << " - 0x" << hex << text_tasks_end;
|
||||
handleEvent(*result, result->NOINJECTION, ss.str());
|
||||
continue; // next experiment
|
||||
}
|
||||
|
||||
// perform injection
|
||||
if (pc_injection) {
|
||||
// jump to "data" address
|
||||
address_t current_PC = simulator.getCPU(0).getInstructionPointer();
|
||||
address_t new_PC = param.msg.fsppilot().data_address();
|
||||
m_log << "jump from 0x" << hex << current_PC << " to 0x" << new_PC << std::endl;
|
||||
simulator.getCPU(0).setRegisterContent(simulator.getCPU(0).getRegister(RID_PC), new_PC);
|
||||
|
||||
// set program counter
|
||||
result->set_bitoffset(0);
|
||||
result->set_original_value(current_PC);
|
||||
redecodeCurrentInstruction();
|
||||
} else {
|
||||
// inject random bitflip
|
||||
// experiment_id == bitpos
|
||||
result->set_original_value(injectBitFlip(data_address, data_width, experiment_id));
|
||||
}
|
||||
|
||||
|
||||
// add listeners
|
||||
simulator.clearListeners(this);
|
||||
simulator.addListener(&l_panic);
|
||||
simulator.addListener(&l_timeout);
|
||||
simulator.addListener(&l_fail_trace);
|
||||
simulator.addListener(&l_color_assert_port);
|
||||
simulator.addListener(&l_trace_end_marker);
|
||||
|
||||
// BPSingleListener single_step;
|
||||
// single_step.setWatchInstructionPointer(ANY_ADDR);
|
||||
// simulator.addListener(&single_step);
|
||||
// fail::BaseListener* ll = simulator.resume();
|
||||
// while (ll == &single_step || ll == &l_fail_trace) {
|
||||
// if (ll == &l_fail_trace) {
|
||||
// Checkpoint::check_result res = cpoint.check(s_fail_trace, l_fail_trace.getTriggerInstructionPointer());
|
||||
|
||||
// if(res == Checkpoint::DIFFERENT_IP) {
|
||||
// std::stringstream ss;
|
||||
// ss << "different IP";
|
||||
// ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
// ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
// std::cout << ss.str() << endl;
|
||||
// break;
|
||||
// } else if(res == Checkpoint::DIFFERENT_VALUE) {
|
||||
// std::stringstream ss;
|
||||
// ss << "different value";
|
||||
// ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
// ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
// std::cout << ss.str() << endl;
|
||||
// break;
|
||||
// } else if(res == Checkpoint::DIFFERENT_DIGEST) {
|
||||
// std::stringstream ss;
|
||||
// ss << "different digest";
|
||||
// ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
// ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
// std::cout << ss.str() << endl;
|
||||
// break;
|
||||
// } else if(res == Checkpoint::INVALID) {
|
||||
// std::stringstream ss;
|
||||
// ss << "invalid checkpoint";
|
||||
// ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
// ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
// std::cout << ss.str() << endl;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// std::stringstream ss;
|
||||
// ss << "@ IP " << std::hex << simulator.getCPU(0).getInstructionPointer();
|
||||
// const ElfSymbol &sym = m_elf.getSymbol(simulator.getCPU(0).getInstructionPointer());
|
||||
// ss << " " << sym.getName();
|
||||
// std::cout << ss.str() << endl;
|
||||
// ll = simulator.addListenerAndResume(ll);
|
||||
// }
|
||||
|
||||
// std::cout << (ll == &l_color_assert_port) << " COLOR ASSERT" << endl;
|
||||
|
||||
// //continue;
|
||||
// simulator.terminate(0);
|
||||
|
||||
// resume and wait for results
|
||||
m_log << "Resuming till the crash (time: " << simulator.getTimerTicks() << ")"<< std::endl;
|
||||
bool reached_check_start = false;
|
||||
fail::BaseListener* l = simulator.resume();
|
||||
|
||||
while(l == &l_fail_trace) {
|
||||
Checkpoint::check_result res = cpoint.check(s_fail_trace, l_fail_trace.getTriggerInstructionPointer());
|
||||
if(res == Checkpoint::DIFFERENT_IP) {
|
||||
std::stringstream ss;
|
||||
ss << "different IP";
|
||||
ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
handleEvent(*result, result->SDC_WRONG_RESULT, ss.str());
|
||||
break;
|
||||
} else if(res == Checkpoint::DIFFERENT_VALUE) {
|
||||
std::stringstream ss;
|
||||
ss << "different value";
|
||||
ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
handleEvent(*result, result->SDC_WRONG_RESULT, ss.str());
|
||||
break;
|
||||
} else if(res == Checkpoint::DIFFERENT_DIGEST) {
|
||||
std::stringstream ss;
|
||||
ss << "different digest";
|
||||
ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
handleEvent(*result, result->SDC_WRONG_RESULT, ss.str());
|
||||
break;
|
||||
} else if(res == Checkpoint::INVALID) {
|
||||
std::stringstream ss;
|
||||
ss << "invalid checkpoint";
|
||||
ss << "@ IP 0x" << std::hex << l_fail_trace.getTriggerInstructionPointer();
|
||||
ss << " (checkpoint " << std::dec << cpoint.getCount() << ")";
|
||||
handleEvent(*result, result->SDC_WRONG_RESULT, ss.str());
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset the soft timeout listener
|
||||
simulator.removeListener(&l_timeout);
|
||||
simulator.addListener(&l_timeout);
|
||||
assert(l_timeout.getTimeout() == i_timeout);
|
||||
|
||||
l = simulator.addListenerAndResume(&l_fail_trace);
|
||||
}
|
||||
|
||||
// End of Injection Phase. Now we have crashed
|
||||
m_log << "Crashed (time: " << simulator.getTimerTicks() << ")"<< std::endl;
|
||||
result->set_time_crash(simulator.getTimerTicks());
|
||||
|
||||
if(l == &l_fail_trace) {
|
||||
// already reported invalid checkpoint
|
||||
} else if(l == &l_trace_end_marker) {
|
||||
// trace ended successfully
|
||||
std::stringstream ss;
|
||||
ss << "correct end after " << cpoint.getCount() << " checkpoints";
|
||||
handleEvent(*result, result->OK, ss.str());
|
||||
} else if (l == &l_panic) {
|
||||
// error detected
|
||||
stringstream sstr;
|
||||
sstr << "PANIC";
|
||||
|
||||
// CoRedOS specific trap information
|
||||
const Register *reg_eax = simulator.getCPU(0).getRegister(RID_CAX);
|
||||
uint32_t trap = simulator.getCPU(0).getRegisterContent(reg_eax);
|
||||
sstr << " trap " << dec << trap;
|
||||
|
||||
//address_t sp = simulator.getCPU(0).getStackPointer();
|
||||
//if(mm.isMapped(sp)) {
|
||||
// uint32_t ip;
|
||||
// mm.getBytes(sp, 4, &ip);
|
||||
// sstr << " @ 0x" << hex << ip;
|
||||
|
||||
const Register *reg_esi = simulator.getCPU(0).getRegister(RID_CSI);
|
||||
address_t sp = simulator.getCPU(0).getRegisterContent(reg_esi) + 4;
|
||||
if(mm.isMapped(sp) && mm.isMapped(sp+1) && mm.isMapped(sp+2) && mm.isMapped(sp+3)) {
|
||||
|
||||
uint32_t ip;
|
||||
mm.getBytes(sp, 4, &ip);
|
||||
sstr << " from 0x" << hex << ip;
|
||||
}
|
||||
|
||||
handleEvent(*result, result->OK_DETECTED_ERROR, sstr.str());
|
||||
} else if ( l == &l_color_assert_port ) {
|
||||
// A colored assert has occured
|
||||
uint32_t color = 0;
|
||||
mm.getBytes(s_color_assert_port.getAddress(), 4, &color);
|
||||
std::stringstream ss;
|
||||
ss << "@ IP" << std::hex << simulator.getCPU(0).getInstructionPointer();
|
||||
|
||||
if (color == 0xb83829de) {
|
||||
handleEvent(*result, result->ERR_ASSERT_UNKOWN, ss.str());
|
||||
} else if (color == 0xf4d9f7ca) {
|
||||
handleEvent(*result, result->ERR_ASSERT_CFG_REGION, ss.str());
|
||||
} else if (color == 0x9451210d) {
|
||||
handleEvent(*result, result->ERR_ASSERT_SYSTEM_STATE, ss.str());
|
||||
} else {
|
||||
handleEvent(*result, result->ERR_ASSERT_SPURIOUS, ss.str());
|
||||
}
|
||||
} else if ( l == &l_timeout || l == &l_timeout_hard) {
|
||||
// timeout, probably infinite loop
|
||||
handleEvent(*result, result->ERR_TIMEOUT, "");
|
||||
} else {
|
||||
// what happened?
|
||||
handleEvent(*result, result->UNKNOWN, "WTF");
|
||||
}
|
||||
|
||||
// For RandomJump do only one experiment not 8
|
||||
if (pc_injection) break;
|
||||
}
|
||||
|
||||
// send results
|
||||
jobclient.sendResult(param);
|
||||
}
|
||||
|
||||
// explicitly terminate, or the simulator will continue to run
|
||||
simulator.terminate();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef __CORED_TESTER_EXPERIMENT_HPP__
|
||||
#define __CORED_TESTER_EXPERIMENT_HPP__
|
||||
|
||||
|
||||
#include "sal/SALInst.hpp"
|
||||
#include "efw/ExperimentFlow.hpp"
|
||||
#include "efw/JobClient.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include "util/ElfReader.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "util/llvmdisassembler/LLVMtoFailTranslator.hpp"
|
||||
|
||||
class CoredTester : public fail::ExperimentFlow {
|
||||
public:
|
||||
|
||||
private:
|
||||
fail::Logger m_log;
|
||||
fail::MemoryManager& m_mm;
|
||||
fail::ElfReader m_elf;
|
||||
fail::LLVMtoFailTranslator* m_ltof;
|
||||
|
||||
unsigned injectBitFlip(fail::address_t data_address, unsigned data_width, unsigned bitpos);
|
||||
void redecodeCurrentInstruction();
|
||||
const fail::ElfSymbol& getELFSymbol(const std::string name);
|
||||
|
||||
public:
|
||||
CoredTester() : m_log("CoredTester", false), m_mm(fail::simulator.getMemoryManager()) {}
|
||||
|
||||
bool run();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "cpn/CampaignManager.hpp"
|
||||
#include "util/CommandLine.hpp"
|
||||
#include "campaign.hpp"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
fail::CommandLine &cmd = fail::CommandLine::Inst();
|
||||
for (int i = 1; i < argc; ++i)
|
||||
cmd.add_args(argv[i]);
|
||||
|
||||
CoredTesterCampaign c;
|
||||
if (fail::campaignmanager.runCampaign(&c)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
set(EXPERIMENT_NAME cored-tracing)
|
||||
set(EXPERIMENT_TYPE CoRedTracing)
|
||||
configure_file(../instantiate-experiment.ah.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY
|
||||
)
|
||||
|
||||
set(MY_CAMPAIGN_SRCS
|
||||
experiment.hpp
|
||||
experiment.cc
|
||||
)
|
||||
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
## Build library
|
||||
add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS})
|
||||
|
||||
add_dependencies(fail-${EXPERIMENT_NAME} fail-comm)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} fail-tracing fail-randomgenerator fail-checkpoint fail-comm)
|
||||
@@ -0,0 +1,292 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "sal/SALInst.hpp"
|
||||
#include "sal/Register.hpp"
|
||||
#include "sal/Listener.hpp"
|
||||
#include "experiment.hpp"
|
||||
#include "util/CommandLine.hpp"
|
||||
#include "util/gzstream/gzstream.h"
|
||||
|
||||
// required (enabled) plugins
|
||||
#include "../plugins/tracing/TracingPlugin.hpp"
|
||||
#include "../plugins/randomgenerator/RandomGenerator.hpp"
|
||||
#include "../plugins/checkpoint/Checkpoint.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace fail;
|
||||
|
||||
void CoRedTracing::parseOptions() {
|
||||
CommandLine &cmd = CommandLine::Inst();
|
||||
cmd.addOption("", "", Arg::None, "USAGE: fail-client -Wf,[option] -Wf,[option] ... <BochsOptions...>\n\n");
|
||||
CommandLine::option_handle HELP = cmd.addOption("h", "help", Arg::None, "-h,--help \tPrint usage and exit");
|
||||
|
||||
|
||||
CommandLine::option_handle ELF_FILE = cmd.addOption("", "elf-file", Arg::Required,
|
||||
"--elf-file \tELF Binary File (default: $FAIL_ELF_PATH)");
|
||||
CommandLine::option_handle START_SYMBOL = cmd.addOption("s", "start-symbol", Arg::Required,
|
||||
"-s,--start-symbol \tELF symbol to start tracing (default: main)");
|
||||
CommandLine::option_handle STOP_SYMBOL = cmd.addOption("e", "end-symbol", Arg::Required,
|
||||
"-e,--end-symbol \tELF symbol to end tracing");
|
||||
CommandLine::option_handle SAVE_SYMBOL = cmd.addOption("S", "save-symbol", Arg::Required,
|
||||
"-S,--save-symbol \tELF symbol to save the state of the machine (default: main)\n");
|
||||
CommandLine::option_handle STATE_FILE = cmd.addOption("f", "state-file", Arg::Required,
|
||||
"-f,--state-file \tFile/dir to save the state to (default: state)");
|
||||
CommandLine::option_handle TRACE_FILE = cmd.addOption("t", "trace-file", Arg::Required,
|
||||
"-t,--trace-file \tFile to save the execution trace to (default: trace.pb)\n");
|
||||
|
||||
CommandLine::option_handle FULL_TRACE = cmd.addOption("", "full-trace", Arg::None, "--full-trace \tDo a full trace (more data, default: off)");
|
||||
CommandLine::option_handle MEM_SYMBOL = cmd.addOption("m", "memory-symbol", Arg::Required,
|
||||
"-m,--memory-symbol \tELF symbol(s) to trace accesses (default: all mem read/writes are traced)");
|
||||
CommandLine::option_handle MEM_REGION = cmd.addOption("M", "memory-region", Arg::Required,
|
||||
"-M,--memory-region \trestrict memory region which is traced"
|
||||
" (Possible formats: 0x<address>, 0x<address>:0x<address>, 0x<address>:<length>)");
|
||||
|
||||
if (!cmd.parse()) {
|
||||
cerr << "Error parsing arguments." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (cmd[HELP]) {
|
||||
cmd.printUsage();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (cmd[ELF_FILE].count() > 0)
|
||||
elf_file = cmd[ELF_FILE].first()->arg;
|
||||
else {
|
||||
char * elfpath = getenv("FAIL_ELF_PATH");
|
||||
if (elfpath == NULL) {
|
||||
m_log << "FAIL_ELF_PATH not set :( (alternative: --elf-file) " << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
elf_file = elfpath;
|
||||
}
|
||||
m_elf = new ElfReader(elf_file.c_str());
|
||||
|
||||
if (cmd[START_SYMBOL].count() > 0)
|
||||
start_symbol = cmd[START_SYMBOL].first()->arg;
|
||||
else
|
||||
start_symbol = "main";
|
||||
|
||||
if (cmd[STOP_SYMBOL].count() > 0)
|
||||
stop_symbol = std::string(cmd[STOP_SYMBOL].first()->arg);
|
||||
else {
|
||||
m_log << "You have to give an end symbol (-e,--end-symbol)!" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (cmd[SAVE_SYMBOL].count() > 0)
|
||||
save_symbol = std::string(cmd[SAVE_SYMBOL].first()->arg);
|
||||
else
|
||||
save_symbol = "main";
|
||||
|
||||
if (cmd[STATE_FILE].count() > 0)
|
||||
state_file = std::string(cmd[STATE_FILE].first()->arg);
|
||||
else
|
||||
state_file = "state";
|
||||
|
||||
if (cmd[TRACE_FILE].count() > 0)
|
||||
trace_file = std::string(cmd[TRACE_FILE].first()->arg);
|
||||
else
|
||||
trace_file = "trace.pb";
|
||||
|
||||
use_memory_map = false;
|
||||
|
||||
if (cmd[MEM_SYMBOL].count() > 0) {
|
||||
use_memory_map = true;
|
||||
option::Option *opt = cmd[MEM_SYMBOL].first();
|
||||
|
||||
while (opt != 0) {
|
||||
const ElfSymbol &symbol = m_elf->getSymbol(opt->arg);
|
||||
assert(symbol.isValid());
|
||||
|
||||
m_log << "Adding '" << opt->arg << "' == 0x" << std::hex << symbol.getAddress()
|
||||
<< "+" << std::dec << symbol.getSize() << " to trace map" << std::endl;
|
||||
traced_memory_map.add(symbol.getAddress(), symbol.getSize());
|
||||
|
||||
opt = opt->next();
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd[MEM_REGION].count() > 0) {
|
||||
use_memory_map = true;
|
||||
option::Option *opt = cmd[MEM_REGION].first();
|
||||
|
||||
while (opt != 0) {
|
||||
char *endptr;
|
||||
guest_address_t begin = strtol(opt->arg, &endptr, 16);
|
||||
guest_address_t size;
|
||||
if (endptr == opt->arg) {
|
||||
m_log << "Couldn't parse " << opt->arg << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
char delim = *endptr;
|
||||
if (delim == 0) {
|
||||
size = 1;
|
||||
} else if (delim == ':') {
|
||||
char *p = endptr +1;
|
||||
size = strtol(p, &endptr, 16) - begin;
|
||||
if (p == endptr || *endptr != 0) {
|
||||
m_log << "Couldn't parse " << opt->arg << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
} else if (delim == '+') {
|
||||
char *p = endptr +1;
|
||||
size = strtol(p, &endptr, 10);
|
||||
if (p == endptr || *endptr != 0) {
|
||||
m_log << "Couldn't parse " << opt->arg << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
m_log << "Couldn't parse " << opt->arg << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
traced_memory_map.add(begin, size);
|
||||
|
||||
m_log << "Adding " << opt->arg << " 0x" << std::hex << begin
|
||||
<< "+" << std::dec << size << " to trace map" << std::endl;
|
||||
|
||||
opt = opt->next();
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd[FULL_TRACE]) {
|
||||
this->full_trace = true;
|
||||
}
|
||||
|
||||
assert(m_elf->getSymbol(start_symbol).isValid());
|
||||
assert(m_elf->getSymbol(stop_symbol).isValid());
|
||||
assert(m_elf->getSymbol(save_symbol).isValid());
|
||||
|
||||
m_log << "start symbol: " << start_symbol << " 0x" << std::hex << m_elf->getSymbol(start_symbol).getAddress() << std::endl;
|
||||
m_log << "save symbol: " << save_symbol << " 0x" << std::hex << m_elf->getSymbol(save_symbol).getAddress() << std::endl;
|
||||
m_log << "stop symbol: " << stop_symbol << " 0x" << std::hex << m_elf->getSymbol(stop_symbol).getAddress() << std::endl;
|
||||
|
||||
m_log << "state file: " << state_file << std::endl;
|
||||
m_log << "trace file: " << trace_file << std::endl;
|
||||
m_log << "full-trace: " << this->full_trace << std::endl;
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool CoRedTracing::run()
|
||||
{
|
||||
parseOptions();
|
||||
|
||||
BPSingleListener l_start_symbol(m_elf->getSymbol(start_symbol).getAddress());
|
||||
BPSingleListener l_save_symbol (m_elf->getSymbol(save_symbol).getAddress());
|
||||
BPSingleListener l_stop_symbol (m_elf->getSymbol(stop_symbol).getAddress());
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// STEP 1: run until interesting function starts, start the tracing
|
||||
simulator.addListenerAndResume(&l_start_symbol);
|
||||
m_log << start_symbol << " reached, start tracing" << std::endl;
|
||||
|
||||
// restrict memory access logging to injection target
|
||||
TracingPlugin tp;
|
||||
tp.setFullTrace(this->full_trace);
|
||||
|
||||
if (use_memory_map) {
|
||||
m_log << "Use restricted memory map for tracing" << std::endl;
|
||||
tp.restrictMemoryAddresses(&traced_memory_map);
|
||||
}
|
||||
|
||||
ogzstream of(trace_file.c_str());
|
||||
if (of.bad()) {
|
||||
m_log << "Couldn't open trace file: " << trace_file << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
tp.setTraceFile(&of);
|
||||
|
||||
// this must be done *after* configuring the plugin:
|
||||
simulator.addFlow(&tp);
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// STEP 2: continue to the save point, and save state
|
||||
if (start_symbol != save_symbol) {
|
||||
simulator.addListenerAndResume(&l_save_symbol);
|
||||
}
|
||||
m_log << start_symbol << " reached, save state" << std::endl;
|
||||
simulator.save(state_file);
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Step 3: add plugins
|
||||
// symbol to trigger checkpoints
|
||||
const ElfSymbol &s_fail_trace = m_elf->getSymbol("fail_trace");
|
||||
|
||||
Checkpoint *cpoint;
|
||||
if(s_fail_trace.isValid()) {
|
||||
Checkpoint::range_vector check_ranges;
|
||||
|
||||
ElfReader::symbol_iterator it = m_elf->sym_begin();
|
||||
for( ; it != m_elf->sym_end(); ++it) {
|
||||
const std::string name = it->getName();
|
||||
|
||||
size_t pos = name.rfind("_stack");
|
||||
if((pos == std::string::npos) || (pos != (name.size() - 6))) continue;
|
||||
|
||||
const ElfSymbol &s_end = m_elf->getSymbol(name); // *it ?
|
||||
const std::string ptr_name = "OS_" + name + "ptr";
|
||||
stringstream ptrstr;
|
||||
ptrstr << "_ZN4arch";
|
||||
ptrstr << ptr_name.size();
|
||||
ptrstr << ptr_name;
|
||||
ptrstr << "E";
|
||||
const ElfSymbol &s_sptr = m_elf->getSymbol(ptrstr.str());
|
||||
if(!s_sptr.isValid()) {
|
||||
m_log << "no stack end symbol for " << name << " (" << ptrstr.str() << "), skipping!" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
m_log << "found task stack symbol: " << name << std::endl;
|
||||
|
||||
Checkpoint::indirectable_address_t start = std::make_pair(s_sptr.getAddress(), true);
|
||||
Checkpoint::indirectable_address_t end = std::make_pair(s_end.getEnd(), false);
|
||||
check_ranges.push_back(std::make_pair(start, end));
|
||||
}
|
||||
|
||||
cpoint = new Checkpoint(s_fail_trace, check_ranges, "checkpoint.trace");
|
||||
simulator.addFlow(cpoint);
|
||||
} else {
|
||||
m_log << "Checkpoint plugin NOT added to simulation" << std::endl;
|
||||
}
|
||||
|
||||
// symbol to read random values from
|
||||
const ElfSymbol &s_random_source = m_elf->getSymbol("random_source");
|
||||
RandomGenerator *rgen;
|
||||
if (s_random_source.isValid()) {
|
||||
const unsigned seed = 12342;
|
||||
rgen = new RandomGenerator(s_random_source, seed);
|
||||
simulator.addFlow(rgen);
|
||||
} else {
|
||||
m_log << "Randomgenerator plugin NOT added to simulation" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Step 4: Continue to the stop point
|
||||
simulator.addListener(&l_stop_symbol);
|
||||
simulator.resume();
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Step 5: tear down the tracing
|
||||
|
||||
simulator.removeFlow(&tp);
|
||||
// serialize trace to file
|
||||
if (of.fail()) {
|
||||
m_log << "failed to write " << trace_file << std::endl;
|
||||
return false;
|
||||
}
|
||||
of.close();
|
||||
|
||||
simulator.clearListeners();
|
||||
simulator.terminate();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef __CORED_TRACING_HPP__
|
||||
#define __CORED_TRACING_HPP__
|
||||
|
||||
#include "efw/ExperimentFlow.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include "util/ElfReader.hpp"
|
||||
#include "util/MemoryMap.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
class CoRedTracing : public fail::ExperimentFlow {
|
||||
std::string start_symbol;
|
||||
std::string stop_symbol;
|
||||
std::string save_symbol;
|
||||
|
||||
std::string state_file;
|
||||
std::string trace_file;
|
||||
std::string elf_file;
|
||||
|
||||
bool use_memory_map;
|
||||
fail::MemoryMap traced_memory_map;
|
||||
|
||||
bool full_trace;
|
||||
|
||||
fail::Logger m_log;
|
||||
fail::ElfReader *m_elf;
|
||||
|
||||
public:
|
||||
void parseOptions();
|
||||
bool run();
|
||||
|
||||
CoRedTracing() : full_trace(false), m_log("CoRedTracing", false) {};
|
||||
};
|
||||
|
||||
#endif // __CORED_TRACING_HPP__
|
||||
@@ -16,6 +16,5 @@ set(MY_CAMPAIGN_SRCS
|
||||
## Build library
|
||||
add_library(fail-${EXPERIMENT_NAME} ${MY_CAMPAIGN_SRCS})
|
||||
add_dependencies(fail-${EXPERIMENT_NAME} fail-comm)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} fail-comm)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME})
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} fail-comm fail-util)
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
set(EXPERIMENT_NAME fiascoFail)
|
||||
set(EXPERIMENT_TYPE FiascoFailExperiment)
|
||||
configure_file(../instantiate-experiment-indirect.ah.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY
|
||||
)
|
||||
|
||||
## Setup desired protobuf descriptions HERE ##
|
||||
set(MY_PROTOS
|
||||
fiascofail.proto
|
||||
)
|
||||
|
||||
set(MY_CAMPAIGN_SRCS
|
||||
instantiateExperiment.cc
|
||||
experimentInfo.hpp
|
||||
experiment.hpp
|
||||
experiment.cc
|
||||
campaign.hpp
|
||||
campaign.cc
|
||||
)
|
||||
|
||||
#### PROTOBUFS ####
|
||||
find_package(Protobuf REQUIRED)
|
||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
find_package(MySQL REQUIRED)
|
||||
include_directories(${MYSQL_INCLUDE_DIR})
|
||||
|
||||
set(PROTOBUF_IMPORT_DIRS ${PROTOBUF_IMPORT_DIRS} ${CMAKE_CURRENT_BINARY_DIR}/../../core/comm)
|
||||
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
|
||||
|
||||
## Build library
|
||||
add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS})
|
||||
add_dependencies(fail-${EXPERIMENT_NAME} fail-comm)
|
||||
#target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY} ${MYSQL_LIBRARIES})
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} fail)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY} ${MYSQL_LIBRARIES})
|
||||
|
||||
## This is the example's campaign server distributing experiment parameters
|
||||
add_executable(${EXPERIMENT_NAME}-server main.cc)
|
||||
target_link_libraries(${EXPERIMENT_NAME}-server fail-${EXPERIMENT_NAME} fail ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} ${MYSQL_LIBRARIES})
|
||||
install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin)
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "campaign.hpp"
|
||||
#include "cpn/CampaignManager.hpp"
|
||||
|
||||
void FiascoFailCampaign::cb_send_pilot(DatabaseCampaignMessage pilot)
|
||||
{
|
||||
FiascoFailExperimentData *data = new FiascoFailExperimentData;
|
||||
data->msg.mutable_fsppilot()->CopyFrom(pilot);
|
||||
fail::campaignmanager.addParam(data);
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "cpn/DatabaseCampaign.hpp"
|
||||
#include "comm/ExperimentData.hpp"
|
||||
#include "experimentInfo.hpp"
|
||||
#include "fiascofail.pb.h"
|
||||
//#include <google/protobuf/descriptor.h>
|
||||
|
||||
class FiascoFailExperimentData : public fail::ExperimentData
|
||||
{
|
||||
public:
|
||||
FiascofailProtoMsg msg;
|
||||
FiascoFailExperimentData() : fail::ExperimentData(&msg) {}
|
||||
};
|
||||
|
||||
class FiascoFailCampaign : public fail::DatabaseCampaign
|
||||
{
|
||||
virtual const google::protobuf::Descriptor * cb_result_message()
|
||||
{
|
||||
return google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName("FiascofailProtoMsg");
|
||||
}
|
||||
virtual void cb_send_pilot(DatabaseCampaignMessage pilot);
|
||||
|
||||
virtual int expected_number_of_results(std::string variant, std::string benchmark)
|
||||
{
|
||||
#if FIASCO_FAULTMODEL_BURST
|
||||
return 1;
|
||||
#else
|
||||
return 8;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,575 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include "experiment.hpp"
|
||||
#include "experimentInfo.hpp"
|
||||
#include "campaign.hpp"
|
||||
|
||||
#include "sal/SALConfig.hpp"
|
||||
#include "sal/SALInst.hpp"
|
||||
#include "sal/Memory.hpp"
|
||||
#include "sal/Listener.hpp"
|
||||
#include <sal/bochs/BochsMemory.hpp>
|
||||
#include "util/WallclockTimer.hpp"
|
||||
#include "config/FailConfig.hpp"
|
||||
#include "util/CommandLine.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace fail;
|
||||
|
||||
#define LOCAL 0
|
||||
|
||||
void FiascoFailExperiment::parseOptions()
|
||||
{
|
||||
CommandLine &cmd = CommandLine::Inst();
|
||||
cmd.addOption("", "", Arg::None, "USAGE: fail-client -Wf,[option] ... <BochsOptions...>\n\n");
|
||||
CommandLine::option_handle GOLDEN = cmd.addOption("g", "golden", Arg::None, "-g,--golden \tExecute golden-run experiment?");
|
||||
CommandLine::option_handle HELP = cmd.addOption("h", "help", Arg::None, "-h,--help \tPrint usage and exit");
|
||||
CommandLine::option_handle END_ADDRESS = cmd.addOption("E", "end", Arg::Required, "-E,--end \tEnd-Address of experiment");
|
||||
CommandLine::option_handle TOTAL_TIMER = cmd.addOption("T", "time", Arg::Required, "-T,--time \tTotal timer ticks of the golden run experiment from restoring point");
|
||||
CommandLine::option_handle TOTAL_INSTR = cmd.addOption("t", "total", Arg::Required, "-t,--total \tTotal instructions of the golden run experiment from restoring point");
|
||||
CommandLine::option_handle ECC_PANIC_FUNC = cmd.addOption("p", "panic", Arg::Required, "-p--panic \tAddress of the ecc_panic function");
|
||||
CommandLine::option_handle ERROR_CORRECTED_ADDR = cmd.addOption("c", "corrected", Arg::Required, "-c--corected \tAddress of the errors_corrected variable");
|
||||
|
||||
if(!cmd.parse())
|
||||
{
|
||||
cerr << "Error parsing arguments." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if(cmd[HELP])
|
||||
{
|
||||
cmd.printUsage();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(cmd[GOLDEN].count() > 0)
|
||||
{
|
||||
_golden_run = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_golden_run = false;
|
||||
}
|
||||
|
||||
// Check if end-address is given
|
||||
if(cmd[END_ADDRESS].count() > 0)
|
||||
{
|
||||
endAddress = strtoul(cmd[END_ADDRESS].first()->arg, NULL, 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log << "You have to give an end address!" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Check if number of golden run timer ticks is given
|
||||
if(cmd[TOTAL_TIMER].count() > 0)
|
||||
{
|
||||
golden_run_timer_ticks = strtoull(cmd[TOTAL_TIMER].first()->arg, NULL, 10);
|
||||
}
|
||||
else if(!_golden_run)
|
||||
{
|
||||
m_log << "You hava to give the number of total timer ticks of the golden run" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Check if number of total instructions is given
|
||||
if(cmd[TOTAL_INSTR].count() > 0)
|
||||
{
|
||||
golden_run_instructions = strtoul(cmd[TOTAL_INSTR].first()->arg, NULL, 10);
|
||||
}
|
||||
else if(!_golden_run)
|
||||
{
|
||||
m_log << "You have to give the number of total instructions of the golden run" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Check if ecc_panic function address is given
|
||||
if(cmd[ECC_PANIC_FUNC].count() > 0)
|
||||
{
|
||||
ecc_panic_address = strtoul(cmd[ECC_PANIC_FUNC].first()->arg, NULL, 16);
|
||||
}
|
||||
else if(!_golden_run)
|
||||
{
|
||||
m_log << "You have to give the address of the ecc_panic function" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Check if errors_corrected variable address is given
|
||||
if(cmd[ERROR_CORRECTED_ADDR].count() > 0)
|
||||
{
|
||||
addr_errors_corrected = strtoul(cmd[ERROR_CORRECTED_ADDR].first()->arg, NULL, 16);
|
||||
}
|
||||
else if(!_golden_run)
|
||||
{
|
||||
m_log << "You have to give the address of the errors_corrected variable" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
void FiascoFailExperiment::readGoldenRun(string& target)
|
||||
{
|
||||
ifstream golden_run_file("golden.out");
|
||||
|
||||
if(!golden_run_file.good())
|
||||
{
|
||||
m_log << "Could not open file golden.out" << endl;
|
||||
simulator.terminate();
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
target.assign((istreambuf_iterator<char>(golden_run_file)), istreambuf_iterator<char>());
|
||||
golden_run_file.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* Function to record every output on the VGA-Output-Port in m_CurrentOutput
|
||||
* Runs until any breakpoint different from the VGA-Port is reached
|
||||
*/
|
||||
BaseListener* FiascoFailExperiment::waitIOOrOther(bool clear_output)
|
||||
{
|
||||
IOPortListener ev_ioport(0x3F8, true); // VGA-Output-Port: 0x3F8
|
||||
BaseListener* ev = NULL;
|
||||
if(clear_output)
|
||||
{
|
||||
m_CurrentOutput.clear();
|
||||
}
|
||||
while(true)
|
||||
{
|
||||
simulator.addListener(&ev_ioport); // Add VGA-Port to the current listeners...
|
||||
ev = simulator.resume(); // ...and continue
|
||||
if(ev == &ev_ioport) // If current breakpoint == VGA-Port...
|
||||
{
|
||||
m_CurrentOutput += ev_ioport.getData(); // ... add output to m_CurrentOutput
|
||||
}
|
||||
else // Else: Breakpoint different from VGA-Port reached, break
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ev; // Return the current breakpoint
|
||||
}
|
||||
|
||||
bool FiascoFailExperiment::run()
|
||||
{
|
||||
m_log << "startup" << endl;
|
||||
parseOptions();
|
||||
|
||||
if(_golden_run)
|
||||
{
|
||||
// Do the golden-run experiment
|
||||
goldenRun();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do the actual fault injection
|
||||
faultInjection();
|
||||
}
|
||||
|
||||
// Experiment finished
|
||||
simulator.terminate();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FiascoFailExperiment::faultInjection()
|
||||
{
|
||||
string golden_run;
|
||||
readGoldenRun(golden_run); // Read the output string from the golden run
|
||||
|
||||
BPSingleListener bp;
|
||||
int experiments = 0;
|
||||
#if !LOCAL
|
||||
for(experiments = 0; experiments < 500 || (m_jc.getNumberOfUndoneJobs() != 0); )
|
||||
{
|
||||
#endif
|
||||
m_log << "asking job server for experiment parameters" << endl;
|
||||
FiascoFailExperimentData param;
|
||||
#if !LOCAL
|
||||
if(!m_jc.getParam(param))
|
||||
{
|
||||
m_log << "Dying." << endl;
|
||||
simulator.terminate(1);
|
||||
}
|
||||
#else
|
||||
// XXX debug
|
||||
param.msg.mutable_fsppilot()->set_injection_instr(96);
|
||||
param.msg.mutable_fsppilot()->set_injection_instr_absolute(4026670033);
|
||||
param.msg.mutable_fsppilot()->set_data_address(4237508604);
|
||||
param.msg.mutable_fsppilot()->set_data_width(1);
|
||||
param.msg.mutable_fsppilot()->set_variant("baseline");
|
||||
param.msg.mutable_fsppilot()->set_benchmark("shared_ds");
|
||||
#endif
|
||||
|
||||
if(param.msg.fsppilot().data_width() != 1)
|
||||
{
|
||||
m_log << "cannot deal with data_width = " << param.msg.fsppilot().data_width() << endl;
|
||||
simulator.terminate(1);
|
||||
}
|
||||
|
||||
// Get the experiment data from the Job-Server
|
||||
int id = param.getWorkloadID();
|
||||
m_variant = param.msg.fsppilot().variant();
|
||||
m_benchmark = param.msg.fsppilot().benchmark();
|
||||
unsigned instr_offset = param.msg.fsppilot().injection_instr(); // Offset to the IP where the fault injection has to be done
|
||||
guest_address_t mem_addr = param.msg.fsppilot().data_address(); // Memory address wehre the fault injection has to be done
|
||||
|
||||
// for each job with the SINGLEBITFLIP fault model we're actually doing *8*
|
||||
// experiments (one for each bit)
|
||||
for(int bit_offset = 0; bit_offset < 8; ++bit_offset)
|
||||
{
|
||||
++experiments;
|
||||
|
||||
WallclockTimer timer; // Timer to log the actual time of the experiment
|
||||
timer.startTimer();
|
||||
|
||||
FiascofailProtoMsg_Result *result = param.msg.add_result(); // Protobuf object for the result
|
||||
result->set_bit_offset(bit_offset); // Set the bit offset (1 if FAULTMODEL_BURST is active)
|
||||
m_log << dec << "job " << id << " @bit: " << bit_offset << " " << m_variant << "/" << m_benchmark
|
||||
<< " instr-offset " << hex << instr_offset
|
||||
<< " mem " << hex << mem_addr << "+" << dec << bit_offset << endl;
|
||||
|
||||
m_log << "restoring state" << endl;
|
||||
simulator.restore("state"); // Restore the state (Entry point is the first IP of the main-function from the application)
|
||||
m_log << "restore @ip " << hex << simulator.getCPU(0).getInstructionPointer() << " finished!" << endl;
|
||||
|
||||
// convert to microseconds (simulator.getTimerTicksPerSecond() only
|
||||
// works reliably when simulation has begun)
|
||||
unsigned goldenrun_runtime = (unsigned)(golden_run_timer_ticks * 1000000.0 / simulator.getTimerTicksPerSecond());
|
||||
unsigned timeout_runtime = goldenrun_runtime + 1000000/18.2; // + 1 timer tick
|
||||
|
||||
BPSingleListener func_finish(endAddress); // Add the last IP of the main-function to the listeners (end of experiment)
|
||||
simulator.addListener(&func_finish);
|
||||
|
||||
|
||||
simtime_t time_start = simulator.getTimerTicks(); // measure elapsed time
|
||||
|
||||
if(instr_offset > 0)
|
||||
{
|
||||
bp.setWatchInstructionPointer(ANY_ADDR); // Create new Breakpoint...
|
||||
bp.setCounter(instr_offset + 1); // ...to break when the IP for the fault injection is reached...
|
||||
simulator.addListener(&bp); // ...and add it to the actual listeners
|
||||
|
||||
BaseListener *go = waitIOOrOther(true); // Resume simulation and log VGA-Output
|
||||
if(go == &func_finish) // If func_finish has triggerd the break, something went wong...
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "experiment reached finish() before FI";
|
||||
m_log << ss.str() << endl;
|
||||
result->set_resulttype(result->UNKNOWN);
|
||||
result->set_details(ss.str());
|
||||
result->set_runtime(timer);
|
||||
m_jc.sendResult(param);
|
||||
|
||||
continue; // ... so continue with next experiment
|
||||
}
|
||||
else if(go != &bp) // Else if the breakpoint for the fault injection is not reached, something went wrong...
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "experiment didn't reach bp";
|
||||
m_log << ss.str() << endl;
|
||||
result->set_resulttype(result->UNKNOWN);
|
||||
result->set_details(ss.str());
|
||||
result->set_latest_ip(simulator.getCPU(0).getInstructionPointer());
|
||||
result->set_runtime(timer);
|
||||
#if !LOCAL
|
||||
m_jc.sendResult(param);
|
||||
#endif
|
||||
|
||||
#if FIASCO_FAULTMODEL_BURST
|
||||
bit_offset = 8;
|
||||
#endif
|
||||
|
||||
continue; // ... so continue with the next experiment
|
||||
}
|
||||
}
|
||||
|
||||
// sanity check (check if actual IP equals the trced IP)
|
||||
uint32_t injection_ip = simulator.getCPU(0).getInstructionPointer();
|
||||
if(param.msg.fsppilot().has_injection_instr_absolute() &&
|
||||
injection_ip != param.msg.fsppilot().injection_instr_absolute())
|
||||
{
|
||||
stringstream ss;
|
||||
ss << "SANITY CHECK FAILED: " << hex << injection_ip
|
||||
<< " != " << hex << param.msg.fsppilot().injection_instr_absolute();
|
||||
m_log << ss.str() << endl;
|
||||
result->set_resulttype(result->UNKNOWN);
|
||||
result->set_latest_ip(injection_ip);
|
||||
result->set_details(ss.str());
|
||||
result->set_runtime(timer);
|
||||
#if !LOCAL
|
||||
m_jc.sendResult(param);
|
||||
#endif
|
||||
|
||||
#if FIASCO_FAULTMODEL_BURST
|
||||
bit_offset = 8;
|
||||
#endif
|
||||
|
||||
continue; // If sanity check fails: next experiment
|
||||
}
|
||||
if(param.msg.fsppilot().has_injection_instr_absolute())
|
||||
{
|
||||
m_log << "Absolute IP sanity check OK" << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log << "Absolute IP sanity check skipped (job parameters insufficient)" << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --- fault injection ---
|
||||
MemoryManager& mm = simulator.getMemoryManager(); // Get the memory manager from Bochs
|
||||
host_address_t addr = reinterpret_cast<BochsMemoryManager*>(&mm)->guestToHost(mem_addr); // check if the fault-address is mapped (guestToHost returns ADDR_INV if not)
|
||||
if (addr == (host_address_t)ADDR_INV)
|
||||
{
|
||||
result->set_resulttype(result->UNKNOWN);
|
||||
result->set_latest_ip(injection_ip);
|
||||
result->set_runtime(timer);
|
||||
stringstream ss;
|
||||
ss << "INVALID DATA-ADDRESS " << hex << mem_addr << " @ ip " << injection_ip;
|
||||
result->set_details(ss.str());
|
||||
m_jc.sendResult(param);
|
||||
|
||||
continue; // Faul-address is not mapped so continue with the next experiment
|
||||
}
|
||||
byte_t data = mm.getByte(mem_addr); // Get tha actual value stored in the fault-addres
|
||||
byte_t newdata;
|
||||
#if FIASCO_FAULTMODEL_BURST
|
||||
newdata = data ^ 0xff; // If Faultmode burst is active: Flip every 8 bits...
|
||||
bit_offset = 8; // ...and continue with the next byte
|
||||
#else
|
||||
newdata = data ^ (1 << bit_offset); // Else: Flip the bit according to the actual bit-offset and continue with next bit
|
||||
#endif
|
||||
mm.setByte(mem_addr, newdata); // Store the new data in the actual faut-address
|
||||
m_log << "fault injected @ ip " << injection_ip
|
||||
<< " 0x" << hex << ((int)data) << " -> 0x" << ((int)newdata) << endl;
|
||||
|
||||
|
||||
|
||||
|
||||
// --- aftermath ---
|
||||
// catch traps as "extraordinary" ending
|
||||
TrapListener ev_trap(ANY_TRAP);
|
||||
simulator.addListener(&ev_trap);
|
||||
|
||||
// jump outside text segment (TODO: text segments for multiple elf-files + paging)
|
||||
/*
|
||||
BPRangeListener ev_below_text(ANY_ADDR, addr_text_start -1); // TODO
|
||||
BPRangeListener ev_beyond_text(addr_text_end + 1, ANY_ADDR); // TODO
|
||||
simulator.addListener(&ev_below_text);
|
||||
simulator.addListener(&ev_beyond_text);
|
||||
*/
|
||||
|
||||
// timeout (e.g., stuck in a HLT instruction)
|
||||
TimerListener ev_timeout(timeout_runtime);
|
||||
simulator.addListener(&ev_timeout);
|
||||
|
||||
// grant generous (10x) more instructions before aborting to avoid false positives
|
||||
BPSingleListener ev_dyninstructions(ANY_ADDR);
|
||||
// FIXME overflow possible
|
||||
ev_dyninstructions.setCounter(golden_run_instructions * 10);
|
||||
simulator.addListener(&ev_dyninstructions);
|
||||
|
||||
// incomplete (e.g. cursors blinks so nothing happens any more or a longjump occurs)
|
||||
BPSingleListener ev_blink(FIASCO_BREAK_BLINK);
|
||||
simulator.addListener(&ev_blink);
|
||||
BPSingleListener ev_longjmp(FIASCO_BREAK_LONGJMP);
|
||||
simulator.addListener(&ev_longjmp);
|
||||
|
||||
// function called by ecc apsects, when an uncorrectable error is detected
|
||||
BPSingleListener func_ecc_panic(ecc_panic_address);
|
||||
if(ecc_panic_address != ADDR_INV)
|
||||
{
|
||||
simulator.addListener(&func_ecc_panic);
|
||||
}
|
||||
|
||||
// wait until experiment-terminating event occurs
|
||||
bool finished = false;
|
||||
BaseListener *go;
|
||||
while(!finished)
|
||||
{
|
||||
go = waitIOOrOther(false); // resume experiment until func_finish or any other BP is reached and log the output
|
||||
if(go == &ev_trap) // if a trap is triggered, check which one
|
||||
{
|
||||
// Traps that occour in golden run are considered as deliberate
|
||||
if(ev_trap.getTriggerNumber() == 14) // Page fault trap
|
||||
{
|
||||
finished = false;
|
||||
simulator.addListener(&ev_trap); // Trap considered as deliberate so continue
|
||||
}
|
||||
else
|
||||
{
|
||||
finished = true; // Trap not considered as deliberate so break
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
finished = true; // Experiment reached BP so break
|
||||
}
|
||||
}
|
||||
|
||||
// record latest IP regardless of result
|
||||
// TODO: consider recording latest IP within text segment, too, which
|
||||
// would make this usable for the jump-outside case
|
||||
result->set_latest_ip(simulator.getCPU(0).getInstructionPointer());
|
||||
|
||||
// record error_corrected regardless of result
|
||||
if (addr_errors_corrected != ADDR_INV)
|
||||
{
|
||||
int32_t error_corrected = mm.getByte(addr_errors_corrected);
|
||||
result->set_error_corrected(error_corrected ? result->TRUE : result->FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
// not setting this yields NULL in the DB
|
||||
//result->set_error_corrected(0);
|
||||
}
|
||||
|
||||
result->set_sim_runtime_factor(
|
||||
(simulator.getTimerTicks() - time_start) / (double) golden_run_timer_ticks); // Get the runtime factor compared to the golden run
|
||||
|
||||
|
||||
// Look for result
|
||||
if(go == &func_finish) // If BP == func_finished...
|
||||
{
|
||||
if(strcmp(m_CurrentOutput.c_str(), golden_run.c_str()) == 0) // ...and output is equal to the golden run: Result: OK
|
||||
{
|
||||
m_log << "experiment finished ordinarily" << endl;
|
||||
result->set_resulttype(result->OK);
|
||||
}
|
||||
else // ...or output is different from the golden run: Result: SDC
|
||||
{
|
||||
m_log << "experiment finished, but output incorrect" << endl;
|
||||
result->set_resulttype(result->SDC);
|
||||
result->set_details(m_CurrentOutput.c_str());
|
||||
}
|
||||
}
|
||||
else if(go == &ev_trap) // If BP == trap: Result: Trap
|
||||
{
|
||||
m_log << dec << "Result TRAP #" << ev_trap.getTriggerNumber() << endl;
|
||||
result->set_resulttype(result->TRAP);
|
||||
|
||||
stringstream ss;
|
||||
ss << ev_trap.getTriggerNumber();
|
||||
result->set_details(ss.str());
|
||||
}
|
||||
else if(go == &func_ecc_panic) // If BP == ecc_panic_function: Result: Detected (but not corrected)
|
||||
{
|
||||
m_log << "ECC Panic: uncorrectable error" << endl;
|
||||
result->set_resulttype(result->DETECTED); // DETECTED <=> ECC_PANIC <=> reboot
|
||||
}
|
||||
// TODO (see above)
|
||||
/*else if(go == &ev_below_text || go == &ev_beyond_text)
|
||||
{
|
||||
m_log << "Result Trap #" << ev_trap.getTriggerNumber() << endl;
|
||||
result->set_jump_outside(result->TRUE);
|
||||
result->set_resulttype(result->TRAP);
|
||||
|
||||
stringstream ss;
|
||||
ss << ev_trap.getTriggerNumber();
|
||||
result->set_details(ss.str());
|
||||
}*/
|
||||
else if(go == &ev_timeout || go == &ev_dyninstructions || go == &ev_blink || go == &ev_longjmp) // Result: Timeout if any of these BP occur
|
||||
{
|
||||
m_log << "Result TIMEOUT" << endl;
|
||||
result->set_resulttype(result->TIMEOUT);
|
||||
if(go == &ev_dyninstructions)
|
||||
{
|
||||
result->set_details("i");
|
||||
}
|
||||
else if(go == &ev_blink)
|
||||
{
|
||||
result->set_details("b");
|
||||
}
|
||||
else if(go == &ev_longjmp)
|
||||
{
|
||||
result->set_details("l");
|
||||
}
|
||||
else
|
||||
{
|
||||
result->set_details("t");
|
||||
}
|
||||
}
|
||||
else // None of the above BPs reached so obviously something went wrong
|
||||
{
|
||||
m_log << "Result WTF?" << endl;
|
||||
result->set_resulttype(result->UNKNOWN);
|
||||
|
||||
stringstream ss;
|
||||
ss << "event addr: " << go << " EIP " << simulator.getCPU(0).getInstructionPointer();
|
||||
result->set_details(ss.str());
|
||||
}
|
||||
result->set_runtime(timer);
|
||||
}
|
||||
|
||||
#if !LOCAL
|
||||
m_jc.sendResult(param); // Send the result back to the job server and continue with next experiment (if there is one)
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void FiascoFailExperiment::goldenRun()
|
||||
{
|
||||
std::vector<int> m_lTraps;
|
||||
|
||||
|
||||
simulator.restore("state"); // Restore state (Continues from the first IP in the main function of the Application)
|
||||
|
||||
BPSingleListener l_stop_address(endAddress); // Add the last IP of the main function to the actual listeners
|
||||
m_log << "Golden-Run start, Stop-Address: 0x" << hex << endAddress << endl;
|
||||
|
||||
std::string golden_output;
|
||||
ofstream golden_output_file("golden.out"); // Save the logged output in "golden.out"
|
||||
|
||||
simulator.addListener(&l_stop_address);
|
||||
|
||||
TrapListener ev_trap(ANY_TRAP); // Trap listeners, break if any trap is triggered
|
||||
simulator.addListener(&ev_trap);
|
||||
|
||||
bool finished = false;
|
||||
m_CurrentOutput = "";
|
||||
while(!finished) // Continue and log output
|
||||
{
|
||||
BaseListener* ev = waitIOOrOther(false);
|
||||
if(ev == &ev_trap) // if trap is triggered, log the number
|
||||
{
|
||||
m_lTraps.push_back(ev_trap.getTriggerNumber());
|
||||
simulator.addListener(&ev_trap);
|
||||
}
|
||||
else if(ev == &l_stop_address) // if stop address is reached, save the output and finish the experiment
|
||||
{
|
||||
golden_output.assign(m_CurrentOutput.c_str());
|
||||
golden_output_file << m_CurrentOutput.c_str();
|
||||
m_log << "Output successfully logged..." << endl;
|
||||
finished = true;
|
||||
}
|
||||
else // something went wrong
|
||||
{
|
||||
m_log << "Error on logging Output, terminating..." << endl;
|
||||
golden_output_file.close();
|
||||
simulator.clearListeners();
|
||||
simulator.terminate();
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
m_log << "Saving..." << endl;
|
||||
golden_output_file.close();
|
||||
m_log << "Done." << endl;
|
||||
|
||||
stringstream ss;
|
||||
ss << "triggered traps: ";
|
||||
for(std::vector<int>::iterator lIterator = m_lTraps.begin(); lIterator != m_lTraps.end(); ++lIterator)
|
||||
{
|
||||
ss << *lIterator << " ";
|
||||
}
|
||||
m_log << ss.str() << endl;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "util/Logger.hpp"
|
||||
#include "efw/ExperimentFlow.hpp"
|
||||
#include "efw/JobClient.hpp"
|
||||
#include "sal/Listener.hpp"
|
||||
|
||||
class FiascoFailExperiment : public fail::ExperimentFlow
|
||||
{
|
||||
private:
|
||||
fail::Logger m_log;
|
||||
fail::JobClient m_jc;
|
||||
std::string m_variant, m_benchmark;
|
||||
void readGoldenRun(std::string &);
|
||||
fail::BaseListener* waitIOOrOther(bool);
|
||||
void parseOptions();
|
||||
bool faultInjection();
|
||||
|
||||
std::string m_CurrentOutput;
|
||||
fail::guest_address_t endAddress;
|
||||
unsigned golden_run_instructions;
|
||||
unsigned long long golden_run_timer_ticks;
|
||||
fail::guest_address_t ecc_panic_address;
|
||||
fail::guest_address_t addr_errors_corrected;
|
||||
bool _golden_run;
|
||||
void goldenRun();
|
||||
|
||||
public:
|
||||
FiascoFailExperiment() : m_log("FiascoFail", false){}
|
||||
bool run();
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef __FIASCOFAIL_EXPERIMENT_INFO_HPP
|
||||
#define __FIASCOFAIL_EXPERIMENT_INFO_HPP
|
||||
|
||||
#define FIASCO_BREAK_BLINK 0xf004b800
|
||||
#define FIASCO_BREAK_LONGJMP 0xf004c88e
|
||||
|
||||
#define FIASCO_FAULTMODEL_BURST 1
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
import "DatabaseCampaignMessage.proto";
|
||||
|
||||
message FiascofailProtoMsg {
|
||||
required DatabaseCampaignMessage fsppilot = 1;
|
||||
|
||||
repeated group Result = 2 {
|
||||
// single experiment bit offset
|
||||
required uint32 bit_offset = 1 [(sql_primary_key) = true];
|
||||
|
||||
enum ResultType {
|
||||
OK = 0;
|
||||
SDC = 1;
|
||||
DETECTED = 2;
|
||||
TRAP = 3;
|
||||
TIMEOUT = 4;
|
||||
UNKNOWN = 5;
|
||||
}
|
||||
required ResultType resulttype = 2;
|
||||
|
||||
// all subsequent fields are optional, resulting in NULLable DB
|
||||
// columns, saving space when unused; NULL should be interpreted as 0
|
||||
// for these cases
|
||||
enum MemAccessOutside {
|
||||
NONE = 0;
|
||||
READ = 1;
|
||||
WRITE = 2;
|
||||
}
|
||||
optional MemAccessOutside memaccess_outside = 3;
|
||||
|
||||
enum Flag {
|
||||
FALSE = 0;
|
||||
TRUE = 1;
|
||||
}
|
||||
optional Flag jump_outside = 4;
|
||||
|
||||
// did ECC correct the fault?
|
||||
optional Flag error_corrected = 5;
|
||||
|
||||
// simulated runtime factor compared to golden run (1.000 = golden run runtime)
|
||||
optional float sim_runtime_factor = 6;
|
||||
|
||||
// especially interesting for TRAP/UNKNOWN: latest IP
|
||||
optional uint32 latest_ip = 7;
|
||||
|
||||
// optional textual description of what happened
|
||||
optional string details = 8;
|
||||
|
||||
// experiment runtime (FIXME: should be part of DatabaseCampaignMessage instead)
|
||||
optional float runtime = 9;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#include "experiment.hpp"
|
||||
#include "sal/SALInst.hpp"
|
||||
|
||||
void instantiateFiascoFailExperiment()
|
||||
{
|
||||
fail::simulator.addFlow(new FiascoFailExperiment);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "cpn/CampaignManager.hpp"
|
||||
#include "util/CommandLine.hpp"
|
||||
#include "campaign.hpp"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
fail::CommandLine &cmd = fail::CommandLine::Inst();
|
||||
for(int i = 1; i < argc; ++i)
|
||||
{
|
||||
cmd.add_args(argv[i]);
|
||||
}
|
||||
|
||||
FiascoFailCampaign c;
|
||||
if(fail::campaignmanager.runCampaign(&c))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
set(EXPERIMENT_NAME generic-experiment)
|
||||
set(EXPERIMENT_TYPE GenericExperiment)
|
||||
configure_file(../instantiate-experiment.ah.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/instantiate-${EXPERIMENT_NAME}.ah @ONLY
|
||||
)
|
||||
|
||||
## Setup desired protobuf descriptions HERE ##
|
||||
set(MY_PROTOS
|
||||
generic-experiment.proto
|
||||
)
|
||||
|
||||
set(MY_CAMPAIGN_SRCS
|
||||
experiment.hpp
|
||||
experiment.cc
|
||||
campaign.hpp
|
||||
campaign.cc
|
||||
)
|
||||
|
||||
#### PROTOBUFS ####
|
||||
find_package(Protobuf REQUIRED)
|
||||
include_directories(${PROTOBUF_INCLUDE_DIRS})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
find_package(MySQL REQUIRED)
|
||||
include_directories(${MYSQL_INCLUDE_DIR})
|
||||
|
||||
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
|
||||
|
||||
## Build library
|
||||
add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS})
|
||||
add_dependencies(fail-${EXPERIMENT_NAME} fail-comm)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY} fail-sal)
|
||||
|
||||
## This is the example's campaign server distributing experiment parameters
|
||||
add_executable(${EXPERIMENT_NAME}-server main.cc)
|
||||
target_link_libraries(${EXPERIMENT_NAME}-server -Wl,--start-group fail-${EXPERIMENT_NAME} fail-sal fail-util fail-cpn fail-comm ${PROTOBUF_LIBRARY} ${Boost_THREAD_LIBRARY} ${MYSQL_LIBRARIES} -Wl,--end-group)
|
||||
install(TARGETS ${EXPERIMENT_NAME}-server RUNTIME DESTINATION bin)
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include "campaign.hpp"
|
||||
#include "experimentInfo.hpp"
|
||||
#include "cpn/CampaignManager.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include "util/ProtoStream.hpp"
|
||||
#include "sal/SALConfig.hpp"
|
||||
|
||||
#include "experimentInfo.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace fail;
|
||||
using namespace google::protobuf;
|
||||
|
||||
void GenericExperimentCampaign::cb_send_pilot(DatabaseCampaignMessage pilot) {
|
||||
GenericExperimentData *data = new GenericExperimentData;
|
||||
data->msg.mutable_fsppilot()->CopyFrom(pilot);
|
||||
campaignmanager.addParam(data);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef __KESOGCCAMPAIGN_HPP__
|
||||
#define __KESOGCCAMPAIGN_HPP__
|
||||
|
||||
#include "cpn/DatabaseCampaign.hpp"
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
class GenericExperimentCampaign : public fail::DatabaseCampaign {
|
||||
virtual const google::protobuf::Descriptor * cb_result_message() {
|
||||
return google::protobuf::DescriptorPool::generated_pool()
|
||||
->FindMessageTypeByName("GenericExperimentMessage");
|
||||
}
|
||||
|
||||
virtual void cb_send_pilot(DatabaseCampaignMessage pilot);
|
||||
};
|
||||
|
||||
#endif // __KESOGCCAMPAIGN_HPP__
|
||||
@@ -0,0 +1,2 @@
|
||||
SET(bochs_configure_params "--enable-a20-pin;--enable-x86-64;--enable-cpu-level=6;--enable-ne2000;--enable-acpi;--enable-pci;--enable-usb;--enable-trace-cache;--enable-fast-function-calls;--enable-host-specific-asms;--enable-readline;--enable-clgd54xx;--enable-fpu;--enable-vmx=2;--enable-monitor-mwait;--enable-cdrom;--enable-sb16=linux;--enable-gdb-stub;--with-nogui" CACHE STRING "")
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
// getpid
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "experiment.hpp"
|
||||
#include "experimentInfo.hpp"
|
||||
#include "sal/SALConfig.hpp"
|
||||
#include "sal/SALInst.hpp"
|
||||
#include "sal/Memory.hpp"
|
||||
#include "sal/Listener.hpp"
|
||||
|
||||
#include "sal/bochs/BochsListener.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "campaign.hpp"
|
||||
#include "generic-experiment.pb.h"
|
||||
#include "util/CommandLine.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace fail;
|
||||
|
||||
|
||||
GenericExperiment::~GenericExperiment() {}
|
||||
|
||||
static GenericExperimentData space_for_param;
|
||||
ExperimentData* GenericExperiment::cb_allocate_experiment_data() {
|
||||
return &space_for_param;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a new result slot in the given experiment data
|
||||
*/
|
||||
google::protobuf::Message* GenericExperiment::cb_new_result(ExperimentData* data) {
|
||||
GenericExperimentData *param = static_cast<GenericExperimentData *>(data);
|
||||
GenericExperimentMessage_Result *result = param->msg.add_result();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void handleEvent(GenericExperimentMessage_Result& result,
|
||||
GenericExperimentMessage_Result_ResultType restype,
|
||||
unsigned int details) {
|
||||
cout << "Result details: " << restype << " "<< details << endl;
|
||||
result.set_resulttype(restype);
|
||||
result.set_details(details);
|
||||
}
|
||||
|
||||
void GenericExperiment::parseSymbols(const std::string &args, std::set<fail::BaseListener *> * into) {
|
||||
std::vector<std::string> elems;
|
||||
std::stringstream ss(args);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, ',')) {
|
||||
const ElfSymbol * symbol = &m_elf.getSymbol(item);
|
||||
if (!symbol->isValid()) {
|
||||
m_log << "ELF Symbol not found: " << item << endl;
|
||||
simulator.terminate(1);
|
||||
}
|
||||
m_log << "Adding symbol " << item << " at 0x" << hex << symbol->getAddress() << endl;
|
||||
BPSingleListener *l = new BPSingleListener(symbol->getAddress());
|
||||
into->insert(l);
|
||||
end_markers.insert(l);
|
||||
listener_to_symbol[l] = symbol;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool GenericExperiment::cb_start_experiment() {
|
||||
CommandLine &cmd = CommandLine::Inst();
|
||||
cmd.addOption("", "", Arg::None, "USAGE: fail-client -Wf,[option] -Wf,[option] ... <BochsOptions...>\n\n");
|
||||
CommandLine::option_handle HELP = cmd.addOption("h", "help", Arg::None, "-h,--help \tPrint usage and exit");
|
||||
|
||||
CommandLine::option_handle STATE_DIR = cmd.addOption("", "state-dir", Arg::Required,
|
||||
"--state-dir \t Path to the state directory");
|
||||
|
||||
// catch any trap
|
||||
CommandLine::option_handle TRAP = cmd.addOption("", "trap", Arg::None,
|
||||
"--trap \tCatch Traps");
|
||||
CommandLine::option_handle WRITE_MEM_TEXT = cmd.addOption("", "catch-write-textsegment", Arg::None,
|
||||
"--catch-write-textsegment \tCatch writes to the text segment");
|
||||
|
||||
CommandLine::option_handle WRITE_MEM_OUTERSPACE
|
||||
= cmd.addOption("", "catch-write-outerspace", Arg::None,
|
||||
"--catch-write-outerspace \tCatch writes to the outerspace");
|
||||
|
||||
CommandLine::option_handle TIMEOUT = cmd.addOption("", "timeout", Arg::Required,
|
||||
"--timeout \t Experiment Timeout in uS");
|
||||
|
||||
|
||||
std::map<std::string, CommandLine::option_handle> option_handles;
|
||||
for (std::map<std::string, ListenerSet *>::iterator it = end_marker_groups.begin();
|
||||
it != end_marker_groups.end(); ++it) {
|
||||
CommandLine::option_handle handle =
|
||||
cmd.addOption("", it->first, Arg::Required,
|
||||
"--" + it->first + " \tList of symbols (comma separated)");
|
||||
option_handles[it->first] = handle;
|
||||
}
|
||||
|
||||
if (!cmd.parse()) {
|
||||
cerr << "Error parsing arguments." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (cmd[HELP]) {
|
||||
cmd.printUsage();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
address_t minimal_ip = INT_MAX; // Every address is lower
|
||||
address_t maximal_ip = 0;
|
||||
address_t minimal_data = 0x100000; // 1 Mbyte
|
||||
address_t maximal_data = 0;
|
||||
|
||||
for (ElfReader::section_iterator it = m_elf.sec_begin();
|
||||
it != m_elf.sec_end(); ++it) {
|
||||
const ElfSymbol &symbol = *it;
|
||||
std::string prefix(".text");
|
||||
if (symbol.getName().compare(0, prefix.size(), prefix) == 0) {
|
||||
minimal_ip = std::min(minimal_ip, symbol.getStart());
|
||||
maximal_ip = std::max(maximal_ip, symbol.getEnd());
|
||||
} else {
|
||||
minimal_data = std::min(minimal_data, symbol.getStart());
|
||||
maximal_data = std::max(maximal_data, symbol.getEnd());
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd[WRITE_MEM_TEXT]) {
|
||||
m_log << "Catch writes to text segment from " << hex << minimal_ip << " to " << maximal_ip << std::endl;
|
||||
enabled_mem_text = true;
|
||||
|
||||
l_mem_text.setWatchAddress(minimal_ip);
|
||||
l_mem_text.setTriggerAccessType(MemAccessEvent::MEM_WRITE);
|
||||
l_mem_text.setWatchWidth(maximal_ip - minimal_ip);
|
||||
}
|
||||
|
||||
if (cmd[WRITE_MEM_OUTERSPACE]) {
|
||||
m_log << "Catch writes to outerspace from " << hex << " from " << maximal_data << std::endl;
|
||||
enabled_mem_outerspace = true;
|
||||
|
||||
l_mem_outerspace.setWatchAddress(maximal_data);
|
||||
l_mem_outerspace.setTriggerAccessType(MemAccessEvent::MEM_WRITE);
|
||||
l_mem_outerspace.setWatchWidth(0xfffffff0);
|
||||
}
|
||||
|
||||
if (cmd[TRAP]) {
|
||||
m_log << "Catch all traps" << endl;
|
||||
enabled_trap = true;
|
||||
}
|
||||
|
||||
if (cmd[STATE_DIR]) {
|
||||
std::string value(cmd[STATE_DIR].first()->arg);
|
||||
m_state_dir = value;
|
||||
m_log << "Set state dir to " << value << endl;
|
||||
}
|
||||
|
||||
if (cmd[TIMEOUT]) {
|
||||
std::string value(cmd[TIMEOUT].first()->arg);
|
||||
std::stringstream ss(value);
|
||||
ss >> m_Timeout;
|
||||
if (ss.bad()) {
|
||||
m_log << "Could not parse --timeout argument" << endl;
|
||||
return false; // Initialization failed
|
||||
}
|
||||
l_timeout.setTimeout(m_Timeout);
|
||||
enabled_timeout = true;
|
||||
m_log << "Enabled Experiment Timeout of " << dec << m_Timeout << " microseconds" << endl;
|
||||
}
|
||||
|
||||
for (std::map<std::string, CommandLine::option_handle>::iterator it = option_handles.begin();
|
||||
it != option_handles.end(); ++it) {
|
||||
if (cmd[option_handles[it->first]]) {
|
||||
option::Option *opt = cmd[option_handles[it->first]].first();
|
||||
while (opt != 0) {
|
||||
parseSymbols(std::string(opt->arg), end_marker_groups[it->first]);
|
||||
opt = opt->next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true; // Everything OK
|
||||
}
|
||||
|
||||
|
||||
bool GenericExperiment::cb_before_resume() {
|
||||
if (enabled_trap)
|
||||
simulator.addListener(&l_trap);
|
||||
|
||||
if (enabled_mem_text)
|
||||
simulator.addListener(&l_mem_text);
|
||||
|
||||
if (enabled_mem_outerspace) {
|
||||
std::cout << "enabled mem outerspace " << endl;
|
||||
simulator.addListener(&l_mem_outerspace);
|
||||
}
|
||||
|
||||
if (enabled_timeout)
|
||||
simulator.addListener(&l_timeout);
|
||||
|
||||
for (std::set<BaseListener *>::iterator it = end_markers.begin();
|
||||
it != end_markers.end(); ++it) {
|
||||
simulator.addListener(*it);
|
||||
}
|
||||
|
||||
return true; // everything OK
|
||||
}
|
||||
|
||||
void GenericExperiment::cb_after_resume(fail::BaseListener *event) {
|
||||
GenericExperimentMessage_Result * result = static_cast<GenericExperimentMessage_Result *>(this->get_current_result());
|
||||
|
||||
// Record the crash time
|
||||
result->set_crash_time(simulator.getTimerTicks());
|
||||
|
||||
|
||||
if (event == &l_timeout) {
|
||||
handleEvent(*result, result->TIMEOUT, m_Timeout);
|
||||
} else if (event == &l_trap) {
|
||||
handleEvent(*result, result->TRAP, l_trap.getTriggerNumber());
|
||||
} else if (event == &l_mem_text) {
|
||||
handleEvent(*result, result->WRITE_TEXTSEGMENT,
|
||||
l_mem_text.getTriggerAddress());
|
||||
|
||||
} else if (event == &l_mem_outerspace){
|
||||
handleEvent(*result, result->WRITE_OUTERSPACE,
|
||||
l_mem_outerspace.getTriggerAddress());
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// End Marker Groups
|
||||
//////////////////////////////////////////////////
|
||||
} else if (OK_marker.find(event) != OK_marker.end()) {
|
||||
const ElfSymbol *symbol = listener_to_symbol[event];
|
||||
handleEvent(*result, result->OK_MARKER, symbol->getAddress());
|
||||
|
||||
} else if (FAIL_marker.find(event) != FAIL_marker.end()) {
|
||||
const ElfSymbol *symbol = listener_to_symbol[event];
|
||||
handleEvent(*result, result->FAIL_MARKER, symbol->getAddress());
|
||||
|
||||
} else if (DETECTED_marker.find(event) != DETECTED_marker.end()) {
|
||||
const ElfSymbol *symbol = listener_to_symbol[event];
|
||||
handleEvent(*result, result->DETECTED_MARKER, symbol->getAddress());
|
||||
|
||||
} else if (GROUP1_marker.find(event) != GROUP1_marker.end()) {
|
||||
const ElfSymbol *symbol = listener_to_symbol[event];
|
||||
handleEvent(*result, result->GROUP1_MARKER, symbol->getAddress());
|
||||
|
||||
} else if (GROUP2_marker.find(event) != GROUP2_marker.end()) {
|
||||
const ElfSymbol *symbol = listener_to_symbol[event];
|
||||
handleEvent(*result, result->GROUP2_MARKER, symbol->getAddress());
|
||||
|
||||
} else if (GROUP3_marker.find(event) != GROUP3_marker.end()) {
|
||||
const ElfSymbol *symbol = listener_to_symbol[event];
|
||||
handleEvent(*result, result->GROUP3_MARKER, symbol->getAddress());
|
||||
|
||||
} else if (GROUP4_marker.find(event) != GROUP4_marker.end()) {
|
||||
const ElfSymbol *symbol = listener_to_symbol[event];
|
||||
handleEvent(*result, result->GROUP4_MARKER, symbol->getAddress());
|
||||
|
||||
} else {
|
||||
handleEvent(*result, result->UNKNOWN, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
#ifndef __GENERIC_EXPERIMENT_EXPERIMENT_HPP__
|
||||
#define __GENERIC_EXPERIMENT_EXPERIMENT_HPP__
|
||||
|
||||
#include "sal/SALInst.hpp"
|
||||
#include "efw/DatabaseExperiment.hpp"
|
||||
#include "sal/Listener.hpp"
|
||||
#include "efw/JobClient.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include "util/ElfReader.hpp"
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
|
||||
class GenericExperiment : public fail::DatabaseExperiment {
|
||||
fail::ElfReader m_elf;
|
||||
|
||||
std::string m_state_dir;
|
||||
|
||||
bool enabled_mem_text;
|
||||
fail::MemAccessListener l_mem_text;
|
||||
|
||||
bool enabled_mem_outerspace;
|
||||
fail::MemAccessListener l_mem_outerspace;
|
||||
|
||||
bool enabled_trap;
|
||||
fail::TrapListener l_trap;
|
||||
|
||||
bool enabled_timeout;
|
||||
unsigned m_Timeout;
|
||||
fail::TimerListener l_timeout;
|
||||
|
||||
std::map<fail::BaseListener *, const fail::ElfSymbol *> listener_to_symbol;
|
||||
|
||||
typedef std::set<fail::BaseListener *> ListenerSet;
|
||||
|
||||
ListenerSet end_markers;
|
||||
ListenerSet OK_marker;
|
||||
ListenerSet FAIL_marker;
|
||||
ListenerSet DETECTED_marker;
|
||||
ListenerSet GROUP1_marker;
|
||||
ListenerSet GROUP2_marker;
|
||||
ListenerSet GROUP3_marker;
|
||||
ListenerSet GROUP4_marker;
|
||||
|
||||
std::map<std::string, ListenerSet * > end_marker_groups;
|
||||
|
||||
void parseSymbols(const std::string &args, std::set<fail::BaseListener *> *into);
|
||||
|
||||
public:
|
||||
GenericExperiment() : DatabaseExperiment("GenericExperiment"),
|
||||
m_state_dir("state"),
|
||||
l_trap(fail::ANY_TRAP), l_timeout(0) {
|
||||
enabled_mem_text = false;
|
||||
enabled_mem_outerspace = false;
|
||||
enabled_trap = false;
|
||||
enabled_timeout = false;
|
||||
|
||||
end_marker_groups["ok-marker"] = &OK_marker;
|
||||
end_marker_groups["fail-marker"] = &FAIL_marker;
|
||||
end_marker_groups["detected-marker"] = &FAIL_marker;
|
||||
end_marker_groups["group1-marker"] = &GROUP1_marker;
|
||||
end_marker_groups["group2-marker"] = &GROUP2_marker;
|
||||
end_marker_groups["group3-marker"] = &GROUP3_marker;
|
||||
end_marker_groups["group4-marker"] = &GROUP4_marker;
|
||||
}
|
||||
virtual ~GenericExperiment();
|
||||
|
||||
/**
|
||||
* Get path to the state directory
|
||||
*/
|
||||
virtual std::string cb_state_directory() { return m_state_dir; }
|
||||
|
||||
/**
|
||||
* Allocate enough space to hold the incoming ExperimentData message.
|
||||
*/
|
||||
virtual fail::ExperimentData* cb_allocate_experiment_data();
|
||||
|
||||
/**
|
||||
* Allocate a new result slot in the given experiment data
|
||||
*/
|
||||
virtual google::protobuf::Message* cb_new_result(fail::ExperimentData* data);
|
||||
|
||||
/**
|
||||
* Callback that is called, before the actual experiment
|
||||
* starts. Simulation is terminated on false.
|
||||
* @param The current result message
|
||||
* @return \c true on success, \c false otherwise
|
||||
*/
|
||||
virtual bool cb_start_experiment();
|
||||
|
||||
/**
|
||||
* Callback that is called before the resuming till crash has
|
||||
* started. This is called after the fault was injected. Here the
|
||||
* end listeners should be installed. Returns true on
|
||||
* success. Otherwise the experiment is canceled.
|
||||
|
||||
* @return \c true on success, \c false otherwise
|
||||
*/
|
||||
virtual bool cb_before_resume();
|
||||
|
||||
/**
|
||||
* Callback that is called after the resume-till-crash phase with
|
||||
* the last triggered listener. This callback should collect all
|
||||
* data and fill up the result message.
|
||||
*/
|
||||
virtual void cb_after_resume(fail::BaseListener *event);
|
||||
};
|
||||
|
||||
#endif // __GENERIC_EXPERIMENT_EXPERIMENT_HPP__
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef __EXPERIMENT_INFO_HPP__
|
||||
#define __EXPERIMENT_INFO_HPP__
|
||||
|
||||
#include "comm/ExperimentData.hpp"
|
||||
#include "generic-experiment.pb.h"
|
||||
|
||||
class GenericExperimentData : public fail::ExperimentData {
|
||||
public:
|
||||
GenericExperimentMessage msg;
|
||||
GenericExperimentData() : fail::ExperimentData(&msg) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // __EXPERIMENT_INFO_HPP__
|
||||
@@ -0,0 +1,36 @@
|
||||
import "DatabaseCampaignMessage.proto";
|
||||
|
||||
message GenericExperimentMessage {
|
||||
required DatabaseCampaignMessage fsppilot = 1;
|
||||
|
||||
repeated group Result = 2 {
|
||||
// This submessage is required by the database experiment and
|
||||
// is filled with standard experiment result values
|
||||
required DatabaseExperimentMessage base_result = 1;
|
||||
|
||||
// make these optional to reduce overhead for server->client communication
|
||||
enum ResultType {
|
||||
OK_MARKER = 1;
|
||||
FAIL_MARKER = 2;
|
||||
DETECTED_MARKER = 3;
|
||||
|
||||
GROUP1_MARKER = 4;
|
||||
GROUP2_MARKER = 5;
|
||||
GROUP3_MARKER = 6;
|
||||
GROUP4_MARKER = 7;
|
||||
|
||||
TIMEOUT = 8;
|
||||
TRAP = 9;
|
||||
WRITE_TEXTSEGMENT = 10;
|
||||
WRITE_OUTERSPACE = 11;
|
||||
|
||||
UNKNOWN = 100;
|
||||
}
|
||||
// result type, see above
|
||||
required ResultType resulttype = 4;
|
||||
|
||||
required uint64 crash_time = 5;
|
||||
|
||||
optional uint64 details = 7;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "cpn/CampaignManager.hpp"
|
||||
#include "util/CommandLine.hpp"
|
||||
#include "campaign.hpp"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
fail::CommandLine &cmd = fail::CommandLine::Inst();
|
||||
for (int i = 1; i < argc; ++i)
|
||||
cmd.add_args(argv[i]);
|
||||
|
||||
GenericExperimentCampaign c;
|
||||
if (fail::campaignmanager.runCampaign(&c)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
SET(PLUGINS_ACTIVATED "tracing" CACHE STRING "")
|
||||
|
||||
SET(bochs_configure_params "--enable-a20-pin;--enable-x86-64;--enable-cpu-level=6;--enable-ne2000;--enable-acpi;--enable-pci;--enable-usb;--enable-trace-cache;--enable-fast-function-calls;--enable-host-specific-asms;--enable-readline;--enable-clgd54xx;--enable-fpu;--enable-vmx=2;--enable-monitor-mwait;--enable-cdrom;--enable-sb16=linux;--enable-gdb-stub;--with-nogui" CACHE STRING "")
|
||||
|
||||
# Build the import and prune trace tools always
|
||||
SET(BUILD_IMPORT_TRACE ON CACHE BOOL "" FORCE)
|
||||
SET(BUILD_PRUNE_TRACE ON CACHE BOOL "" FORCE)
|
||||
SET(BUILD_CONVERT_TRACE ON CACHE BOOL "" FORCE)
|
||||
SET(BUILD_DUMP_TRACE ON CACHE BOOL "" FORCE)
|
||||
SET(BUILD_LLVM_DISASSEMBLER ON CACHE BOOL "" FORCE)
|
||||
@@ -15,3 +15,6 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
## build library
|
||||
add_library(fail-${EXPERIMENT_NAME} ${MY_EXPERIMENT_SRCS})
|
||||
add_dependencies(fail-${EXPERIMENT_NAME} fail-comm)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} fail-tracing fail-serialoutput fail-comm fail-util)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY})
|
||||
|
||||
@@ -27,8 +27,8 @@ PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${MY_PROTOS})
|
||||
|
||||
## Build library
|
||||
add_library(fail-${EXPERIMENT_NAME} ${PROTO_SRCS} ${PROTO_HDRS} ${MY_CAMPAIGN_SRCS})
|
||||
add_dependencies(fail-${EXPERIMENT_NAME} fail-comm)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} fail-tracing fail-comm)
|
||||
add_dependencies(fail-${EXPERIMENT_NAME} fail-comm fail-util fail-sal fail-tracing)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} fail-comm fail-util fail-sal fail-tracing)
|
||||
target_link_libraries(fail-${EXPERIMENT_NAME} ${PROTOBUF_LIBRARY})
|
||||
|
||||
## This is the example's campaign server distributing experiment parameters
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
## Configuration
|
||||
SET(PLUGINS_ACTIVATED "tracing" CACHE STRING "")
|
||||
|
||||
SET(bochs_configure_params "--enable-a20-pin;--enable-x86-64;--enable-cpu-level=6;--enable-ne2000;--enable-acpi;--enable-pci;--enable-usb;--enable-trace-cache;--enable-fast-function-calls;--enable-host-specific-asms;--enable-disasm;--enable-readline;--enable-clgd54xx;--enable-fpu;--enable-vmx=2;--enable-monitor-mwait;--enable-cdrom;--enable-sb16=linux;--enable-gdb-stub;--with-nogui" CACHE STRING "")
|
||||
@@ -5,6 +5,9 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "util/Logger.hpp"
|
||||
#include "util/ElfReader.hpp"
|
||||
#include "util/CommandLine.hpp"
|
||||
#include "util/gzstream/gzstream.h"
|
||||
|
||||
#include "experiment.hpp"
|
||||
#include "experimentInfo.hpp"
|
||||
@@ -25,6 +28,8 @@
|
||||
|
||||
using namespace std;
|
||||
using namespace fail;
|
||||
const std::string WeatherMonitorExperiment::dir_images(DIR_IMAGES);
|
||||
const std::string WeatherMonitorExperiment::dir_prerequisites(DIR_PREREQUISITES);
|
||||
|
||||
// Check if configuration dependencies are satisfied:
|
||||
#if !defined(CONFIG_EVENT_BREAKPOINTS) || !defined(CONFIG_SR_RESTORE) || \
|
||||
@@ -32,61 +37,183 @@ using namespace fail;
|
||||
#error This experiment needs: breakpoints, traps, save, and restore. Enable these in the configuration.
|
||||
#endif
|
||||
|
||||
bool WeatherMonitorExperiment::run()
|
||||
bool WeatherMonitorExperiment::readElfSymbols(
|
||||
guest_address_t& entry,
|
||||
guest_address_t& text_start,
|
||||
guest_address_t& text_end,
|
||||
guest_address_t& data_start,
|
||||
guest_address_t& data_end,
|
||||
guest_address_t& wait_begin,
|
||||
guest_address_t& wait_end,
|
||||
guest_address_t& vptr_panic)
|
||||
{
|
||||
char const *statename = "bochs.state" WEATHER_SUFFIX;
|
||||
Logger log("Weathermonitor", false);
|
||||
BPSingleListener bp;
|
||||
ElfReader elfreader(filename_elf(m_variant, m_benchmark).c_str());
|
||||
|
||||
log << "startup" << endl;
|
||||
entry = elfreader.getSymbol("main").getAddress();
|
||||
text_start = elfreader.getSymbol("___TEXT_START__").getAddress();
|
||||
text_end = elfreader.getSymbol("___TEXT_END__").getAddress();
|
||||
data_start = elfreader.getSymbol("___DATA_START__").getAddress();
|
||||
data_end = elfreader.getSymbol("___BSS_END__").getAddress();
|
||||
wait_begin = elfreader.getSymbol("wait_begin").getAddress();
|
||||
wait_end = elfreader.getSymbol("wait_end").getAddress();
|
||||
|
||||
/*
|
||||
* this does not work as the guestsys doesn't output anything
|
||||
* albeit that, it's no longer needed in this experiment
|
||||
*/
|
||||
|
||||
#if 0
|
||||
// STEP 0: record memory map with vptr addresses
|
||||
ofstream mmap;
|
||||
mmap.open ("memory.map");
|
||||
GuestListener g;
|
||||
while (true) {
|
||||
simulator.addListenerAndResume(&g);
|
||||
mmap << g.getData() << flush;
|
||||
// vptr_panic only exists in guarded version
|
||||
vptr_panic = elfreader.getSymbol("vptr_panic").getAddress();
|
||||
// use a dummy address, in case the symbol cannot be found
|
||||
if (vptr_panic == ADDR_INV) {
|
||||
vptr_panic = 99999999;
|
||||
}
|
||||
mmap.close();
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
if (entry == ADDR_INV || text_start == ADDR_INV || text_end == ADDR_INV ||
|
||||
data_start == ADDR_INV || data_end == ADDR_INV ||
|
||||
wait_begin == ADDR_INV || wait_end == ADDR_INV) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string WeatherMonitorExperiment::filename_elf(const std::string& variant, const std::string& benchmark)
|
||||
{
|
||||
if (variant.size() && benchmark.size()) {
|
||||
return dir_images + "/" + variant + ".elf";
|
||||
}
|
||||
return "weather.elf";
|
||||
}
|
||||
|
||||
std::string WeatherMonitorExperiment::filename_state(const std::string& variant, const std::string& benchmark)
|
||||
{
|
||||
if (variant.size() && benchmark.size()) {
|
||||
return dir_prerequisites + "/" + variant + ".state";
|
||||
}
|
||||
return "state.weather";
|
||||
}
|
||||
|
||||
std::string WeatherMonitorExperiment::filename_trace(const std::string& variant, const std::string& benchmark)
|
||||
{
|
||||
if (variant.size() && benchmark.size()) {
|
||||
return dir_prerequisites + "/" + variant + ".trace";
|
||||
}
|
||||
return "trace.weather";
|
||||
}
|
||||
|
||||
std::string WeatherMonitorExperiment::filename_traceinfo(const std::string& variant, const std::string& benchmark)
|
||||
{
|
||||
if (variant.size() && benchmark.size()) {
|
||||
return dir_prerequisites + "/" + variant + ".info";
|
||||
}
|
||||
return "weather.info";
|
||||
}
|
||||
|
||||
bool WeatherMonitorExperiment::writeTraceInfo(unsigned numinstr_tracing, unsigned numinstr_after)
|
||||
{
|
||||
ofstream ti(filename_traceinfo(m_variant, m_benchmark).c_str(), ios::out);
|
||||
if (!ti.is_open()) {
|
||||
cout << "failed to open " << filename_traceinfo(m_variant, m_benchmark) << endl;
|
||||
return false;
|
||||
}
|
||||
ti << numinstr_tracing << endl << numinstr_after << endl;
|
||||
ti.flush();
|
||||
ti.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherMonitorExperiment::readTraceInfo(unsigned& numinstr_tracing, unsigned& numinstr_after)
|
||||
{
|
||||
ifstream file(filename_traceinfo(m_variant, m_benchmark).c_str());
|
||||
if (!file.is_open()) {
|
||||
cout << "failed to open " << filename_traceinfo(m_variant, m_benchmark) << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
string buf;
|
||||
unsigned count = 0;
|
||||
|
||||
while (getline(file, buf)) {
|
||||
stringstream ss(buf, ios::in);
|
||||
switch (count) {
|
||||
case 0:
|
||||
ss >> numinstr_tracing;
|
||||
break;
|
||||
case 1:
|
||||
ss >> numinstr_after;
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
file.close();
|
||||
assert(count == 2);
|
||||
return (count == 2);
|
||||
}
|
||||
|
||||
|
||||
void WeatherMonitorExperiment::parseOptions()
|
||||
{
|
||||
CommandLine &cmd = CommandLine::Inst();
|
||||
cmd.addOption("", "", Arg::None, "USAGE: fail-client -Wf,[option] -Wf,[option] ... <BochsOptions...>");
|
||||
CommandLine::option_handle HELP =
|
||||
cmd.addOption("h", "help", Arg::None, "-h,--help \tPrint usage and exit");
|
||||
CommandLine::option_handle VARIANT =
|
||||
cmd.addOption("", "variant", Arg::Required, "--variant v \texperiment variant");
|
||||
CommandLine::option_handle BENCHMARK =
|
||||
cmd.addOption("", "benchmark", Arg::Required, "--benchmark b \tbenchmark");
|
||||
|
||||
if (!cmd.parse()) {
|
||||
cerr << "Error parsing arguments." << endl;
|
||||
simulator.terminate(1);
|
||||
} else if (cmd[HELP]) {
|
||||
cmd.printUsage();
|
||||
simulator.terminate(0);
|
||||
}
|
||||
|
||||
if (cmd[VARIANT].count() > 0 && cmd[BENCHMARK].count() > 0) {
|
||||
m_variant = std::string(cmd[VARIANT].first()->arg);
|
||||
m_benchmark = std::string(cmd[BENCHMARK].first()->arg);
|
||||
} else {
|
||||
cerr << "Please supply parameters for --variant and --benchmark." << endl;
|
||||
simulator.terminate(1);
|
||||
}
|
||||
}
|
||||
|
||||
bool WeatherMonitorExperiment::establishState(guest_address_t& entry)
|
||||
{
|
||||
// STEP 1: run until interesting function starts, and save state
|
||||
bp.setWatchInstructionPointer(WEATHER_FUNC_MAIN);
|
||||
bp.setWatchInstructionPointer(entry);
|
||||
simulator.addListenerAndResume(&bp);
|
||||
log << "test function entry reached, saving state" << endl;
|
||||
log << "EIP = " << hex << bp.getTriggerInstructionPointer() << endl;
|
||||
simulator.save(statename);
|
||||
assert(bp.getTriggerInstructionPointer() == WEATHER_FUNC_MAIN);
|
||||
assert(simulator.getCPU(0).getInstructionPointer() == WEATHER_FUNC_MAIN);
|
||||
LOG << "test function entry reached, saving state" << endl;
|
||||
LOG << "EIP = " << hex << bp.getTriggerInstructionPointer() << endl;
|
||||
simulator.save(filename_state(m_variant, m_benchmark).c_str());
|
||||
assert(bp.getTriggerInstructionPointer() == entry);
|
||||
assert(simulator.getCPU(0).getInstructionPointer() == entry);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherMonitorExperiment::performTrace(
|
||||
guest_address_t& entry,
|
||||
guest_address_t& data_start,
|
||||
guest_address_t& data_end,
|
||||
guest_address_t& wait_end)
|
||||
{
|
||||
// STEP 2: record trace for fault-space pruning
|
||||
log << "restoring state" << endl;
|
||||
simulator.restore(statename);
|
||||
log << "EIP = " << hex << simulator.getCPU(0).getInstructionPointer() << endl;
|
||||
assert(simulator.getCPU(0).getInstructionPointer() == WEATHER_FUNC_MAIN);
|
||||
LOG << "STEP 2 restoring state" << endl;
|
||||
simulator.restore(filename_state(m_variant, m_benchmark).c_str());
|
||||
LOG << "EIP = " << hex << simulator.getCPU(0).getInstructionPointer() << endl;
|
||||
assert(simulator.getCPU(0).getInstructionPointer() == entry);
|
||||
|
||||
log << "enabling tracing" << endl;
|
||||
LOG << "enabling tracing" << endl;
|
||||
TracingPlugin tp;
|
||||
|
||||
// TODO: record max(ESP)
|
||||
|
||||
// restrict memory access logging to injection target
|
||||
MemoryMap mm;
|
||||
mm.add(WEATHER_DATA_START, WEATHER_DATA_END - WEATHER_DATA_START);
|
||||
mm.add(data_start, data_end - data_start);
|
||||
tp.restrictMemoryAddresses(&mm);
|
||||
//tp.setLogIPOnly(true);
|
||||
|
||||
// record trace
|
||||
char const *tracefile = "trace.tc" WEATHER_SUFFIX;
|
||||
ofstream of(tracefile);
|
||||
ogzstream of(filename_trace(m_variant, m_benchmark).c_str());
|
||||
tp.setTraceFile(&of);
|
||||
|
||||
// this must be done *after* configuring the plugin:
|
||||
@@ -95,7 +222,7 @@ bool WeatherMonitorExperiment::run()
|
||||
#if 1
|
||||
// trace WEATHER_NUMITER_TRACING measurement loop iterations
|
||||
// -> calibration
|
||||
bp.setWatchInstructionPointer(WEATHER_FUNC_WAIT_END);
|
||||
bp.setWatchInstructionPointer(wait_end);
|
||||
bp.setCounter(WEATHER_NUMITER_TRACING);
|
||||
#else
|
||||
// FIXME this doesn't work properly: trace is one instruction too short as
|
||||
@@ -111,54 +238,61 @@ bool WeatherMonitorExperiment::run()
|
||||
|
||||
// count instructions
|
||||
// FIXME add SAL functionality for this?
|
||||
int instr_counter = 0;
|
||||
unsigned numinstr_tracing = 0;
|
||||
while (simulator.resume() == &ev_count) {
|
||||
++instr_counter;
|
||||
++numinstr_tracing;
|
||||
simulator.addListener(&ev_count);
|
||||
}
|
||||
|
||||
log << dec << "tracing finished after " << instr_counter
|
||||
LOG << dec << "tracing finished after " << numinstr_tracing
|
||||
<< " instructions, seeing wait_end " << WEATHER_NUMITER_TRACING << " times" << endl;
|
||||
simulator.removeFlow(&tp);
|
||||
|
||||
// serialize trace to file
|
||||
if (of.fail()) {
|
||||
log << "failed to write " << tracefile << endl;
|
||||
LOG << "failed to write " << filename_trace(m_variant, m_benchmark) << endl;
|
||||
simulator.clearListeners(this); // cleanup
|
||||
return false;
|
||||
}
|
||||
of.close();
|
||||
log << "trace written to " << tracefile << endl;
|
||||
LOG << "trace written to " << filename_trace(m_variant, m_benchmark) << endl;
|
||||
|
||||
// wait another WEATHER_NUMITER_AFTER measurement loop iterations
|
||||
bp.setWatchInstructionPointer(WEATHER_FUNC_WAIT_END);
|
||||
bp.setWatchInstructionPointer(wait_end);
|
||||
bp.setCounter(WEATHER_NUMITER_AFTER);
|
||||
simulator.addListener(&bp);
|
||||
|
||||
// count instructions
|
||||
// FIXME add SAL functionality for this?
|
||||
instr_counter = 0;
|
||||
unsigned numinstr_after = 0;
|
||||
while (simulator.resume() == &ev_count) {
|
||||
++instr_counter;
|
||||
++numinstr_after;
|
||||
simulator.addListener(&ev_count);
|
||||
}
|
||||
|
||||
log << dec << "experiment finished after " << instr_counter
|
||||
LOG << dec << "experiment finished after " << numinstr_after
|
||||
<< " instructions, seeing wait_end " << WEATHER_NUMITER_AFTER << " times" << endl;
|
||||
|
||||
#elif 0
|
||||
// STEP 3: The actual experiment.
|
||||
if (!writeTraceInfo(numinstr_tracing, numinstr_after)) {
|
||||
LOG << "failed to write " << filename_traceinfo(m_variant, m_benchmark) << endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherMonitorExperiment::faultInjection()
|
||||
{
|
||||
#if !LOCAL
|
||||
for (int i = 0; i < 50 || (m_jc.getNumberOfUndoneJobs() != 0) ; ++i) { // only do 50 sequential experiments, to prevent swapping
|
||||
// 50 exp ~ 0.5GB RAM usage per instance (linearly increasing)
|
||||
#endif
|
||||
|
||||
// get an experiment parameter set
|
||||
log << "asking job server for experiment parameters" << endl;
|
||||
LOG << "asking job server for experiment parameters" << endl;
|
||||
WeatherMonitorExperimentData param;
|
||||
#if !LOCAL
|
||||
if (!m_jc.getParam(param)) {
|
||||
log << "Dying." << endl;
|
||||
LOG << "Dying." << endl;
|
||||
// communicate that we were told to die
|
||||
simulator.terminate(1);
|
||||
}
|
||||
@@ -168,9 +302,29 @@ bool WeatherMonitorExperiment::run()
|
||||
param.msg.fsppilot().set_data_address(0x00103bdc);
|
||||
#endif
|
||||
|
||||
|
||||
int id = param.getWorkloadID();
|
||||
m_variant = param.msg.fsppilot().variant();
|
||||
m_benchmark = param.msg.fsppilot().benchmark();
|
||||
unsigned injection_instr = param.msg.fsppilot().injection_instr();
|
||||
|
||||
/* get symbols from ELF */
|
||||
LOG << "retrieving ELF addresses..." << endl;
|
||||
guest_address_t entry, text_start, text_end, data_start, data_end, wait_begin, wait_end, vptr_panic;
|
||||
if (!readElfSymbols(entry, text_start, text_end, data_start, data_end, wait_begin, wait_end, vptr_panic)) {
|
||||
LOG << "failed, essential symbols are missing!" << endl;
|
||||
simulator.terminate(1);
|
||||
} else {
|
||||
LOG << "successfully retrieved ELF's addresses." << endl;
|
||||
}
|
||||
|
||||
/* get NUMINSTR_TRACING and NUMINSTR_AFTER */
|
||||
unsigned numinstr_tracing, numinstr_after;
|
||||
if (!readTraceInfo(numinstr_tracing, numinstr_after)) {
|
||||
LOG << "failed to read trace info from " << filename_traceinfo(m_variant, m_benchmark) << endl;
|
||||
simulator.terminate(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
address_t data_address = param.msg.fsppilot().data_address();
|
||||
|
||||
//old data. now it resides in the DatabaseCampaignMessage
|
||||
@@ -180,11 +334,11 @@ bool WeatherMonitorExperiment::run()
|
||||
// 8 results in one job
|
||||
WeathermonitorProtoMsg_Result *result = param.msg.add_result();
|
||||
result->set_bitoffset(bit_offset);
|
||||
log << dec << "job " << id << " instr " << injection_instr
|
||||
LOG << dec << "job " << id << " instr " << injection_instr
|
||||
<< " mem " << data_address << "+" << bit_offset << endl;
|
||||
|
||||
log << "restoring state" << endl;
|
||||
simulator.restore(statename);
|
||||
LOG << "restoring state" << endl;
|
||||
simulator.restore(filename_state(m_variant, m_benchmark).c_str());
|
||||
|
||||
// XXX debug
|
||||
/*
|
||||
@@ -197,13 +351,13 @@ bool WeatherMonitorExperiment::run()
|
||||
|
||||
// this marks THE END
|
||||
BPSingleListener ev_end(ANY_ADDR);
|
||||
ev_end.setCounter(WEATHER_NUMINSTR_TRACING + WEATHER_NUMINSTR_AFTER);
|
||||
ev_end.setCounter(numinstr_tracing + numinstr_after);
|
||||
simulator.addListener(&ev_end);
|
||||
|
||||
// count loop iterations by counting wait_begin() calls
|
||||
// FIXME would be nice to have a callback API for this as this needs to
|
||||
// be done "in parallel"
|
||||
BPSingleListener ev_wait_begin(WEATHER_FUNC_WAIT_BEGIN);
|
||||
BPSingleListener ev_wait_begin(wait_begin);
|
||||
simulator.addListener(&ev_wait_begin);
|
||||
int count_loop_iter_before = 0;
|
||||
|
||||
@@ -229,7 +383,7 @@ bool WeatherMonitorExperiment::run()
|
||||
// note at what IP we did it
|
||||
uint32_t injection_ip = simulator.getCPU(0).getInstructionPointer();
|
||||
result->set_iter_before_fi(count_loop_iter_before);
|
||||
log << "fault injected @ ip " << injection_ip
|
||||
LOG << "fault injected @ ip " << injection_ip
|
||||
<< " 0x" << hex << ((int)data) << " -> 0x" << ((int)newdata) << endl;
|
||||
// sanity check
|
||||
if (param.msg.fsppilot().has_injection_instr_absolute() &&
|
||||
@@ -237,7 +391,7 @@ bool WeatherMonitorExperiment::run()
|
||||
stringstream ss;
|
||||
ss << "SANITY CHECK FAILED: " << injection_ip
|
||||
<< " != " << param.msg.fsppilot().injection_instr_absolute();
|
||||
log << ss.str() << endl;
|
||||
LOG << ss.str() << endl;
|
||||
result->set_resulttype(result->UNKNOWN);
|
||||
result->set_latest_ip(injection_ip);
|
||||
result->set_details(ss.str());
|
||||
@@ -264,12 +418,12 @@ bool WeatherMonitorExperiment::run()
|
||||
TrapListener ev_trap(ANY_TRAP);
|
||||
simulator.addListener(&ev_trap);
|
||||
// jump outside text segment
|
||||
BPRangeListener ev_below_text(ANY_ADDR, WEATHER_TEXT_START - 1);
|
||||
BPRangeListener ev_beyond_text(WEATHER_TEXT_END + 1, ANY_ADDR);
|
||||
BPRangeListener ev_below_text(ANY_ADDR, text_start - 1);
|
||||
BPRangeListener ev_beyond_text(text_end + 1, ANY_ADDR);
|
||||
simulator.addListener(&ev_below_text);
|
||||
simulator.addListener(&ev_beyond_text);
|
||||
// error detected
|
||||
BPSingleListener ev_detected(WEATHER_FUNC_VPTR_PANIC);
|
||||
BPSingleListener ev_detected(vptr_panic);
|
||||
simulator.addListener(&ev_detected);
|
||||
// timeout (e.g., stuck in a HLT instruction)
|
||||
// 10000us = 500000 instructions
|
||||
@@ -278,7 +432,7 @@ bool WeatherMonitorExperiment::run()
|
||||
|
||||
#if LOCAL && 0
|
||||
// XXX debug
|
||||
log << "enabling tracing" << endl;
|
||||
LOG << "enabling tracing" << endl;
|
||||
TracingPlugin tp;
|
||||
tp.setLogIPOnly(true);
|
||||
tp.setOstream(&cout);
|
||||
@@ -300,28 +454,28 @@ bool WeatherMonitorExperiment::run()
|
||||
result->set_latest_ip(simulator.getCPU(0).getInstructionPointer());
|
||||
|
||||
if (ev == &ev_end) {
|
||||
log << "Result FINISHED (" << dec
|
||||
LOG << "Result FINISHED (" << dec
|
||||
<< count_loop_iter_before << "+" << count_loop_iter_after << ")" << endl;
|
||||
result->set_resulttype(result->FINISHED);
|
||||
} else if (ev == &ev_timeout) {
|
||||
log << "Result TIMEOUT (" << dec
|
||||
LOG << "Result TIMEOUT (" << dec
|
||||
<< count_loop_iter_before << "+" << count_loop_iter_after << ")" << endl;
|
||||
result->set_resulttype(result->TIMEOUT);
|
||||
} else if (ev == &ev_below_text || ev == &ev_beyond_text) {
|
||||
log << "Result OUTSIDE" << endl;
|
||||
LOG << "Result OUTSIDE" << endl;
|
||||
result->set_resulttype(result->OUTSIDE);
|
||||
} else if (ev == &ev_trap) {
|
||||
log << dec << "Result TRAP #" << ev_trap.getTriggerNumber() << endl;
|
||||
LOG << dec << "Result TRAP #" << ev_trap.getTriggerNumber() << endl;
|
||||
result->set_resulttype(result->TRAP);
|
||||
|
||||
stringstream ss;
|
||||
ss << ev_trap.getTriggerNumber();
|
||||
result->set_details(ss.str());
|
||||
} else if (ev == &ev_detected) {
|
||||
log << dec << "Result DETECTED" << endl;
|
||||
LOG << dec << "Result DETECTED" << endl;
|
||||
result->set_resulttype(result->DETECTED);
|
||||
} else {
|
||||
log << "Result WTF?" << endl;
|
||||
LOG << "Result WTF?" << endl;
|
||||
result->set_resulttype(result->UNKNOWN);
|
||||
|
||||
stringstream ss;
|
||||
@@ -331,7 +485,7 @@ bool WeatherMonitorExperiment::run()
|
||||
}
|
||||
// sanity check: do we have exactly 8 results?
|
||||
if (param.msg.result_size() != 8) {
|
||||
log << "WTF? param.msg.result_size() != 8" << endl;
|
||||
LOG << "WTF? param.msg.result_size() != 8" << endl;
|
||||
} else {
|
||||
#if !LOCAL
|
||||
m_jc.sendResult(param);
|
||||
@@ -342,7 +496,44 @@ bool WeatherMonitorExperiment::run()
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WeatherMonitorExperiment::run()
|
||||
{
|
||||
LOG << "startup" << endl;
|
||||
#if PREREQUISITES
|
||||
parseOptions();
|
||||
|
||||
/* get symbols from ELF */
|
||||
LOG << "retrieving ELF addresses..." << endl;
|
||||
guest_address_t entry, text_start, text_end, data_start, data_end, wait_begin, wait_end, vptr_panic;
|
||||
if (!readElfSymbols(entry, text_start, text_end, data_start, data_end, wait_begin, wait_end, vptr_panic)) {
|
||||
LOG << "failed, essential symbols are missing!" << endl;
|
||||
simulator.terminate(1);
|
||||
} else {
|
||||
LOG << "successfully retrieved ELF's addresses." << endl;
|
||||
}
|
||||
|
||||
//STEP 1
|
||||
if (establishState(entry)) {
|
||||
LOG << "STEP 1 (establish state) finished." << endl;
|
||||
} else {
|
||||
LOG << "STEP 1 (establish state) failed!" << endl;
|
||||
}
|
||||
|
||||
//STEP 2
|
||||
if (performTrace(entry, data_start, data_end, wait_end)) {
|
||||
LOG << "STEP 2 (perform trace) finished." << endl;
|
||||
} else {
|
||||
LOG << "STEP 2 (perform trace) failed!" << endl;
|
||||
}
|
||||
|
||||
#else // !PREREQUISITES i.e. STEP 3 "the actual experiment"
|
||||
faultInjection();
|
||||
|
||||
#endif
|
||||
|
||||
// Explicitly terminate, or the simulator will continue to run.
|
||||
simulator.terminate();
|
||||
}
|
||||
|
||||
@@ -4,10 +4,39 @@
|
||||
#include "efw/ExperimentFlow.hpp"
|
||||
#include "efw/JobClient.hpp"
|
||||
|
||||
#include "util/Logger.hpp"
|
||||
#include "util/ElfReader.hpp"
|
||||
|
||||
#include "sal/Listener.hpp"
|
||||
#include "sal/SALConfig.hpp"
|
||||
|
||||
class WeatherMonitorExperiment : public fail::ExperimentFlow {
|
||||
fail::JobClient m_jc;
|
||||
std::string m_variant, m_benchmark;
|
||||
static const std::string dir_images;
|
||||
static const std::string dir_prerequisites;
|
||||
fail::Logger LOG;
|
||||
fail::BPSingleListener bp;
|
||||
|
||||
std::string filename_elf(const std::string& variant, const std::string& benchmark);
|
||||
std::string filename_state(const std::string& variant, const std::string& benchmark);
|
||||
std::string filename_trace(const std::string& variant, const std::string& benchmark);
|
||||
std::string filename_traceinfo(const std::string& variant, const std::string& benchmark);
|
||||
bool writeTraceInfo(unsigned numinstr_tracing, unsigned numinstr_after);
|
||||
bool readTraceInfo(unsigned& numinstr_tracing, unsigned& numinstr_after);
|
||||
bool readElfSymbols(fail::guest_address_t& entry, fail::guest_address_t& text_start,
|
||||
fail::guest_address_t& text_end, fail::guest_address_t& data_start,
|
||||
fail::guest_address_t& data_end, fail::guest_address_t& wait_begin,
|
||||
fail::guest_address_t& wait_end, fail::guest_address_t& vptr_panic);
|
||||
bool establishState(fail::guest_address_t& entry);
|
||||
bool performTrace(fail::guest_address_t& entry, fail::guest_address_t& data_start,
|
||||
fail::guest_address_t& data_end, fail::guest_address_t& wait_end);
|
||||
bool faultInjection();
|
||||
|
||||
public:
|
||||
WeatherMonitorExperiment() : LOG("Weathermonitor", false) {}
|
||||
bool run();
|
||||
void parseOptions(void);
|
||||
};
|
||||
|
||||
#endif // __WEATHERMONITOR_EXPERIMENT_HPP__
|
||||
|
||||
@@ -1,127 +1,9 @@
|
||||
#ifndef __WEATHERMONITOR_EXPERIMENT_INFO_HPP__
|
||||
#define __WEATHERMONITOR_EXPERIMENT_INFO_HPP__
|
||||
#pragma once
|
||||
|
||||
// autogenerated, don't edit!
|
||||
#define DIR_IMAGES "oostubs"
|
||||
#define DIR_PREREQUISITES "prerequisites"
|
||||
#define PREREQUISITES 0 //1 == STEP1/2
|
||||
|
||||
// 0 = vanilla, 1 = guarded, 2 = plausibility
|
||||
#define WEATHERMONITOR_VARIANT 0
|
||||
#define WEATHER_NUMITER_TRACING 4 //same for all variants
|
||||
#define WEATHER_NUMITER_AFTER 2 //same for all variants
|
||||
|
||||
#if WEATHERMONITOR_VARIANT == 0 // without vptr guards
|
||||
|
||||
// suffix for simulator state, trace file
|
||||
#define WEATHER_SUFFIX ".vanilla"
|
||||
// main() address:
|
||||
// nm -C vanilla.elf|fgrep main
|
||||
#define WEATHER_FUNC_MAIN 0x00100d70
|
||||
// wait_begin address
|
||||
#define WEATHER_FUNC_WAIT_BEGIN 0x00100d68
|
||||
// wait_end address
|
||||
#define WEATHER_FUNC_WAIT_END 0x00100d6c
|
||||
// vptr_panic address (only exists in guarded variant)
|
||||
#define WEATHER_FUNC_VPTR_PANIC 0x99999999
|
||||
// number of main loop iterations to trace
|
||||
// (determines trace length and therefore fault-space width)
|
||||
#define WEATHER_NUMITER_TRACING 4
|
||||
// number of instructions needed for these iterations in golden run (taken from
|
||||
// experiment step #2)
|
||||
#define WEATHER_NUMINSTR_TRACING 20599
|
||||
// number of additional loop iterations for FI experiments (to see whether
|
||||
// everything continues working fine)
|
||||
#define WEATHER_NUMITER_AFTER 2
|
||||
// number of instructions needed for these iterations in golden run (taken from
|
||||
// experiment step #2)
|
||||
#define WEATHER_NUMINSTR_AFTER 10272
|
||||
// data/BSS begin:
|
||||
// nm -C vanilla.elf|fgrep ___DATA_START__
|
||||
#define WEATHER_DATA_START 0x00101558
|
||||
// data/BSS end:
|
||||
// nm -C vanilla.elf|fgrep ___BSS_END__
|
||||
#define WEATHER_DATA_END 0x00102e48
|
||||
// text begin:
|
||||
// nm -C vanilla.elf|fgrep ___TEXT_START__
|
||||
#define WEATHER_TEXT_START 0x00100000
|
||||
// text end:
|
||||
// nm -C vanilla.elf|fgrep ___TEXT_END__
|
||||
#define WEATHER_TEXT_END 0x0010139f
|
||||
|
||||
#elif WEATHERMONITOR_VARIANT == 1 // with guards
|
||||
|
||||
// suffix for simulator state, trace file
|
||||
#define WEATHER_SUFFIX ".guarded"
|
||||
// main() address:
|
||||
// nm -C guarded.elf|fgrep main
|
||||
#define WEATHER_FUNC_MAIN 0x00100dac
|
||||
// wait_begin address
|
||||
#define WEATHER_FUNC_WAIT_BEGIN 0x00100da4
|
||||
// wait_end address
|
||||
#define WEATHER_FUNC_WAIT_END 0x00100da8
|
||||
// vptr_panic address (only exists in guarded variant)
|
||||
#define WEATHER_FUNC_VPTR_PANIC 0x0010104c
|
||||
// number of main loop iterations to trace
|
||||
// (determines trace length and therefore fault-space width)
|
||||
#define WEATHER_NUMITER_TRACING 4
|
||||
// number of instructions needed for these iterations in golden run (taken from
|
||||
// experiment step #2)
|
||||
#define WEATHER_NUMINSTR_TRACING 20599
|
||||
// number of additional loop iterations for FI experiments (to see whether
|
||||
// everything continues working fine)
|
||||
#define WEATHER_NUMITER_AFTER 2
|
||||
// number of instructions needed for these iterations in golden run (taken from
|
||||
// experiment step #2)
|
||||
#define WEATHER_NUMINSTR_AFTER 10272
|
||||
// data/BSS begin:
|
||||
// nm -C guarded.elf|fgrep ___DATA_START__
|
||||
#define WEATHER_DATA_START 0x00101878
|
||||
// data/BSS end:
|
||||
// nm -C guarded.elf|fgrep ___BSS_END__
|
||||
#define WEATHER_DATA_END 0x00103198
|
||||
// text begin:
|
||||
// nm -C guarded.elf|fgrep ___TEXT_START__
|
||||
#define WEATHER_TEXT_START 0x00100000
|
||||
// text end:
|
||||
// nm -C guarded.elf|fgrep ___TEXT_END__
|
||||
#define WEATHER_TEXT_END 0x001016af
|
||||
|
||||
#elif WEATHERMONITOR_VARIANT == 2 // with guards + plausibility check
|
||||
|
||||
// suffix for simulator state, trace file
|
||||
#define WEATHER_SUFFIX ".plausibility"
|
||||
// main() address:
|
||||
// nm -C plausibility.elf|fgrep main
|
||||
#define WEATHER_FUNC_MAIN 0x00100dbc
|
||||
// wait_begin address
|
||||
#define WEATHER_FUNC_WAIT_BEGIN 0x00100db4
|
||||
// wait_end address
|
||||
#define WEATHER_FUNC_WAIT_END 0x00100db8
|
||||
// vptr_panic address (only exists in guarded variant)
|
||||
#define WEATHER_FUNC_VPTR_PANIC 0x001010f0
|
||||
// number of main loop iterations to trace
|
||||
// (determines trace length and therefore fault-space width)
|
||||
#define WEATHER_NUMITER_TRACING 4
|
||||
// number of instructions needed for these iterations in golden run (taken from
|
||||
// experiment step #2)
|
||||
#define WEATHER_NUMINSTR_TRACING 20599
|
||||
// number of additional loop iterations for FI experiments (to see whether
|
||||
// everything continues working fine)
|
||||
#define WEATHER_NUMITER_AFTER 2
|
||||
// number of instructions needed for these iterations in golden run (taken from
|
||||
// experiment step #2)
|
||||
#define WEATHER_NUMINSTR_AFTER 10272
|
||||
// data/BSS begin:
|
||||
// nm -C plausibility.elf|fgrep ___DATA_START__
|
||||
#define WEATHER_DATA_START 0x00101998
|
||||
// data/BSS end:
|
||||
// nm -C plausibility.elf|fgrep ___BSS_END__
|
||||
#define WEATHER_DATA_END 0x001032b8
|
||||
// text begin:
|
||||
// nm -C plausibility.elf|fgrep ___TEXT_START__
|
||||
#define WEATHER_TEXT_START 0x00100000
|
||||
// text end:
|
||||
// nm -C plausibility.elf|fgrep ___TEXT_END__
|
||||
#define WEATHER_TEXT_END 0x001017cb
|
||||
|
||||
#else
|
||||
#error Unknown WEATHERMONITOR_VARIANT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
TARGET=experimentInfo.hpp
|
||||
|
||||
[ ! -e "$1" -o ! -e "$2" -o ! -e "$3" ] && echo "usage: $0 vanilla.elf guarded.elf plausibility.elf" && exit 1
|
||||
|
||||
function addrof() { nm -C $1 | (fgrep "$2" || echo 99999999) | awk '{print $1}'; }
|
||||
|
||||
cat >$TARGET <<EOF
|
||||
#ifndef __WEATHERMONITOR_EXPERIMENT_INFO_HPP__
|
||||
#define __WEATHERMONITOR_EXPERIMENT_INFO_HPP__
|
||||
|
||||
// autogenerated, don't edit!
|
||||
|
||||
// 0 = vanilla, 1 = guarded, 2 = plausibility
|
||||
#define WEATHERMONITOR_VARIANT 0
|
||||
|
||||
#if WEATHERMONITOR_VARIANT == 0 // without vptr guards
|
||||
|
||||
EOF
|
||||
|
||||
function alldefs() {
|
||||
cat <<EOF
|
||||
// suffix for simulator state, trace file
|
||||
#define WEATHER_SUFFIX ".`basename $1|sed s/\\\\..*$//`"
|
||||
// main() address:
|
||||
// nm -C $(basename $1)|fgrep main
|
||||
#define WEATHER_FUNC_MAIN 0x`addrof $1 main`
|
||||
// wait_begin address
|
||||
#define WEATHER_FUNC_WAIT_BEGIN 0x`addrof $1 wait_begin`
|
||||
// wait_end address
|
||||
#define WEATHER_FUNC_WAIT_END 0x`addrof $1 wait_end`
|
||||
// vptr_panic address (only exists in guarded variant)
|
||||
#define WEATHER_FUNC_VPTR_PANIC 0x`addrof $1 vptr_panic`
|
||||
// number of main loop iterations to trace
|
||||
// (determines trace length and therefore fault-space width)
|
||||
#define WEATHER_NUMITER_TRACING 4
|
||||
// number of instructions needed for these iterations in golden run (taken from
|
||||
// experiment step #2)
|
||||
#define WEATHER_NUMINSTR_TRACING 20599
|
||||
// number of additional loop iterations for FI experiments (to see whether
|
||||
// everything continues working fine)
|
||||
#define WEATHER_NUMITER_AFTER 2
|
||||
// number of instructions needed for these iterations in golden run (taken from
|
||||
// experiment step #2)
|
||||
#define WEATHER_NUMINSTR_AFTER 10272
|
||||
// data/BSS begin:
|
||||
// nm -C $(basename $1)|fgrep ___DATA_START__
|
||||
#define WEATHER_DATA_START 0x`addrof $1 ___DATA_START__`
|
||||
// data/BSS end:
|
||||
// nm -C $(basename $1)|fgrep ___BSS_END__
|
||||
#define WEATHER_DATA_END 0x`addrof $1 ___BSS_END__`
|
||||
// text begin:
|
||||
// nm -C $(basename $1)|fgrep ___TEXT_START__
|
||||
#define WEATHER_TEXT_START 0x`addrof $1 ___TEXT_START__`
|
||||
// text end:
|
||||
// nm -C $(basename $1)|fgrep ___TEXT_END__
|
||||
#define WEATHER_TEXT_END 0x`addrof $1 ___TEXT_END__`
|
||||
EOF
|
||||
}
|
||||
|
||||
alldefs $1 >>$TARGET
|
||||
cat >>$TARGET <<EOF
|
||||
|
||||
#elif WEATHERMONITOR_VARIANT == 1 // with guards
|
||||
|
||||
EOF
|
||||
alldefs $2 >>$TARGET
|
||||
cat >>$TARGET <<EOF
|
||||
|
||||
#elif WEATHERMONITOR_VARIANT == 2 // with guards + plausibility check
|
||||
|
||||
EOF
|
||||
alldefs $3 >>$TARGET
|
||||
cat >>$TARGET <<EOF
|
||||
|
||||
#else
|
||||
#error Unknown WEATHERMONITOR_VARIANT
|
||||
#endif
|
||||
|
||||
#endif
|
||||
EOF
|
||||
@@ -0,0 +1,11 @@
|
||||
set(PLUGIN_NAME checkpoint)
|
||||
|
||||
set(MY_PLUGIN_SRCS
|
||||
Checkpoint.cc
|
||||
Checkpoint.hpp
|
||||
sha1.c
|
||||
)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
## Build library
|
||||
add_library(fail-${PLUGIN_NAME} ${MY_PLUGIN_SRCS})
|
||||
@@ -0,0 +1,230 @@
|
||||
#include "Checkpoint.hpp"
|
||||
#include "sal/Listener.hpp"
|
||||
#include "sal/Memory.hpp"
|
||||
#include "sha1.h"
|
||||
#include <cstring>
|
||||
#include "sal/bochs/BochsCPU.hpp"
|
||||
#include "sal/SALConfig.hpp"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace fail;
|
||||
|
||||
bool Checkpoint::run()
|
||||
{
|
||||
assert(!m_checking && "FATAL: Checkpoint plugin must not be added to simulation in checking mode");
|
||||
|
||||
// log information
|
||||
m_log << "Checkpoint Logger started." << std::endl;
|
||||
m_log << "Triggering on: " << m_symbol << std::endl;
|
||||
m_log << "Writing output to: " << m_file << std::endl;
|
||||
|
||||
/*
|
||||
std::vector<address_range>::const_iterator it = m_check_ranges.begin();
|
||||
for( ; it != m_check_ranges.end(); ++it) {
|
||||
m_log << "Checksumming: " <<
|
||||
<< ((it->first.second) ? "*" : "")
|
||||
<< "0x" << std::hex << it->first.first
|
||||
<< " - " <<
|
||||
<< (it->second.second) ? "*" : ""
|
||||
<< "0x" << std::hex << it->second.first
|
||||
<< std::endl;
|
||||
}
|
||||
*/
|
||||
|
||||
if (!m_ostream.is_open()) {
|
||||
m_log << "No output file." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// listen for memory writes and save checkpoints
|
||||
MemWriteListener ev_mem(m_symbol.getAddress());
|
||||
while (true) {
|
||||
simulator.addListenerAndResume(&ev_mem);
|
||||
|
||||
save_checkpoint(ev_mem.getTriggerInstructionPointer());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
address_t Checkpoint::resolve_address(const indirectable_address_t &addr) {
|
||||
if(addr.second) {
|
||||
const address_t paddr = addr.first;
|
||||
address_t value = 0;
|
||||
|
||||
MemoryManager& mm = simulator.getMemoryManager();
|
||||
|
||||
if(mm.isMapped(paddr) && mm.isMapped(paddr+1) && mm.isMapped(paddr+2) && mm.isMapped(paddr+3)) {
|
||||
simulator.getMemoryManager().getBytes(paddr, 4, &value);
|
||||
}
|
||||
|
||||
// HACK/WORKAROUND for dOSEK, which uses bit 31 for parity!
|
||||
// This fixes checkpoint ranges for dOSEK, but breaks other systems *if*
|
||||
// addresses with bit 31 set are used as the limit for checkpoint regions
|
||||
return value & ~(1<<31);
|
||||
} else {
|
||||
return addr.first;
|
||||
}
|
||||
}
|
||||
|
||||
void Checkpoint::checksum(uint8_t (&Message_Digest)[20])
|
||||
{
|
||||
SHA1Context sha;
|
||||
int err;
|
||||
|
||||
// prepare SHA1 hash
|
||||
err = SHA1Reset(&sha);
|
||||
assert(err == 0);
|
||||
|
||||
MemoryManager& mm = simulator.getMemoryManager();
|
||||
|
||||
// disable paging on x86
|
||||
#ifdef BUILD_X86
|
||||
const Register *reg_cr0 = simulator.getCPU(0).getRegister(RID_CR0);
|
||||
uint32_t cr0 = simulator.getCPU(0).getRegisterContent(reg_cr0);
|
||||
simulator.getCPU(0).setRegisterContent(reg_cr0, cr0 & ~(1<<31));
|
||||
#endif
|
||||
|
||||
// iterate memory regions
|
||||
std::vector<address_range>::const_iterator it = m_check_ranges.begin();
|
||||
for( ; it != m_check_ranges.end(); ++it) {
|
||||
fail::address_t start = resolve_address(it->first);
|
||||
fail::address_t end = resolve_address(it->second);
|
||||
|
||||
if((start == 0) || (end == 0)) {
|
||||
m_log << std::hex << "invalid checksum range pointer" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
//m_log << std::hex << "checksumming 0x" << start << " - 0x" << end << std::endl;
|
||||
|
||||
for(fail::address_t addr = start; addr < end; addr++) {
|
||||
if(mm.isMapped(addr)) {
|
||||
// read byte
|
||||
uint8_t data = mm.getByte(addr);
|
||||
// add to hash
|
||||
err = SHA1Input(&sha, &data, 1);
|
||||
} else {
|
||||
err = SHA1Input(&sha, (uint8_t*) &addr, 4);
|
||||
}
|
||||
|
||||
assert(err == 0);
|
||||
}
|
||||
}
|
||||
|
||||
// restore paging on x86
|
||||
#ifdef BUILD_X86
|
||||
simulator.getCPU(0).setRegisterContent(reg_cr0, cr0);
|
||||
#endif
|
||||
|
||||
// complete hash
|
||||
err = SHA1Result(&sha, Message_Digest);
|
||||
assert(err == 0);
|
||||
}
|
||||
|
||||
void Checkpoint::checkpoint(const fail::ElfSymbol symbol,
|
||||
uint32_t &value,
|
||||
fail::simtime_t &simtime,
|
||||
std::string &digest_str)
|
||||
{
|
||||
// increment checkpoint count
|
||||
m_count++;
|
||||
|
||||
// timestamp
|
||||
simtime = simulator.getTimerTicks();
|
||||
|
||||
// written value
|
||||
address_t addr = symbol.getAddress();
|
||||
MemoryManager& mm = simulator.getMemoryManager();
|
||||
if(mm.isMapped(addr) && mm.isMapped(addr+1) && mm.isMapped(addr+2) && mm.isMapped(addr+3)) {
|
||||
mm.getBytes(symbol.getAddress(), symbol.getSize(), &value);
|
||||
} else {
|
||||
value = 0xDEADBEEF; // TODO: invalid value?
|
||||
}
|
||||
|
||||
// checksum
|
||||
uint8_t digest[20];
|
||||
checksum(digest);
|
||||
|
||||
// checksum to string
|
||||
std::stringstream s;
|
||||
s.fill('0');
|
||||
for ( size_t i = 0 ; i < 20 ; ++i )
|
||||
s << std::setw(2) << std::hex <<(unsigned short)digest[i];
|
||||
digest_str = s.str();
|
||||
}
|
||||
|
||||
void Checkpoint::save_checkpoint(fail::address_t ip)
|
||||
{
|
||||
uint32_t value;
|
||||
fail::simtime_t simtime;
|
||||
std::string digest;
|
||||
|
||||
// get checkpoint info
|
||||
checkpoint(m_symbol, value, simtime, digest);
|
||||
|
||||
// log checkpoint
|
||||
m_log << std::dec << "Checkpoint " << m_count << " @ " << simtime << std::endl;
|
||||
|
||||
// write checkpoint
|
||||
if (m_ostream.is_open()) {
|
||||
m_ostream << std::hex << ip << "\t" << std::dec << simtime << "\t" << value << "\t" << digest << std::endl;
|
||||
} else {
|
||||
m_log << "Output error" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Checkpoint::check_result Checkpoint::check(const fail::ElfSymbol symbol, fail::address_t ip)
|
||||
{
|
||||
uint32_t value;
|
||||
fail::simtime_t simtime;
|
||||
std::string digest;
|
||||
|
||||
address_t golden_ip;
|
||||
uint32_t golden_timestamp;
|
||||
uint32_t golden_value;
|
||||
char golden_digest_hex[41];
|
||||
|
||||
assert(m_checking && "FATAL: Checkpoint plugin cannot check in tracing mode");
|
||||
|
||||
// get checkpoint info
|
||||
checkpoint(symbol, value, simtime, digest);
|
||||
|
||||
// check with log
|
||||
if (!m_istream.is_open()) {
|
||||
m_log << "Input file not open!" << std::endl;
|
||||
return INVALID;
|
||||
}
|
||||
if (m_istream.eof()) {
|
||||
m_log << "Checkpoint after last golden checkpoint!" << std::endl;
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
// read golden values
|
||||
m_istream >> std::hex >> golden_ip;
|
||||
m_istream >> std::dec >> golden_timestamp;
|
||||
m_istream >> std::dec >> golden_value;
|
||||
m_istream.width(41);
|
||||
m_istream >> golden_digest_hex;
|
||||
std::string golden_digest = golden_digest_hex;
|
||||
|
||||
|
||||
//bool same_timestamp = simtime == golden_timestamp);
|
||||
bool same_ip = ip == golden_ip;
|
||||
bool same_value = value == golden_value;
|
||||
bool same_digest = digest == golden_digest;
|
||||
|
||||
if (!same_ip || !same_value || !same_digest) {
|
||||
// log
|
||||
m_log << "GOLDEN:" << std::hex << golden_ip << "\t" << std::dec << golden_timestamp << "\t" << golden_value << "\t" << golden_digest << std::endl;
|
||||
m_log << "TEST: " << std::hex << ip << "\t" << std::dec << simtime << "\t" << value << "\t" << digest << std::endl;
|
||||
}
|
||||
|
||||
|
||||
if(!same_value) return DIFFERENT_VALUE;
|
||||
if(!same_ip) return DIFFERENT_IP;
|
||||
if(!same_digest) return DIFFERENT_DIGEST;
|
||||
|
||||
return IDENTICAL;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
#ifndef __Checkpoint_HPP__
|
||||
#define __Checkpoint_HPP__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <unistd.h>
|
||||
#include "efw/ExperimentFlow.hpp"
|
||||
#include "config/FailConfig.hpp"
|
||||
#include "util/Logger.hpp"
|
||||
#include <fstream>
|
||||
#include "util/ElfReader.hpp"
|
||||
|
||||
/**
|
||||
* @class Checkpoint
|
||||
* @brief Listens to a memory location and outputs instruction pointer, written value,
|
||||
* timestamp and SHA1 hash of memory regions to file on each write access from SUT
|
||||
*/
|
||||
class Checkpoint : public fail::ExperimentFlow
|
||||
{
|
||||
public:
|
||||
typedef std::pair<fail::address_t,bool> indirectable_address_t; //!< fixed address or pointer to address
|
||||
typedef std::pair<indirectable_address_t,indirectable_address_t> address_range; //!< contiguous memory region
|
||||
typedef std::vector<address_range> range_vector; //!< vector of memory regions
|
||||
|
||||
enum check_result {
|
||||
IDENTICAL,
|
||||
DIFFERENT_IP,
|
||||
DIFFERENT_VALUE,
|
||||
DIFFERENT_DIGEST,
|
||||
INVALID
|
||||
};
|
||||
|
||||
private:
|
||||
const fail::ElfSymbol m_symbol; //!< target memory symbol triggering checkpoints
|
||||
const range_vector m_check_ranges; //!< address ranges to checksum
|
||||
const bool m_checking; //!< checking mode (when false: tracing mode)
|
||||
std::string m_file; //!< the input/output filename
|
||||
fail::Logger m_log; //!< debug output
|
||||
std::ofstream m_ostream; //!< outputfile stream
|
||||
std::ifstream m_istream; //!< inputfile stream
|
||||
unsigned m_count;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct Checkpoint Logger in tracing (output) mode.
|
||||
*
|
||||
* @param symbol The global memory address the plugin listens to
|
||||
* @param check_ranges Address ranges which are included in the saved checksum
|
||||
* @param outputfile The path to the file to write the checkpoints
|
||||
*/
|
||||
Checkpoint(const fail::ElfSymbol & symbol,
|
||||
const std::vector<address_range> check_ranges,
|
||||
const std::string& outputfile) :
|
||||
m_symbol(symbol), m_check_ranges(check_ranges), m_checking(false),
|
||||
m_file(outputfile) , m_log("CPLogger", false), m_count(0)
|
||||
{
|
||||
m_ostream.open(m_file.c_str() );
|
||||
if (!m_ostream.is_open()) {
|
||||
m_log << "Could not open " << m_file.c_str() << " for writing." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct Checkpoint Logger in checking (input) mode.
|
||||
*
|
||||
* @param symbol The global memory address the plugin listens to
|
||||
* @param check_ranges Address ranges which are compared to the saved checksum
|
||||
* @param inputfile The path to the file to read in checkpoints
|
||||
*/
|
||||
Checkpoint(const std::vector<address_range> check_ranges,
|
||||
const std::string& inputfile) :
|
||||
m_check_ranges(check_ranges), m_checking(true), m_file(inputfile),
|
||||
m_log("CPLogger", false), m_count(0)
|
||||
{
|
||||
m_istream.open(m_file.c_str() );
|
||||
if (!m_istream.is_open()) {
|
||||
m_log << "Could not open " << m_file.c_str() << " for reading." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//! How many checkpoints have been triggered so far
|
||||
unsigned getCount() const {
|
||||
return m_count;
|
||||
}
|
||||
|
||||
//! Start plugin control flow for tracing mode. Do not call in checking mode!
|
||||
bool run();
|
||||
|
||||
/**
|
||||
* Perform a check against saved checkpoints. Call this method in experiment when
|
||||
* a MemWriteBreakpoint on symbol triggers.
|
||||
*
|
||||
* @param symbol (memory) symbol which triggered checkpoint
|
||||
* @param ip instruction pointer which triggered checkpoint
|
||||
* @return check result
|
||||
*/
|
||||
check_result check(const fail::ElfSymbol symbol, fail::address_t ip);
|
||||
|
||||
private:
|
||||
//! calulate checksum over memory regions
|
||||
void checksum(uint8_t (&Message_Digest)[20]);
|
||||
|
||||
//! extract checkpoint information from simulation
|
||||
void checkpoint(const fail::ElfSymbol symbol,
|
||||
uint32_t &value,
|
||||
fail::simtime_t &simtime,
|
||||
std::string &digest_str);
|
||||
|
||||
//! save checkpoint to file
|
||||
void save_checkpoint(fail::address_t ip);
|
||||
|
||||
//! get value of indirectable_address_t
|
||||
fail::address_t resolve_address(const indirectable_address_t &addr);
|
||||
};
|
||||
|
||||
#endif // __Checkpoint_HPP__
|
||||
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* sha1.c
|
||||
*
|
||||
* Copyright (C) The Internet Society (2001). All Rights Reserved.
|
||||
* This file is taken from RFC3174.
|
||||
*
|
||||
* Description:
|
||||
* This file implements the Secure Hashing Algorithm 1 as
|
||||
* defined in FIPS PUB 180-1 published April 17, 1995.
|
||||
*
|
||||
* The SHA-1, produces a 160-bit message digest for a given
|
||||
* data stream. It should take about 2**n steps to find a
|
||||
* message with the same digest as a given message and
|
||||
* 2**(n/2) to find any two messages with the same digest,
|
||||
* when n is the digest size in bits. Therefore, this
|
||||
* algorithm can serve as a means of providing a
|
||||
* "fingerprint" for a message.
|
||||
*
|
||||
* Portability Issues:
|
||||
* SHA-1 is defined in terms of 32-bit "words". This code
|
||||
* uses <stdint.h> (included via "sha1.h" to define 32 and 8
|
||||
* bit unsigned integer types. If your C compiler does not
|
||||
* support 32 bit unsigned integers, this code is not
|
||||
* appropriate.
|
||||
*
|
||||
* Caveats:
|
||||
* SHA-1 is designed to work with messages less than 2^64 bits
|
||||
* long. Although SHA-1 allows a message digest to be generated
|
||||
* for messages of any number of bits less than 2^64, this
|
||||
* implementation only works with messages with a length that is
|
||||
* a multiple of the size of an 8-bit character.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
/*
|
||||
* Define the SHA1 circular left shift macro
|
||||
*/
|
||||
#define SHA1CircularShift(bits,word) \
|
||||
(((word) << (bits)) | ((word) >> (32-(bits))))
|
||||
|
||||
/* Local Function Prototyptes */
|
||||
void SHA1PadMessage(SHA1Context *);
|
||||
void SHA1ProcessMessageBlock(SHA1Context *);
|
||||
|
||||
/*
|
||||
* SHA1Reset
|
||||
*
|
||||
* Description:
|
||||
* This function will initialize the SHA1Context in preparation
|
||||
* for computing a new SHA1 message digest.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to reset.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int SHA1Reset(SHA1Context *context)
|
||||
{
|
||||
if (!context)
|
||||
{
|
||||
return shaNull;
|
||||
}
|
||||
|
||||
context->Length_Low = 0;
|
||||
context->Length_High = 0;
|
||||
context->Message_Block_Index = 0;
|
||||
|
||||
context->Intermediate_Hash[0] = 0x67452301;
|
||||
context->Intermediate_Hash[1] = 0xEFCDAB89;
|
||||
context->Intermediate_Hash[2] = 0x98BADCFE;
|
||||
context->Intermediate_Hash[3] = 0x10325476;
|
||||
context->Intermediate_Hash[4] = 0xC3D2E1F0;
|
||||
|
||||
context->Computed = 0;
|
||||
context->Corrupted = 0;
|
||||
|
||||
return shaSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1Result
|
||||
*
|
||||
* Description:
|
||||
* This function will return the 160-bit message digest into the
|
||||
* Message_Digest array provided by the caller.
|
||||
* NOTE: The first octet of hash is stored in the 0th element,
|
||||
* the last octet of hash in the 19th element.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to use to calculate the SHA-1 hash.
|
||||
* Message_Digest: [out]
|
||||
* Where the digest is returned.
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int SHA1Result( SHA1Context *context,
|
||||
uint8_t Message_Digest[SHA1HashSize])
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!context || !Message_Digest)
|
||||
{
|
||||
return shaNull;
|
||||
}
|
||||
|
||||
if (context->Corrupted)
|
||||
{
|
||||
return context->Corrupted;
|
||||
}
|
||||
|
||||
if (!context->Computed)
|
||||
{
|
||||
SHA1PadMessage(context);
|
||||
for(i=0; i<64; ++i)
|
||||
{
|
||||
/* message may be sensitive, clear it out */
|
||||
context->Message_Block[i] = 0;
|
||||
}
|
||||
context->Length_Low = 0; /* and clear length */
|
||||
context->Length_High = 0;
|
||||
context->Computed = 1;
|
||||
|
||||
}
|
||||
|
||||
for(i = 0; i < SHA1HashSize; ++i)
|
||||
{
|
||||
Message_Digest[i] = context->Intermediate_Hash[i>>2]
|
||||
>> 8 * ( 3 - ( i & 0x03 ) );
|
||||
}
|
||||
|
||||
return shaSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1Input
|
||||
*
|
||||
* Description:
|
||||
* This function accepts an array of octets as the next portion
|
||||
* of the message.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The SHA context to update
|
||||
* message_array: [in]
|
||||
* An array of characters representing the next portion of
|
||||
* the message.
|
||||
* length: [in]
|
||||
* The length of the message in message_array
|
||||
*
|
||||
* Returns:
|
||||
* sha Error Code.
|
||||
*
|
||||
*/
|
||||
int SHA1Input( SHA1Context *context,
|
||||
const uint8_t *message_array,
|
||||
unsigned length)
|
||||
{
|
||||
if (!length)
|
||||
{
|
||||
return shaSuccess;
|
||||
}
|
||||
|
||||
if (!context || !message_array)
|
||||
{
|
||||
return shaNull;
|
||||
}
|
||||
|
||||
if (context->Computed)
|
||||
{
|
||||
context->Corrupted = shaStateError;
|
||||
|
||||
return shaStateError;
|
||||
}
|
||||
|
||||
if (context->Corrupted)
|
||||
{
|
||||
return context->Corrupted;
|
||||
}
|
||||
while(length-- && !context->Corrupted)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] =
|
||||
(*message_array & 0xFF);
|
||||
|
||||
context->Length_Low += 8;
|
||||
if (context->Length_Low == 0)
|
||||
{
|
||||
context->Length_High++;
|
||||
if (context->Length_High == 0)
|
||||
{
|
||||
/* Message is too long */
|
||||
context->Corrupted = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->Message_Block_Index == 64)
|
||||
{
|
||||
SHA1ProcessMessageBlock(context);
|
||||
}
|
||||
|
||||
message_array++;
|
||||
}
|
||||
|
||||
return shaSuccess;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1ProcessMessageBlock
|
||||
*
|
||||
* Description:
|
||||
* This function will process the next 512 bits of the message
|
||||
* stored in the Message_Block array.
|
||||
*
|
||||
* Parameters:
|
||||
* None.
|
||||
*
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
* Comments:
|
||||
|
||||
* Many of the variable names in this code, especially the
|
||||
* single character names, were used because those were the
|
||||
* names used in the publication.
|
||||
*
|
||||
*
|
||||
*/
|
||||
void SHA1ProcessMessageBlock(SHA1Context *context)
|
||||
{
|
||||
const uint32_t K[] = { /* Constants defined in SHA-1 */
|
||||
0x5A827999,
|
||||
0x6ED9EBA1,
|
||||
0x8F1BBCDC,
|
||||
0xCA62C1D6
|
||||
};
|
||||
int t; /* Loop counter */
|
||||
uint32_t temp; /* Temporary word value */
|
||||
uint32_t W[80]; /* Word sequence */
|
||||
uint32_t A, B, C, D, E; /* Word buffers */
|
||||
|
||||
/*
|
||||
* Initialize the first 16 words in the array W
|
||||
*/
|
||||
for(t = 0; t < 16; t++)
|
||||
{
|
||||
W[t] = context->Message_Block[t * 4] << 24;
|
||||
W[t] |= context->Message_Block[t * 4 + 1] << 16;
|
||||
W[t] |= context->Message_Block[t * 4 + 2] << 8;
|
||||
W[t] |= context->Message_Block[t * 4 + 3];
|
||||
}
|
||||
|
||||
for(t = 16; t < 80; t++)
|
||||
{
|
||||
W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
|
||||
}
|
||||
|
||||
A = context->Intermediate_Hash[0];
|
||||
B = context->Intermediate_Hash[1];
|
||||
C = context->Intermediate_Hash[2];
|
||||
D = context->Intermediate_Hash[3];
|
||||
E = context->Intermediate_Hash[4];
|
||||
|
||||
for(t = 0; t < 20; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) +
|
||||
((B & C) | ((~B) & D)) + E + W[t] + K[0];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 20; t < 40; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 40; t < 60; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) +
|
||||
((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
for(t = 60; t < 80; t++)
|
||||
{
|
||||
temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
|
||||
E = D;
|
||||
D = C;
|
||||
C = SHA1CircularShift(30,B);
|
||||
B = A;
|
||||
A = temp;
|
||||
}
|
||||
|
||||
context->Intermediate_Hash[0] += A;
|
||||
context->Intermediate_Hash[1] += B;
|
||||
context->Intermediate_Hash[2] += C;
|
||||
context->Intermediate_Hash[3] += D;
|
||||
context->Intermediate_Hash[4] += E;
|
||||
|
||||
context->Message_Block_Index = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* SHA1PadMessage
|
||||
*
|
||||
|
||||
* Description:
|
||||
* According to the standard, the message must be padded to an even
|
||||
* 512 bits. The first padding bit must be a '1'. The last 64
|
||||
* bits represent the length of the original message. All bits in
|
||||
* between should be 0. This function will pad the message
|
||||
* according to those rules by filling the Message_Block array
|
||||
* accordingly. It will also call the ProcessMessageBlock function
|
||||
* provided appropriately. When it returns, it can be assumed that
|
||||
* the message digest has been computed.
|
||||
*
|
||||
* Parameters:
|
||||
* context: [in/out]
|
||||
* The context to pad
|
||||
* ProcessMessageBlock: [in]
|
||||
* The appropriate SHA*ProcessMessageBlock function
|
||||
* Returns:
|
||||
* Nothing.
|
||||
*
|
||||
*/
|
||||
|
||||
void SHA1PadMessage(SHA1Context *context)
|
||||
{
|
||||
/*
|
||||
* Check to see if the current message block is too small to hold
|
||||
* the initial padding bits and length. If so, we will pad the
|
||||
* block, process it, and then continue padding into a second
|
||||
* block.
|
||||
*/
|
||||
if (context->Message_Block_Index > 55)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0x80;
|
||||
while(context->Message_Block_Index < 64)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
}
|
||||
|
||||
SHA1ProcessMessageBlock(context);
|
||||
|
||||
while(context->Message_Block_Index < 56)
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context->Message_Block[context->Message_Block_Index++] = 0x80;
|
||||
while(context->Message_Block_Index < 56)
|
||||
{
|
||||
|
||||
context->Message_Block[context->Message_Block_Index++] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the message length as the last 8 octets
|
||||
*/
|
||||
context->Message_Block[56] = context->Length_High >> 24;
|
||||
context->Message_Block[57] = context->Length_High >> 16;
|
||||
context->Message_Block[58] = context->Length_High >> 8;
|
||||
context->Message_Block[59] = context->Length_High;
|
||||
context->Message_Block[60] = context->Length_Low >> 24;
|
||||
context->Message_Block[61] = context->Length_Low >> 16;
|
||||
context->Message_Block[62] = context->Length_Low >> 8;
|
||||
context->Message_Block[63] = context->Length_Low;
|
||||
|
||||
SHA1ProcessMessageBlock(context);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* sha1.h
|
||||
*
|
||||
* Description:
|
||||
* This is the header file for code which implements the Secure
|
||||
* Hashing Algorithm 1 as defined in FIPS PUB 180-1 published
|
||||
* April 17, 1995.
|
||||
*
|
||||
* Many of the variable names in this code, especially the
|
||||
* single character names, were used because those were the names
|
||||
* used in the publication.
|
||||
*
|
||||
* Please read the file sha1.c for more information.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SHA1_H_
|
||||
#define _SHA1_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef _SHA_enum_
|
||||
#define _SHA_enum_
|
||||
enum
|
||||
{
|
||||
shaSuccess = 0,
|
||||
shaNull, /* Null pointer parameter */
|
||||
shaInputTooLong, /* input data too long */
|
||||
shaStateError /* called Input after Result */
|
||||
};
|
||||
#endif
|
||||
#define SHA1HashSize 20
|
||||
|
||||
/*
|
||||
* This structure will hold context information for the SHA-1
|
||||
* hashing operation
|
||||
*/
|
||||
typedef struct SHA1Context
|
||||
{
|
||||
uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
|
||||
|
||||
uint32_t Length_Low; /* Message length in bits */
|
||||
uint32_t Length_High; /* Message length in bits */
|
||||
|
||||
/* Index into message block array */
|
||||
int_least16_t Message_Block_Index;
|
||||
uint8_t Message_Block[64]; /* 512-bit message blocks */
|
||||
|
||||
int Computed; /* Is the digest computed? */
|
||||
int Corrupted; /* Is the message digest corrupted? */
|
||||
} SHA1Context;
|
||||
|
||||
/*
|
||||
* Function Prototypes
|
||||
*/
|
||||
|
||||
int SHA1Reset( SHA1Context *);
|
||||
int SHA1Input( SHA1Context *,
|
||||
const uint8_t *,
|
||||
unsigned int);
|
||||
int SHA1Result( SHA1Context *,
|
||||
uint8_t Message_Digest[SHA1HashSize]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -10,7 +10,7 @@ bool SerialOutputLogger::run()
|
||||
while (true) {
|
||||
simulator.addListener(&ev_ioport);
|
||||
simulator.resume();
|
||||
if (m_output.size() < m_limit) {
|
||||
if (m_limit == 0 || m_output.size() < m_limit) {
|
||||
m_output += ev_ioport.getData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
// database credentials
|
||||
$host = "localhost";
|
||||
$username = "";
|
||||
$password = "";
|
||||
$database = "";
|
||||
|
||||
// result-table name
|
||||
$result_table = "result";
|
||||
?>
|
||||
@@ -0,0 +1,64 @@
|
||||
VisualFail*
|
||||
===========
|
||||
|
||||
Guest-system setup
|
||||
------------------
|
||||
For analysis with VisualFail*, the guest-system ELF binary must be compiled with
|
||||
debugging information (gcc/g++/clang/clang++ compiler flag "-g"). Note that
|
||||
debugging information quality/accuracy usually decreases with higher
|
||||
optimization levels.
|
||||
|
||||
Database preparation
|
||||
--------------------
|
||||
1. import-trace -t yourtrace.tc -i MemoryImporter
|
||||
2. import-trace -t yourtrace.tc -i FullTraceImporter
|
||||
3. import-trace -t yourtrace.tc -i ElfImporter -e yourbinary.elf --objdump $(which objdump) --sources
|
||||
|
||||
Step 1 is the prerequisite to run the fault-injection campaign (you may use
|
||||
other importers as well, e.g., the RegisterImporter). Steps 2 and 3 are
|
||||
required for VisualFail* to work.
|
||||
|
||||
Setup
|
||||
-----
|
||||
Copy CONFIGURATION.php.dist to CONFIGURATION.php, edit it, and add your MySQL
|
||||
database credentials and the result-table name (usually starting with
|
||||
"result...", "echo SHOW TABLES | mysql yourdatabase" on the command line should
|
||||
give you the correct table name).
|
||||
|
||||
(In a later version of VisualFail*, we will probably add automatic loading of
|
||||
~/.my.cnf if available.)
|
||||
|
||||
Running and using VisualFail*
|
||||
-----------------------------
|
||||
./StartVF.sh requires PHP 5.4.0 or newer and uses its simple built-in web
|
||||
server. You can connect to it by using http://localhost:1234 in a web browser
|
||||
on the same machine. (If you need to connect from another machine, manually run
|
||||
"php -S 0.0.0.0:1234 -t .")
|
||||
|
||||
Alternatively, VisualFail* can be set up using a "real" web server with a recent
|
||||
PHP version (5.x should suffice).
|
||||
|
||||
Once the web server runs, you can use VisualFail*:
|
||||
|
||||
- Pick a coloring (currently, only "Right margin" really makes sense), a
|
||||
benchmark and a variant from the drop-down menus. Click "Analyze". Wait.
|
||||
|
||||
- Enable the experiment result types you want to highlight by clicking them in
|
||||
the top row.
|
||||
|
||||
- Scroll down the left column with the disassembled machine code. Instructions
|
||||
that activated faults in the FI experiments, and led to one of the enabled
|
||||
result types, are highlighted with red color. The stronger the coloring, the
|
||||
more experiments led to one of these failure modes. (Actually, not the raw
|
||||
number of actual experiments is used, but is weighted with the size of the
|
||||
corresponding def/use equivalence class.)
|
||||
|
||||
- Click one of the highlighted instructions to display a popup with the actual
|
||||
result numbers, and the distribution among the different failure modes.
|
||||
|
||||
- Pick a source-code file from the right-hand side pulldown to look into the
|
||||
instructions generated from that file. The right column now contains the
|
||||
source code from that file, interspersed with the disassembled machine code
|
||||
generated from it. These disassembled machine-code lines are, just like in
|
||||
the disassembly column, clickable to display details. (The source-code lines
|
||||
are currently not clickable, although the mouse cursor indicates otherwise.)
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Starts VisualFAIL over php on Port 1234
|
||||
#
|
||||
|
||||
php -S localhost:1234 -t .
|
||||
@@ -0,0 +1,507 @@
|
||||
<?php
|
||||
require('CONFIGURATION.php');
|
||||
|
||||
// increase default script runtime limit
|
||||
set_time_limit(60*10);
|
||||
|
||||
//Datenbankverbindung aufbauen
|
||||
$verbindung = mysql_connect ($host,$username, $password)
|
||||
or die ("MySQL connection failed.");
|
||||
|
||||
mysql_select_db($database) or die ("Cannot select database '$database'.");
|
||||
|
||||
// identify command
|
||||
switch ($_GET['cmd']) {
|
||||
case "dbTest" : dbTest();break;
|
||||
case "getAsmCode" : getAsmCode();break;
|
||||
case "asmToSourceFile" : asmToSourceFile();break;
|
||||
case "getBinarys" : getBinarys();break;
|
||||
case "getVariants" : getVariants();break;
|
||||
case "getSourceFiles" : getSourceFiles();break;
|
||||
case "getResultTypes" : getResulttypesOUT();break;
|
||||
case "getHighlevelCode" : getHighlevelCode();break;
|
||||
case "resultsDB" : resultsDB();break;
|
||||
case "dechex" : echo json_encode(dechex($_GET['dec']));break;
|
||||
}
|
||||
|
||||
mysql_close($verbindung);
|
||||
|
||||
function dbTest()
|
||||
{
|
||||
|
||||
$check = true;
|
||||
|
||||
$abfrage = "SELECT 1 FROM objdump;";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
if (!$ergebnis) {
|
||||
echo json_encode('Tabelle objdump nicht gefunden <br>');
|
||||
return;
|
||||
}
|
||||
|
||||
$abfrage = "SELECT 1 FROM fulltrace;";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
if (!$ergebnis) {
|
||||
echo json_encode('Tabelle fulltrace nicht gefunden <br>');
|
||||
return;
|
||||
}
|
||||
|
||||
$abfrage = "SELECT 1 FROM dbg_filename;";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
if (!$ergebnis) {
|
||||
echo json_encode('Tabelle dbg_filename nicht gefunden <br>');
|
||||
return;
|
||||
}
|
||||
|
||||
$abfrage = "SELECT 1 FROM dbg_mapping;";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
if (!$ergebnis) {
|
||||
echo json_encode('Tabelle dbg_mapping nicht gefunden <br>');
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
$abfrage = "SELECT 1 FROM dbg_methods;";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
if (!$ergebnis) {
|
||||
echo json_encode('Tabelle dbg_methods nicht gefunden <br>');
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
$abfrage = "SELECT 1 FROM dbg_source;";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
if (!$ergebnis) {
|
||||
echo json_encode('Tabelle dbg_source nicht gefunden <br>');
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
$abfrage = "SELECT 1 FROM dbg_stacktrace;";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
if (!$ergebnis) {
|
||||
echo json_encode('Tabelle dbg_stacktrace nicht gefunden <br>');
|
||||
return;
|
||||
}
|
||||
|
||||
$abfrage = "SELECT 1 FROM dbg_variables;";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
if (!$ergebnis) {
|
||||
echo json_encode('Tabelle dbg_variables nicht gefunden <br>');
|
||||
return;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
function getBinarys()
|
||||
{
|
||||
$binarys = array();
|
||||
|
||||
$abfrage = "SELECT benchmark FROM variant;";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
while ($row = mysql_fetch_object($ergebnis)) {
|
||||
array_push($binarys, $row->benchmark);
|
||||
}
|
||||
|
||||
$result = array_unique($binarys);
|
||||
|
||||
echo json_encode($result);
|
||||
}
|
||||
|
||||
function getVariants()
|
||||
{
|
||||
$variants = array();
|
||||
|
||||
$abfrage = "SELECT id, variant FROM variant WHERE benchmark = '" . $_GET['datei'] ."';";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
while ($row = mysql_fetch_object($ergebnis)) {
|
||||
$variants[$row->id] = $row->variant;
|
||||
}
|
||||
|
||||
echo json_encode($variants);
|
||||
}
|
||||
|
||||
function remove_common_prefix($files)
|
||||
{
|
||||
if (count($files) == 0) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// start with arbitrary file
|
||||
$commonprefix = dirname(current($files));
|
||||
|
||||
foreach ($files AS $id => $file) {
|
||||
for ($i = 0; $i < strlen($commonprefix); ++$i) {
|
||||
if ($i >= strlen($file) || $file[$i] != $commonprefix[$i]) {
|
||||
$commonprefix = substr($commonprefix, 0, $i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (strlen($commonprefix) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$out = array();
|
||||
foreach ($files AS $id => $file) {
|
||||
$out[$id] = substr($file, strlen($commonprefix));
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
function getSourceFiles()
|
||||
{
|
||||
$sourceFiles = array();
|
||||
|
||||
$abfrage = "SELECT file_id, path FROM dbg_filename WHERE variant_id = '" . $_GET['variant_id']. "';";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
while ($row = mysql_fetch_object($ergebnis)) {
|
||||
$sourceFiles[$row->file_id] = $row->path;
|
||||
}
|
||||
|
||||
$sourceFiles = remove_common_prefix($sourceFiles);
|
||||
|
||||
echo json_encode($sourceFiles);
|
||||
}
|
||||
|
||||
function asmCode()
|
||||
{
|
||||
$content = "";
|
||||
|
||||
$abfrage = "SELECT instr_address, disassemble FROM objdump WHERE variant_id = '" . $_GET['variant_id'] ."' ORDER BY instr_address;";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
$content = $content;
|
||||
while ($row = mysql_fetch_object($ergebnis)) {
|
||||
$content .= dechex($row->instr_address) . '<br>';
|
||||
}
|
||||
echo json_encode($content);
|
||||
}
|
||||
|
||||
function collapse_repeated($html, $disasm, $force_finish)
|
||||
{
|
||||
static $last_disasm = '';
|
||||
static $collect = array();
|
||||
$limit_before = $limit_after = 3;
|
||||
|
||||
$out = '';
|
||||
if ($force_finish || $last_disasm != $disasm) {
|
||||
if (count($collect) > $limit_before + $limit_after + 1) {
|
||||
for ($i = 0; $i < $limit_before; ++$i) {
|
||||
$out .= $collect[$i];
|
||||
}
|
||||
$out .= '<i>-- omitted ' . (count($collect) - $limit_before - $limit_after) . " repetitions of '$last_disasm'</i><br>";
|
||||
for ($i = count($collect) - $limit_after; $i < count($collect); ++$i) {
|
||||
$out .= $collect[$i];
|
||||
}
|
||||
} else {
|
||||
$out = implode('', $collect);
|
||||
}
|
||||
$last_disasm = $disasm;
|
||||
$collect = array();
|
||||
}
|
||||
|
||||
if ($force_finish) {
|
||||
$out .= $html;
|
||||
} else {
|
||||
$collect[] = $html;
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
function getAsmCode()
|
||||
{
|
||||
$content = "";
|
||||
$resulttypes = array();
|
||||
|
||||
$asmAbfrage = "SELECT instr_address, disassemble FROM objdump WHERE variant_id = '" . $_GET['variant_id'] ."' ORDER BY instr_address;";
|
||||
|
||||
$asmcode = mysql_query($asmAbfrage);
|
||||
|
||||
getResulttypes($resulttypes);
|
||||
|
||||
$fehlerdaten = resultsDB($_GET['variant_id'], $_GET['version'], $resulttypes);
|
||||
//$fehlerdaten = askDBFehler($_GET['variant_id'], $resulttypes, $_GET['version']);
|
||||
|
||||
//print_r($fehlerdaten);
|
||||
// FIXME id not unique
|
||||
$content = '<div id="maxFehler" ';
|
||||
foreach ($resulttypes as $value) {
|
||||
$temp = $value . '="' . $fehlerdaten['max'][$value] . '" ';
|
||||
$content .= $temp;
|
||||
}
|
||||
$content .= ' >';
|
||||
while ($row = mysql_fetch_object($asmcode)) {
|
||||
if (array_key_exists($row->instr_address,$fehlerdaten['Daten'])) {
|
||||
$line = '<span data-address="' . dechex($row->instr_address) . '" class="hasFehler" ';
|
||||
|
||||
foreach ($resulttypes as $value) {
|
||||
$line .= $value . '="' . $fehlerdaten['Daten'][$row->instr_address][$value] . '" ';
|
||||
}
|
||||
|
||||
$line .= ' style="cursor: pointer;">' . dechex($row->instr_address) . ' ' . htmlspecialchars($row->disassemble) . '</span><br>';
|
||||
$content .= collapse_repeated($line, 'dontcare', true);
|
||||
} else {
|
||||
$line = dechex($row->instr_address) . ' ' . htmlspecialchars($row->disassemble) . '<br>';
|
||||
$content .= collapse_repeated($line, htmlspecialchars($row->disassemble), false);
|
||||
}
|
||||
}
|
||||
$content .= collapse_repeated('', '', true);
|
||||
$content .= ' </div>';
|
||||
|
||||
echo json_encode($content);
|
||||
}
|
||||
|
||||
function getHighlevelCode()
|
||||
{
|
||||
$content = "";
|
||||
$resulttypes = array();
|
||||
|
||||
getResulttypes($resulttypes);
|
||||
|
||||
$kleinsteAdresseAbfrage = "SELECT MIN(instr_address) AS instr_address FROM objdump WHERE variant_id = " . $_GET['variant_id'];
|
||||
$kleinsteAdresseErgebnis = mysql_query($kleinsteAdresseAbfrage) or trigger_error($kleinsteAdresseAbfrage, E_USER_NOTICE);
|
||||
$kleinsteAdresse = mysql_fetch_object($kleinsteAdresseErgebnis);
|
||||
|
||||
$highlevelCodeAbfrage = "SELECT linenumber, line FROM dbg_source WHERE variant_id = '" . $_GET['variant_id']. "' AND file_id = '" . $_GET['file_id']. "' ORDER BY linenumber;";
|
||||
$mappingAbfrage = "SELECT linenumber, instr_absolute, line_range_size FROM dbg_mapping WHERE variant_id = '" . $_GET['variant_id']. "' AND file_id = '" . $_GET['file_id'] . "' AND instr_absolute >= '" . $kleinsteAdresse->instr_address . "' ORDER BY instr_absolute;";
|
||||
|
||||
$highlevelCode = mysql_query($highlevelCodeAbfrage);
|
||||
$mappingInfo = mysql_query($mappingAbfrage);
|
||||
|
||||
$fehlerdaten = resultsDB($_GET['variant_id'], $_GET['version'], $resulttypes);
|
||||
|
||||
// retrieve mapping of linenumber -> array of [start-address;end-address) ranges
|
||||
$mappingRanges = array();
|
||||
while (($row = mysql_fetch_object($mappingInfo))) {
|
||||
if (!isset($mappingRanges[$row->linenumber])) {
|
||||
$mappingRanges[$row->linenumber] = array();
|
||||
}
|
||||
$mappingRanges[$row->linenumber][] =
|
||||
array(intval($row->instr_absolute),
|
||||
$row->instr_absolute + $row->line_range_size);
|
||||
}
|
||||
|
||||
$mapping = array();
|
||||
// "maxFehler" should be "sumFehler" or alike
|
||||
$maxFehlerMapping = array();
|
||||
|
||||
foreach ($mappingRanges as $lineNumber => $value) {
|
||||
$maxFehler = array();
|
||||
foreach ($resulttypes as $val) {
|
||||
$maxFehler[$val] = 0;
|
||||
}
|
||||
foreach ($value as $index => $ranges) {
|
||||
// was ">" instead of ">=" before
|
||||
$InstrMappingAbfrage = "SELECT instr_address, disassemble FROM objdump WHERE variant_id = '" . $_GET['variant_id']. "' AND instr_address >= '" . $ranges[0] . "' AND instr_address < '" . $ranges[1] . "' ORDER BY instr_address;";
|
||||
$mappingErgebnis = mysql_query($InstrMappingAbfrage);
|
||||
while ($row = mysql_fetch_object($mappingErgebnis)) {
|
||||
if (array_key_exists($row->instr_address,$fehlerdaten['Daten'])) {
|
||||
$newline = '<span data-address="' . dechex($row->instr_address) . '" class="hasFehler" ';
|
||||
|
||||
foreach ($resulttypes as $value) {
|
||||
// FIXME prefix with 'data-results-', adapt JS
|
||||
$newline .= $value . '="' . $fehlerdaten['Daten'][$row->instr_address][$value] . '" ';
|
||||
$maxFehler[$value] += $fehlerdaten['Daten'][$row->instr_address][$value];
|
||||
}
|
||||
|
||||
$newline .= ' style="cursor: pointer;">' . dechex($row->instr_address) . ' ' . htmlspecialchars($row->disassemble) . '</span><br>';
|
||||
$newline = collapse_repeated($newline, 'dontcare', true);
|
||||
} else {
|
||||
$newline = dechex($row->instr_address) . ' ' . htmlspecialchars($row->disassemble) . '<br>';
|
||||
$newline = collapse_repeated($newline, htmlspecialchars($row->disassemble), false);
|
||||
}
|
||||
$mapping[$lineNumber] [] = $newline;
|
||||
}
|
||||
$mapping[$lineNumber] [] = collapse_repeated('', '', true);
|
||||
}
|
||||
foreach ($resulttypes as $value) {
|
||||
$maxFehlerMapping[$lineNumber][$value] = $maxFehler[$value];
|
||||
}
|
||||
}
|
||||
|
||||
while ($row = mysql_fetch_object($highlevelCode)) {
|
||||
// FIXME id unique?
|
||||
$content .= '<span data-line="' . $row->linenumber . '" class="sourcecode">' . $row->linenumber . ' : ' . $row->line . '</span><br>';
|
||||
if (array_key_exists($row->linenumber, $mapping)) {
|
||||
$content .= '<div class="mapping">';
|
||||
foreach ($mapping[$row->linenumber] as $index => $span) {
|
||||
$content .= $span;
|
||||
}
|
||||
$content .= '</div><div class="maxFehlerMapping"';
|
||||
foreach ($resulttypes as $value) {
|
||||
$content .= $value . '="' . $maxFehlerMapping[$row->linenumber][$value] . '" ';
|
||||
}
|
||||
$content .= '></div>';
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($content);
|
||||
}
|
||||
|
||||
function getResulttypes(&$resulttypes)
|
||||
{
|
||||
$abfrage = "SELECT resulttype FROM " . $GLOBALS['result_table'] . " GROUP BY resulttype;";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
while ($row = mysql_fetch_object($ergebnis)) {
|
||||
//echo $row->resulttype;
|
||||
array_push($resulttypes, $row->resulttype);
|
||||
}
|
||||
}
|
||||
|
||||
function getResulttypesOUT()
|
||||
{
|
||||
$resulttypes = array();
|
||||
|
||||
$abfrage = "SELECT resulttype FROM " . $GLOBALS['result_table'] . " GROUP BY resulttype;";
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
while ($row = mysql_fetch_object($ergebnis)) {
|
||||
//echo $row->resulttype;
|
||||
array_push($resulttypes, $row->resulttype);
|
||||
}
|
||||
|
||||
echo json_encode($resulttypes);
|
||||
}
|
||||
|
||||
function askDBFehler($variant_id, $resulttypes, $version)
|
||||
{
|
||||
if ($version == 'onlyRightEdge') {
|
||||
// we don't need fulltrace here at all
|
||||
$abfrage = "SELECT t.instr2 AS instr, t.instr2_absolute AS instr_absolute";
|
||||
foreach ( $resulttypes as $value) {
|
||||
$abfrage .= ", SUM(IF(r.resulttype = '" . $value . "', 1, 0)*(t.time2-t.time1+1)) AS " . $value;
|
||||
}
|
||||
$abfrage .= " FROM trace t
|
||||
JOIN fsppilot p
|
||||
ON t.variant_id = p.variant_id
|
||||
AND t.data_address = p.data_address
|
||||
AND p.instr2 = t.instr2
|
||||
JOIN " . $GLOBALS['result_table'] . " r
|
||||
ON p.id = r.pilot_id
|
||||
WHERE t.variant_id = $variant_id
|
||||
AND t.accesstype = 'R'
|
||||
GROUP BY t.instr2_absolute;";
|
||||
} else if ($version == 'latestip') {
|
||||
$abfrage = "SELECT r.latest_ip ";
|
||||
foreach ( $resulttypes as $value) {
|
||||
$abfrage .= ", SUM(IF(r.resulttype = '" . $value . "', 1, 0)*(t.time2-t.time1+1)) AS " . $value;
|
||||
}
|
||||
$abfrage .= " FROM trace t
|
||||
JOIN fsppilot p
|
||||
ON t.variant_id = p.variant_id
|
||||
AND t.data_address = p.data_address
|
||||
AND p.instr2 = t.instr2
|
||||
JOIN " . $GLOBALS['result_table'] . " r
|
||||
ON p.id = r.pilot_id
|
||||
WHERE t.variant_id = '" . $variant_id . "' AND t.accesstype = 'R'
|
||||
GROUP BY r.latest_ip;";
|
||||
} else {
|
||||
$abfrage = "SELECT ft.instr, ft.instr_absolute ";
|
||||
foreach ( $resulttypes as $value) {
|
||||
$abfrage .= ", SUM(IF(r.resulttype = '" . $value . "', 1, 0)*(t.time2-t.time1+1)) AS " . $value;
|
||||
}
|
||||
$abfrage .= " FROM fulltrace ft
|
||||
LEFT JOIN trace t
|
||||
ON ft.variant_id = '" . $variant_id . "'
|
||||
AND t.variant_id = '" . $variant_id . "'
|
||||
AND ft.instr BETWEEN t.instr1 AND t.instr2
|
||||
AND t.accesstype = 'R'
|
||||
JOIN fsppilot p
|
||||
ON t.variant_id = '" . $variant_id . "'
|
||||
AND p.variant_id = '" . $variant_id . "'
|
||||
AND t.data_address = p.data_address
|
||||
AND p.instr2 = t.instr2
|
||||
JOIN " . $GLOBALS['result_table'] . " r
|
||||
ON p.id = r.pilot_id
|
||||
GROUP BY ft.instr_absolute;";
|
||||
}
|
||||
|
||||
//echo $abfrage;
|
||||
|
||||
$ergebnis = mysql_query($abfrage);
|
||||
|
||||
return $ergebnis;
|
||||
}
|
||||
|
||||
function resultsDB($variant_id, $version, $resulttypes)
|
||||
{
|
||||
getResulttypes($resulttypes);
|
||||
|
||||
//print_r($resulttypes);
|
||||
|
||||
$ergebnis = askDBFehler($variant_id, $resulttypes, $version);
|
||||
|
||||
//print_r($ergebnis);
|
||||
|
||||
$results = array();
|
||||
|
||||
// We find the fields number
|
||||
$numfields=mysql_num_fields($ergebnis);
|
||||
|
||||
for ($i=0; $i < $numfields; $i++) {
|
||||
$fieldname[$i]=mysql_field_name($ergebnis, $i);
|
||||
}
|
||||
|
||||
for ($i=2; $i < $numfields; $i++) {
|
||||
$results["max"][$fieldname[$i]] = 0;
|
||||
}
|
||||
|
||||
$maxFehler = 0;
|
||||
while ($row = mysql_fetch_object($ergebnis)) {
|
||||
if ($version != 'latestip') {
|
||||
if ($row->instr_absolute != NULL) {
|
||||
$results["Daten"][$row->instr_absolute] = array();
|
||||
for ($i = 2; $i < $numfields ; $i++) {
|
||||
$results["Daten"][$row->instr_absolute][$fieldname[$i]] = $row->$fieldname[$i];
|
||||
|
||||
if ($row->$fieldname[$i] > $results["max"][$fieldname[$i]]) {
|
||||
$results["max"][$fieldname[$i]] = $row->$fieldname[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ($row->latest_ip != NULL) {
|
||||
$results["Daten"][$row->latest_ip] = array();
|
||||
for ($i = 0 ; $i < $numfields ; $i++) {
|
||||
$results["Daten"][$row->latest_ip][$fieldname[$i]] = $row->$fieldname[$i];
|
||||
|
||||
if ($row->$fieldname[$i] > $results["max"][$fieldname[$i]]) {
|
||||
$results["max"][$fieldname[$i]] = $row->$fieldname[$i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
?>
|
||||
+397
@@ -0,0 +1,397 @@
|
||||
/*!
|
||||
* Bootstrap v3.0.3 (http://getbootstrap.com)
|
||||
* Copyright 2013 Twitter, Inc.
|
||||
* Licensed under http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
||||
|
||||
.btn-default,
|
||||
.btn-primary,
|
||||
.btn-success,
|
||||
.btn-info,
|
||||
.btn-warning,
|
||||
.btn-danger {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
|
||||
.btn-default:active,
|
||||
.btn-primary:active,
|
||||
.btn-success:active,
|
||||
.btn-info:active,
|
||||
.btn-warning:active,
|
||||
.btn-danger:active,
|
||||
.btn-default.active,
|
||||
.btn-primary.active,
|
||||
.btn-success.active,
|
||||
.btn-info.active,
|
||||
.btn-warning.active,
|
||||
.btn-danger.active {
|
||||
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
}
|
||||
|
||||
.btn:active,
|
||||
.btn.active {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
background-image: -webkit-linear-gradient(top, #ffffff 0%, #e0e0e0 100%);
|
||||
background-image: linear-gradient(to bottom, #ffffff 0%, #e0e0e0 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dbdbdb;
|
||||
border-color: #ccc;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.btn-default:hover,
|
||||
.btn-default:focus {
|
||||
background-color: #e0e0e0;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
|
||||
.btn-default:active,
|
||||
.btn-default.active {
|
||||
background-color: #e0e0e0;
|
||||
border-color: #dbdbdb;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #2b669a;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.btn-primary:hover,
|
||||
.btn-primary:focus {
|
||||
background-color: #2d6ca2;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
|
||||
.btn-primary:active,
|
||||
.btn-primary.active {
|
||||
background-color: #2d6ca2;
|
||||
border-color: #2b669a;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #3e8f3e;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.btn-success:hover,
|
||||
.btn-success:focus {
|
||||
background-color: #419641;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
|
||||
.btn-success:active,
|
||||
.btn-success.active {
|
||||
background-color: #419641;
|
||||
border-color: #3e8f3e;
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #e38d13;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.btn-warning:hover,
|
||||
.btn-warning:focus {
|
||||
background-color: #eb9316;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
|
||||
.btn-warning:active,
|
||||
.btn-warning.active {
|
||||
background-color: #eb9316;
|
||||
border-color: #e38d13;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b92c28;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.btn-danger:hover,
|
||||
.btn-danger:focus {
|
||||
background-color: #c12e2a;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
|
||||
.btn-danger:active,
|
||||
.btn-danger.active {
|
||||
background-color: #c12e2a;
|
||||
border-color: #b92c28;
|
||||
}
|
||||
|
||||
.btn-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #28a4c9;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.btn-info:hover,
|
||||
.btn-info:focus {
|
||||
background-color: #2aabd2;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
|
||||
.btn-info:active,
|
||||
.btn-info.active {
|
||||
background-color: #2aabd2;
|
||||
border-color: #28a4c9;
|
||||
}
|
||||
|
||||
.thumbnail,
|
||||
.img-thumbnail {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
|
||||
.dropdown-menu > li > a:hover,
|
||||
.dropdown-menu > li > a:focus {
|
||||
background-color: #e8e8e8;
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
}
|
||||
|
||||
.dropdown-menu > .active > a,
|
||||
.dropdown-menu > .active > a:hover,
|
||||
.dropdown-menu > .active > a:focus {
|
||||
background-color: #357ebd;
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
|
||||
}
|
||||
|
||||
.navbar-default {
|
||||
background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
|
||||
background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-radius: 4px;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
|
||||
.navbar-default .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
|
||||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
|
||||
.navbar-brand,
|
||||
.navbar-nav > li > a {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
.navbar-inverse {
|
||||
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222222 100%);
|
||||
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222222 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #222222 0%, #282828 100%);
|
||||
background-image: linear-gradient(to bottom, #222222 0%, #282828 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.navbar-inverse .navbar-brand,
|
||||
.navbar-inverse .navbar-nav > li > a {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
|
||||
.navbar-static-top,
|
||||
.navbar-fixed-top,
|
||||
.navbar-fixed-bottom {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.alert {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.alert-success {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b2dba1;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
|
||||
}
|
||||
|
||||
.alert-info {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #9acfea;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
|
||||
}
|
||||
|
||||
.alert-warning {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #f5e79e;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
|
||||
}
|
||||
|
||||
.alert-danger {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dca7a7;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
|
||||
}
|
||||
|
||||
.progress {
|
||||
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
|
||||
}
|
||||
|
||||
.progress-bar-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
|
||||
}
|
||||
|
||||
.progress-bar-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
|
||||
}
|
||||
|
||||
.progress-bar-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
|
||||
}
|
||||
|
||||
.progress-bar-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
|
||||
}
|
||||
|
||||
.list-group {
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
|
||||
}
|
||||
|
||||
.list-group-item.active,
|
||||
.list-group-item.active:hover,
|
||||
.list-group-item.active:focus {
|
||||
text-shadow: 0 -1px 0 #3071a9;
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #3278b3;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
|
||||
}
|
||||
|
||||
.panel {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.panel-default > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
}
|
||||
|
||||
.panel-primary > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
|
||||
}
|
||||
|
||||
.panel-success > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
|
||||
}
|
||||
|
||||
.panel-info > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
|
||||
}
|
||||
|
||||
.panel-warning > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
|
||||
}
|
||||
|
||||
.panel-danger > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
|
||||
}
|
||||
|
||||
.well {
|
||||
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dcdcdc;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
|
||||
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
+7118
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,23 @@
|
||||
body {
|
||||
min-height: 2000px;
|
||||
padding-top: 70px;
|
||||
}
|
||||
|
||||
/* Custom container */
|
||||
.container-full {
|
||||
margin: 0 auto;
|
||||
padding: 0 15px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.logo {
|
||||
padding: 0 0 0 30px;
|
||||
}
|
||||
|
||||
.sourcecode {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#analyse {
|
||||
margin: 20px 0 0 0;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
Binary file not shown.
@@ -0,0 +1,229 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata></metadata>
|
||||
<defs>
|
||||
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
|
||||
<font-face units-per-em="1200" ascent="960" descent="-240" />
|
||||
<missing-glyph horiz-adv-x="500" />
|
||||
<glyph />
|
||||
<glyph />
|
||||
<glyph unicode="
" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
|
||||
<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="434" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="163" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="72" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode="€" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
|
||||
<glyph unicode="−" d="M200 400h900v300h-900v-300z" />
|
||||
<glyph unicode="☁" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86t85 208q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
|
||||
<glyph unicode="✉" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
|
||||
<glyph unicode="✏" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
|
||||
<glyph unicode="" horiz-adv-x="500" d="M0 0z" />
|
||||
<glyph unicode="" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
|
||||
<glyph unicode="" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q17 -55 85.5 -75.5t147.5 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
|
||||
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
|
||||
<glyph unicode="" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
|
||||
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
|
||||
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
|
||||
<glyph unicode="" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
|
||||
<glyph unicode="" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
|
||||
<glyph unicode="" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
|
||||
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
|
||||
<glyph unicode="" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 299q-120 -77 -261 -77q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
|
||||
<glyph unicode="" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
|
||||
<glyph unicode="" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
|
||||
<glyph unicode="" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
|
||||
<glyph unicode="" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
|
||||
<glyph unicode="" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
|
||||
<glyph unicode="" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
|
||||
<glyph unicode="" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
|
||||
<glyph unicode="" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
|
||||
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
|
||||
<glyph unicode="" d="M0 25v475l200 700h800q199 -700 200 -700v-475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
|
||||
<glyph unicode="" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
|
||||
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
|
||||
<glyph unicode="" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
|
||||
<glyph unicode="" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
|
||||
<glyph unicode="" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
|
||||
<glyph unicode="" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
|
||||
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
|
||||
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
|
||||
<glyph unicode="" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
|
||||
<glyph unicode="" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
|
||||
<glyph unicode="" d="M1 700v475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
|
||||
<glyph unicode="" d="M2 700v475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
|
||||
<glyph unicode="" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
|
||||
<glyph unicode="" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
|
||||
<glyph unicode="" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
|
||||
<glyph unicode="" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
|
||||
<glyph unicode="" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v70h471q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
|
||||
<glyph unicode="" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
|
||||
<glyph unicode="" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
|
||||
<glyph unicode="" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
|
||||
<glyph unicode="" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
|
||||
<glyph unicode="" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
|
||||
<glyph unicode="" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
|
||||
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
|
||||
<glyph unicode="" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 138.5t-64 210.5zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q60 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l566 567l-136 137l-430 -431l-147 147z" />
|
||||
<glyph unicode="" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
|
||||
<glyph unicode="" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
|
||||
<glyph unicode="" d="M200 0l900 550l-900 550v-1100z" />
|
||||
<glyph unicode="" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||
<glyph unicode="" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||
<glyph unicode="" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
|
||||
<glyph unicode="" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
|
||||
<glyph unicode="" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
|
||||
<glyph unicode="" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
|
||||
<glyph unicode="" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
|
||||
<glyph unicode="" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM300 500h600v200h-600v-200z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM363 700h144q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5q19 0 30 -10t11 -26 q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-105 0 -172 -56t-67 -183zM500 300h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -300t-217.5 -218t-299.5 -80t-299.5 80t-217.5 218t-80 300zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 500v200h194q15 60 36 104.5t55.5 86t88 69t126.5 40.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200 v-206q149 48 201 206h-201v200h200q-25 74 -76 127.5t-124 76.5v-204h-200v203q-75 -24 -130 -77.5t-79 -125.5h209v-200h-210z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
|
||||
<glyph unicode="" d="M0 547l600 453v-300h600v-300h-600v-301z" />
|
||||
<glyph unicode="" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
|
||||
<glyph unicode="" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
|
||||
<glyph unicode="" d="M104 600h296v600h300v-600h298l-449 -600z" />
|
||||
<glyph unicode="" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
|
||||
<glyph unicode="" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
|
||||
<glyph unicode="" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
|
||||
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-33 14.5h-207q-20 0 -32 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111v6t-1 15t-3 18l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6h-111v-100z M100 0h400v400h-400v-400zM200 900q-3 0 14 48t35 96l18 47l214 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
|
||||
<glyph unicode="" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
|
||||
<glyph unicode="" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
|
||||
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
|
||||
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
|
||||
<glyph unicode="" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 33 -48 36t-48 -29l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
|
||||
<glyph unicode="" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -21 -13 -29t-32 1l-94 78h-222l-94 -78q-19 -9 -32 -1t-13 29v64 q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
|
||||
<glyph unicode="" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
|
||||
<glyph unicode="" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
|
||||
<glyph unicode="" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
|
||||
<glyph unicode="" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
|
||||
<glyph unicode="" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
|
||||
<glyph unicode="" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
|
||||
<glyph unicode="" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
|
||||
<glyph unicode="" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
|
||||
<glyph unicode="" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
|
||||
<glyph unicode="" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
|
||||
<glyph unicode="" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM99 500v250v5q0 13 0.5 18.5t2.5 13t8 10.5t15 3h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35q-56 337 -56 351z M1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M74 350q0 21 13.5 35.5t33.5 14.5h17l118 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5l-18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-22 -9 -63 -23t-167.5 -37 t-251.5 -23t-245.5 20.5t-178.5 41.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
|
||||
<glyph unicode="" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
|
||||
<glyph unicode="" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q123 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 212l100 213h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
|
||||
<glyph unicode="" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q123 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
|
||||
<glyph unicode="" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
|
||||
<glyph unicode="" d="M-101 651q0 72 54 110t139 37h302l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 16.5 -10.5t26 -26t16.5 -36.5v-526q0 -13 -85.5 -93.5t-93.5 -80.5h-342q-15 0 -28.5 20t-19.5 41l-131 339h-106q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l106 89v502l-342 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM999 201v600h200v-600h-200z" />
|
||||
<glyph unicode="" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6v7.5v7v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
|
||||
<glyph unicode="" d="M1 585q-15 -31 7 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85l-1 -302q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM76 565l237 339h503l89 -100v-294l-340 -130 q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 500h300l-2 -194l402 294l-402 298v-197h-298v-201z" />
|
||||
<glyph unicode="" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l400 -294v194h302v201h-300v197z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -34 5.5 -93t7.5 -87q0 -9 17 -44t16 -60q12 0 23 -5.5 t23 -15t20 -13.5q20 -10 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55.5t-20 -57.5q12 -21 22.5 -34.5t28 -27t36.5 -17.5q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q101 -2 221 111q31 30 47 48t34 49t21 62q-14 9 -37.5 9.5t-35.5 7.5q-14 7 -49 15t-52 19 q-9 0 -39.5 -0.5t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q8 16 22 22q6 -1 26 -1.5t33.5 -4.5t19.5 -13q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5 t5.5 57.5q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 41 1 44q31 -13 58.5 -14.5t39.5 3.5l11 4q6 36 -17 53.5t-64 28.5t-56 23 q-19 -3 -37 0q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -46 0t-45 -3q-20 -6 -51.5 -25.5t-34.5 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -91t-29.5 -79zM518 915q3 12 16 30.5t16 25.5q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -18 8 -42.5t16.5 -44 t9.5 -23.5q-6 1 -39 5t-53.5 10t-36.5 16z" />
|
||||
<glyph unicode="" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
|
||||
<glyph unicode="" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
|
||||
<glyph unicode="" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM513 609q0 32 21 56.5t52 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-16 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5q-37 0 -62.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
|
||||
<glyph unicode="" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -79.5 -17t-67.5 -51l-388 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23q38 0 53 -36 q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60l517 511 q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
|
||||
<glyph unicode="" d="M79 784q0 131 99 229.5t230 98.5q144 0 242 -129q103 129 245 129q130 0 227 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100l-84.5 84.5t-68 74t-60 78t-33.5 70.5t-15 78z M250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-106 48.5q-73 0 -131 -83l-118 -171l-114 174q-51 80 -124 80q-59 0 -108.5 -49.5t-49.5 -118.5z" />
|
||||
<glyph unicode="" d="M57 353q0 -94 66 -160l141 -141q66 -66 159 -66q95 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-12 12 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141l19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -18q46 -46 77 -99l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
|
||||
<glyph unicode="" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
|
||||
<glyph unicode="" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
|
||||
<glyph unicode="" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335l-27 7q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5v-307l64 -14 q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5zM700 237 q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
|
||||
<glyph unicode="" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -11 2.5 -24.5t5.5 -24t9.5 -26.5t10.5 -25t14 -27.5t14 -25.5 t15.5 -27t13.5 -24h242v-100h-197q8 -50 -2.5 -115t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q32 1 102 -16t104 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10 t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5t-30 142.5h-221z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
|
||||
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
|
||||
<glyph unicode="" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
|
||||
<glyph unicode="" d="M216 519q10 -19 32 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8l9 -1q13 0 26 16l538 630q15 19 6 36q-8 18 -32 16h-300q1 4 78 219.5t79 227.5q2 17 -6 27l-8 8h-9q-16 0 -25 -15q-4 -5 -98.5 -111.5t-228 -257t-209.5 -238.5q-17 -19 -7 -40z" />
|
||||
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
|
||||
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 401h700v699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l248 -237v700h-699zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
|
||||
<glyph unicode="" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
|
||||
<glyph unicode="" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -117q-25 -16 -43.5 -50.5t-18.5 -65.5v-359z" />
|
||||
<glyph unicode="" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
|
||||
<glyph unicode="" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
|
||||
<glyph unicode="" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q16 17 13 40.5t-22 37.5l-192 136q-19 14 -45 12t-42 -19l-119 -118q-143 103 -267 227q-126 126 -227 268l118 118q17 17 20 41.5 t-11 44.5l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
|
||||
<glyph unicode="" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -15 -35.5t-35 -14.5h-1100q-21 0 -35.5 14.5t-14.5 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
|
||||
<glyph unicode="" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
|
||||
<glyph unicode="" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
|
||||
<glyph unicode="" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86t85 208q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300 h200l-300 -300z" />
|
||||
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104t60.5 178q0 121 -85 207.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
|
||||
<glyph unicode="" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
|
||||
<glyph unicode="" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -12t1 -11q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
After Width: | Height: | Size: 61 KiB |
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user