Commit Graph

82 Commits

Author SHA1 Message Date
Alessandro Di Federico e407fc11a1 Various minor cleanups 2018-05-30 12:45:45 +02:00
Alessandro Di Federico 069ae70d3e Fix handling of devirtualized calls
When we have an indirect call (or jump) we are sometimes able to
identify one or more possible targets, therefore, as an optimization,
before performing the indirect jump we check if the target is one of the
expected ones.

This optimization however was creating two issues with the handling of
indirect function calls: 1) the call to the `function_call` marker was
no longer positioned right before the terminator and 2) the function
call was no longer identified as an indirect function call but as call
to `anyPC`. This commit fixes these two issues.

These issues have been identified thanks to a report from Andrea
Gussoni.
2017-08-13 16:47:18 +02:00
Alessandro Di Federico edc6fe118c JTM::setCFGForm: ignore indirect calls 2017-08-12 16:56:23 +02:00
Alessandro Di Federico 47104c0fb4 Replace getNext with nextNonMarker
Most of the times, when we need to get the next instruction, we actually
want to skip over "marker" function calls (e.g., calls to `newpc` and
`function_call`). `nextNonMarker` does exactly this.

`FunctionCallIdentification::isCall` and `JumpTargetManager::setCFGForm`
have also been extended to correctly handle such situations.
2017-08-12 16:56:23 +02:00
Alessandro Di Federico ce09875c36 Make translateIndirectJumps private
`JumpTargetManager::translateIndirectJumps` has been pushed into
`JumpTargetManager::finalizeJumpTargets`. Moreover, an safety check
about the removal of `exitTB` has been introduced.
2017-08-12 16:56:23 +02:00
Alessandro Di Federico 355b8c8ad3 Tag the default case of the dispatcher
The basic block handling the default case of the dispatcher used not to
be tagged with `revamb.block.type`, now it is.
2017-08-12 16:56:23 +02:00
Alessandro Di Federico 9db62b288c Handle .bss-only data segment
This commit fixes an assertion triggered by the fact that a segment
includes exclusively zero-initialized data (i.e., size on file is 0,
memory size is not). In this case LLVM detects the fact that the global
variable associated to the segment is composed exclusively composed by
0s and uses a `ConstantAggregateZero` as an initializer instead of a
`ConstantDataArray`.

Currently the solution is ignore that data, however, in the future it
might be beneficial to be able to read data from `.bss`, even if we just
have zeros there.

Thanks to Thorbjoern Schulz for reporting this bug.
2017-07-07 15:39:01 +02:00
Alessandro Di Federico d8f13c799d Detect try/catch landing pads
Landing pads are basically the `catch` blocks in C++ `try`/`catch`
statements. So far we were missing them since they are encoded in a
particular way in a way similar to DWARF debugging information in the
`.eh_frame` and, more specifically, in the `.gcc_except_table` sections
of ELF programs.

This commit parses these sections so that the basic blocks associated to
landing pads are correctly identified. Personality functions are
detected too. A test is also introduced to assess the effectiveness of
our code.
2017-03-31 10:10:16 +02:00
Alessandro Di Federico ab160b039a Do not remove predecessors while iterating on them 2017-03-23 17:57:31 +01:00
Alessandro Di Federico d398213aa2 Purge translated code in post-order
This commit changes the way instruction and basic block are purged when
re-translation is necessary. Specifically, the purge is now performed
through a post-order visit, which should prevent the removal of any
instructions still holding users.

This commit also introduces the `SubGraph` class, which is useful to be
able to navigate portions of a graph (e.g., a `Function`) in post-order
easily.
2017-03-06 14:31:30 +01:00
Alessandro Di Federico 04a4591f5c When splitting a basic block, retranslate
This commit should fix some bugs due to the fact that when we're
splitting a basic block we don't retranslate the basic block at the
split point but preserve the existing code. This lead to problems, in
particular in x86-64 where certain QEMU local variables were not
available. This change should fix it.

Basically, every time we split a basic block in
`JumpTargetManager::registerJT` we note down that the new basic block
must be purged, and in `JumpTargetManager::harvest` we perform the
purge. `harvest` has been chosen since it's a particularly quiet moment,
i.e., there should be no pending references/iterator to code we have to
delete.
2017-03-02 08:21:11 +01:00
Alessandro Di Federico d6b257ddc5 Dismiss basic block statistics collection
If we need this again, we can do it in revamb-dump.
2017-03-02 08:21:11 +01:00
Alessandro Di Federico 3e8e9c23a0 Change the way we denote JT basic blocks
Currently we're identifying basic blocks that are a jump target by
adding metadata on the terminator instruction. This is a problem in many
cases, therefore we now use the third parameter of `newpc` calls to
understand if a basic block is a jump target.

