MC CFG: Add YAML MCModule representation to enable MC CFG testing.

Like yaml ObjectFiles, this will be very useful for testing the MC CFG
implementation (mostly MCObjectDisassembler), by matching the output
with YAML, and for potential users of the MC CFG, by using it as an input.

There isn't much to the actual format, it is just a serialization of the
MCModule class. Of note:
  - Basic block references (pred/succ, ..) are represented by the BB's
    start address.
  - Just as in the MC CFG, instructions are MCInsts with a size.
  - Operands have a prefix representing the type (only register and
    immediate supported here).
  - Instruction opcodes are represented by their names; enum values aren't
    stable, enum names mostly are: usually, a change to a name would need
    lots of changes in the backend anyway.
    Same with registers.

All in all, an example is better than 1000 words, here goes:

A simple binary:

  Disassembly of section __TEXT,__text:
  _main:
  100000f9c:      48 8b 46 08             movq    8(%rsi), %rax
  100000fa0:      0f be 00                movsbl  (%rax), %eax
  100000fa3:      3b 04 25 48 00 00 00    cmpl    72, %eax
  100000faa:      0f 8c 07 00 00 00       jl      7 <.Lend>
  100000fb0:      2b 04 25 48 00 00 00    subl    72, %eax
  .Lend:
  100000fb7:      c3                      ret

And the (pretty verbose) generated YAML:

  ---
  Atoms:
    - StartAddress:    0x0000000100000F9C
      Size:            20
      Type:            Text
      Content:
        - Inst:            MOV64rm
          Size:            4
          Ops:             [ RRAX, RRSI, I1, R, I8, R ]
        - Inst:            MOVSX32rm8
          Size:            3
          Ops:             [ REAX, RRAX, I1, R, I0, R ]
        - Inst:            CMP32rm
          Size:            7
          Ops:             [ REAX, R, I1, R, I72, R ]
        - Inst:            JL_4
          Size:            6
          Ops:             [ I7 ]
    - StartAddress:    0x0000000100000FB0
      Size:            7
      Type:            Text
      Content:
        - Inst:            SUB32rm
          Size:            7
          Ops:             [ REAX, REAX, R, I1, R, I72, R ]
    - StartAddress:    0x0000000100000FB7
      Size:            1
      Type:            Text
      Content:
        - Inst:            RET
          Size:            1
          Ops:             [  ]
  Functions:
    - Name:            __text
      BasicBlocks:
        - Address:         0x0000000100000F9C
          Preds:           [  ]
          Succs:           [ 0x0000000100000FB7, 0x0000000100000FB0 ]
     <snip>
  ...

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188890 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Ahmed Bougacha
2013-08-21 07:29:02 +00:00
parent f176482752
commit 171ac8ca17
4 changed files with 532 additions and 9 deletions

View File

@ -31,6 +31,7 @@
#include "llvm/MC/MCInstrAnalysis.h"
#include "llvm/MC/MCInstrInfo.h"
#include "llvm/MC/MCModule.h"
#include "llvm/MC/MCModuleYAML.h"
#include "llvm/MC/MCObjectDisassembler.h"
#include "llvm/MC/MCObjectFileInfo.h"
#include "llvm/MC/MCObjectSymbolizer.h"
@ -61,6 +62,7 @@
#include <algorithm>
#include <cctype>
#include <cstring>
using namespace llvm;
using namespace object;
@ -139,6 +141,12 @@ static cl::opt<bool>
CFG("cfg", cl::desc("Create a CFG for every function found in the object"
" and write it to a graphviz file"));
// FIXME: Does it make sense to have a dedicated tool for yaml cfg output?
static cl::opt<std::string>
YAMLCFG("yaml-cfg",
cl::desc("Create a CFG and write it as a YAML MCModule."),
cl::value_desc("yaml output file"));
static StringRef ToolName;
bool llvm::error(error_code ec) {
@ -178,6 +186,7 @@ static const Target *getTarget(const ObjectFile *Obj = NULL) {
}
// Write a graphviz file for the CFG inside an MCFunction.
// FIXME: Use GraphWriter
static void emitDOTFile(const char *FileName, const MCFunction &f,
MCInstPrinter *IP) {
// Start a new dot file.
@ -333,7 +342,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
return;
}
if (CFG) {
if (CFG || !YAMLCFG.empty()) {
OwningPtr<MCObjectDisassembler> OD(
new MCObjectDisassembler(*Obj, *DisAsm, *MIA));
OwningPtr<MCModule> Mod(OD->buildModule(/* withCFG */ true));
@ -350,14 +359,25 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) {
}
}
}
for (MCModule::const_func_iterator FI = Mod->func_begin(),
FE = Mod->func_end();
FI != FE; ++FI) {
static int filenum = 0;
emitDOTFile((Twine((*FI)->getName()) + "_" +
utostr(filenum) + ".dot").str().c_str(),
**FI, IP.get());
++filenum;
if (CFG) {
for (MCModule::const_func_iterator FI = Mod->func_begin(),
FE = Mod->func_end();
FI != FE; ++FI) {
static int filenum = 0;
emitDOTFile((Twine((*FI)->getName()) + "_" +
utostr(filenum) + ".dot").str().c_str(),
**FI, IP.get());
++filenum;
}
}
if (!YAMLCFG.empty()) {
std::string Error;
raw_fd_ostream YAMLOut(YAMLCFG.c_str(), Error);
if (!Error.empty()) {
errs() << "llvm-objdump: warning: " << Error << '\n';
return;
}
mcmodule2yaml(YAMLOut, *Mod, *MII, *MRI);
}
}