The third argument was set only at the very end of all our analysis,
before producing the output. We anticipate this so that is done before
each jump target harvesting, so that this information is available
through `GeneratedCodeBasicInfo`.
2016-12-08 21:56:11 +01:00
Alessandro Di Federico 5c619ab063 Introduce the GCBI and FCI passes
This commit introduces two new passes:

* `GeneratedCodeBasicInfo`: recovers from the IR some basic information
  like the size of delay slots in the input architecture, the name of
  the program counter and so on. It can also identify the type of a
  basic block (e.g., dispatcher, jump target...).  *
* `FunctionCallIdentification`: identifies function calls and injects a
  marker before the associated terminator instruction.

The idea of these two passes is to try to progressively move information
we used to keep in `JumpTargetManager` into the IR, so that it is more
easily accessible and passes do not need a reference to `JTM`.

In particular by having markers for function calls available during jump
target discovery we don't have to have duplicated and suboptimal
implementation of `isCall`.

This commit also introduce some additional helper functions and an
helper class to quickly.
2016-12-08 21:56:11 +01:00
Alessandro Di Federico d6471b991d Remove clone of getLimitedValue from JTM 2016-12-08 21:56:11 +01:00
Alessandro Di Federico c83559fc1f Specify endianess when reading from segments
Let functions such as `JumpTargetManager::readRawValue` take a parameter
specifying if the value should be read from the segment using the
endianess of the original architecture or of the target architecture.

This commit fixes a bug with big endian architectures (i.e., MIPS) since
when materializing a value on the operation stack of SET, the endianess
was changed twice, once in `readRawValue` and the second time while
applying the `bswap` instruction which is registered on the stack.
2016-12-08 21:50:43 +01:00
Alessandro Di Federico 09e25267e7 Introduce the NoFunctionCallsCFG CFG form
`NoFunctionCallsCFG` is a form of the CFG where all the function call
edges are replaced with jumps to the return address. This is beneficial
in certain analysis to pretend we're working on a function-level.

To implement such a form of CFG we now emit right before the terminator
of each caller basic block a call to the "function_call" function
passing as the first parameter the callee basic block and as the second
one the return basic block. Using this function calls, switching to
`NoFunctionCallsCFG` and back becomes straightforward.
2016-12-04 00:28:56 +01:00
Alessandro Di Federico c579da6043 Add support to switch between different CFG forms
This commit introduces `JumpTargetManager::setCFGForm` which allows to
choose which type of CFG the user currently wants. The default and final
form should be `SemanticPreservingCFG`, which is the most conservative
one. However for certain analysis might be beneficial to have a reduced
CFG with almost no dispatcher (in particular for OSRA and SET).

This new function handles the switching between the two currently
available forms of CFG by changing the behavior of the `anyPC` and
`unexpectedPC` basic blocks and rebuilding the dispatcher as
appropriate.
2016-12-04 00:28:56 +01:00
Alessandro Di Federico c069700bc5 Keep the CFG simple: do not jump to the dispatcher
Every time we don't know where an indirect jump can go, we used to emit
a jump to the dispatcher, however this complicates our analyses, in
particular the computed dominator tree provides less useful information
than it could.

This commit transforms all the jumps to the dispatcher into jumps to a
"anypc" basic block which during analysis just contains an unreachable
instruction, but during finalization this instruction is replaced with a
jump to the dispatcher. A similar (temporary) situation is for the
"unexpectepc" case.

This commit also makes the `visit(Sucessors|Predecessors)` functions
more idiomatic by employing a trait for black lists.
2016-12-04 00:28:56 +01:00
Alessandro Di Federico 4f60a23d9a JTM::readRawValue: fix endianess bug
`JumpTargetManager::readRawValue` used to take into account the
endianess information from `DataLayout`, i.e., the output endianess,
while the input endianess should be take into account.

The commit also checks that during final basic block finalization we
have no empty basic blocks.
2016-12-03 08:46:12 +01:00
Alessandro Di Federico 83ea2caacd Isolate ELF code and remove architecture parameter
This commit removes all the ELF-specific code from the `CodeGenerator`
class by creating a new class, `BinaryFile` which contains all the
information about the program that might be needed in an image format
independent way. However, `BinaryFile` has some fields which are
specific to ELF, we might want to address this when additional file
formats are supported.

A key benefit of isolating this code is that we can anticipate the
parsing of the input file, so that we have its architecture available
earlier than when `CodeGenerator` is instantiated, therefore we can drop
the `--architecture` parameter.
2016-12-03 08:46:12 +01:00
Alessandro Di Federico c50dcc5c5d Use symbols to produce meaningful names
This commit introduces the usage of symbols, if they are available. We
employ them to produce meaningful names for basic block names.

* Collect the symbols from `.symtab`/`.dynsym`
* Box the `Segments` into a new data structure (`BinaryInfo`) which also
  handles symbols.
* `JumpTargetManager::nameForAddress`: produce a meaningful name using
  symbols, if possible.
* Spread some `const`-ness
2016-09-28 00:03:13 +02:00
Alessandro Di Federico d01ee1f437 Copyright notices, license and credits 2016-09-21 01:45:26 +02:00
Alessandro Di Federico 29879c8de2 Remove some dead code 2016-09-17 15:33:57 +02:00
Alessandro Di Federico cc87ad607d Introduce NoreturnAnalysis
This commit introduces the `noreturn` analysis, whose aim is to detect
all the basic blocks the are doomed to lead to a `noreturn` syscall such
as `execve` or `exit`.

* Implement `NoreturnAnalysis`.
* Include and initialize in the `Architecture` data structure all the
  necessary information to detect `noreturn` syscalls. Specifically, the
  name of the QEMU helper for syscalls, the name of the register holding
  the syscall number and the syscall numbers representing `noreturn`
  syscalls.
* `ReachingDefinitionsPass`: make reaching definitions available both in
  reaching definitions mode and reached loads mode. This part needs
  further cleanup. We also might be willing to implement this with a
  `Boost.Bimap`.
* Use `SET` to collect information useful for the
  `NoreturnAnalysis`. Also restructure how the `OperationsStack` works
  to be more streamlined and keep track of multiple information about
  the instruction currently being tracked.
2016-09-17 15:33:57 +02:00
Alessandro Di Federico 8dfda3d55a Keep track of memory ranges read by SET 2016-09-17 15:33:56 +02:00
Alessandro Di Federico 46fe86225b Free memory after analyses
* Clear all the data that's not part of the analysis results at the end
  of the `runOnFunction` method
* Clear all the data that's part of the analysis results when the
  `PassManager` tells us so (`Pass::releaseMemory`)
* Do not use the `clear()` method, since it doesn't release memory
* Add some debugging information
2016-09-17 15:33:56 +02:00
Alessandro Di Federico 7859f9de78 Keep track of how jump targets have been met
This commit registers for each jump target how we met it, as a flag. It
also keeps track of which pointers in global data have been involved in
materialization performed by SET: those who are not are of special
interest for us, since they are likely function pointers, and are
therefore marked with a specific flag.
2016-09-17 15:33:55 +02:00
Alessandro Di Federico 4ae7cdadaa Dismiss JumpTargetManager::registerBlock 2016-09-17 15:33:54 +02:00
Alessandro Di Federico 27b4e46525 Draft tracking of reasons for registering JTs 2016-09-17 15:33:54 +02:00
Alessandro Di Federico 1d87dced75 Drop the concept of "reliable" jump target 2016-09-17 15:33:54 +02:00
Alessandro Di Federico 6c5c0ad8f7 Add support for using section information 2016-09-17 15:33:54 +02:00
Alessandro Di Federico dd7e05d6c1 exitTBCleanup: don't delete with pending uses 2016-09-17 15:33:54 +02:00
Alessandro Di Federico deae1f841e SimplifyComparisonsPass: transform in analysis
* Add an "s" in the name
* Transform the pass in analysis and let OSRA use it
2016-09-17 15:33:53 +02:00
Alessandro Di Federico c21c1b190b Give a sensible name to all the basic blocks
* When generating the code for setting a label or jumping to it, give
  sensible names to the new basic blocks.
* Keep track of the last seen PC during translation so it can be used to
  obtain a sensible name for the basic block.
* Let `JumpTargetManager::getBlockAt` set a proper name to the basic
  block before returning, if it doesn't already have one.
2016-08-20 03:10:48 +02:00
Alessandro Di Federico 9c86833004 Introduce forceFallthroughAfterHelper
`forceFallthroughAfterHelper` handles the situation where there isn't a
PC-store between a call to an helper and to `exitTB`, in this case, we
force a branch to the fallthrough PC.

This commit also simplifies `InstructionTranslator::translateCall`:
remove jump to the dispatcher after a call to an helper in case the PC
was saved and it has changed. We don't really need to do this, QEMU will
generate a call to `exitTB` has necessary or
`forceFallthroughAfterHelper` will take care of the thing.
2016-08-20 03:10:48 +02:00
Alessandro Di Federico d3a6442af2 Factor out and improve visitSuccessors
* The function now can take a `std::set` of basic blocks to ignore.
* The visitor function has now several options on how to proceed, and
  can express them through its return value.
* A serious bug in the implementation was also fixed.
2016-08-20 03:10:48 +02:00
Alessandro Di Federico 430a7261b3 Introduce SimplifyComparisonPass
This pass helps us handling instructions like ARM's `blt` which compute
the result of the comparison by bit-fiddling with the bit sign of the
operands of a subtraction.

The idea is to have a series of known boolean expressions using `a`, `b'
and `c` as variables (e.g. the boolean expression corresponding to
"signed greater than") and compare their truth table against the one
being analyzed. In case of match, the comparison can be simplified.
2016-08-20 03:10:48 +02:00
Alessandro Di Federico 56c37f6cf6 Force execution of pinJTS 2016-08-20 03:10:47 +02:00
Alessandro Di Federico ba54372759 Check for "sum jumps" more often 2016-08-20 03:10:47 +02:00
Alessandro Di Federico acf7063aa6 Fix bugs in JumpTargetManager::getPC 2016-08-20 03:10:47 +02:00
Alessandro Di Federico f473731b0f Temporaly disable assertion 2016-08-20 03:10:47 +02:00
Alessandro Di Federico c0dbb6c5e7 Introduce pinning of potential jump targets
`TranslateDirectBranchesPass` now optionally depends on `SETPass`. This
allows us to reuse information obtained by SET and OSRA to pin potential
jump targets we detected to an `exitTB` call. In practice this means
that before a call to `exitTB` a conditional branch or a switch is
present to check if the destination of the jump is one of those we
expected, and if not, go to the dispatcher if the estimated destinations
were marked as approximate, or fail otherwise. Since this feature is
currently WIP, we never fail, we always go the dispatcher instead.

Since the amount of successors might grow during the iterative discovery
process, record the amount of successors as a `exitTB` argument.

* New `exitTB` argument: estimated number of successors.
* Move the code of the old implementation of the pass to the
  `pinConstantStore` function.
* Update routine for cleanup of post-exitTB instructions.
* `findNextExitTB`: more reliable implementation of the search for the
  next call to `exitTB`.
* Keep a reference to the basic block handling the failure of the
  dispatcher's switch, so we can use it to report failure of our jump
  target estimation.
2016-08-20 03:10:47 +02:00
Alessandro Di Federico 08be097123 Fix typos, add an assert, spread some const-ness 2016-08-20 03:10:47 +02:00
Alessandro Di Federico 0ca6087018 Reorganize the iterative BB discovery process
The iteartive basic block discovery process has been reorganized to
minimize the amount of passes we run (in particular SROA, constant
propagation and early CSE) and to proceed until we don't "pin" any new
branch instruction, and not only until we're not able to discover any
new basic block.

The logging output has also been reworked to be more informative.
2016-08-20 03:10:47 +02:00
Alessandro Di Federico 041ea8726d Introduce predecessors and successors 2016-08-20 03:10:47 +02:00
Alessandro Di Federico a997a0525a Use opcode names in basic block statistics 2016-08-20 03:10:46 +02:00
Alessandro Di Federico 1a5fc0f519 Introduce collection of basic block statistics
Let revamb produce a CSV file containing statistics about the translated
input basic blocks for further analysis (e.g., identify false
positives).
2016-08-20 03:10:46 +02:00
Alessandro Di Federico 4dd3638a46 Fix overflow when we check membership to a segment
Checking if a range of addresses belong to a segment should be
implemented by checking if the start and end address belong to the
address, the `Start <= Address && Address + Size < End` approach leads
to subtle errors when `Address` is close to the maximum representable
value due to an overflow.
2016-08-20 03:10:46 +02:00
Alessandro Di Federico dbb462a9a5 Fix issues in release builds
Mainly fixes due to the absence of asserts.
2016-08-20 03:10:46 +02:00