Example #1
0
def test_DotControlFlowGraphsFromBytecode_simple_c_program():
    """Test that simple C program produces two Dot CFGs."""
    dot_cfgs = list(
        opt_util.DotControlFlowGraphsFromBytecode(SIMPLE_C_BYTECODE))
    assert len(dot_cfgs) == 2
    assert "CFG for 'DoSomething' function" in "\n".join(dot_cfgs)
    assert "CFG for 'main' function" in "\n".join(dot_cfgs)
Example #2
0
def _DotControlFlowGraphsFromBytecodeToQueue(
        bytecode: str, queue: multiprocessing.Queue) -> None:
    """Process a bytecode and submit the dot source or the exception."""
    try:
        queue.put(list(opt_util.DotControlFlowGraphsFromBytecode(bytecode)))
    except Exception as e:
        queue.put(DotControlFlowGraphsFromBytecodeError(bytecode, e))
Example #3
0
def _ExtractGraphBatchOrDie(
  src_file_paths: typing.List[pathlib.Path], headers_dir: pathlib.Path
) -> typing.List[typing.Tuple[pathlib.Path, llvm_util.LlvmControlFlowGraph]]:
  """Process a patch of OpenCL sources to graphs.

  Args:
    src_file_paths: A list of source code paths.
    headers_dir: The directory containing header files.

  Returns:
    A list of <path,cfg> tuples.
  """
  batch = []

  for src_file_path in src_file_paths:
    app.Log(1, "Compiling %s", src_file_path.name)
    bytecode = ncc.ExtractLlvmByteCodeOrDie(src_file_path, headers_dir)
    dot_strings = list(opt_util.DotControlFlowGraphsFromBytecode(bytecode))
    cfgs = [llvm_util.ControlFlowGraphFromDotSource(dot) for dot in dot_strings]
    if len(cfgs) != 1:
      app.Fatal(
        "Found %d CFGs in %s: %s",
        len(dot_strings),
        src_file_path.name,
        [c.graph["name"] for c in cfgs],
      )
    ffg = cfgs[0].BuildFullFlowGraph()

    # Set the input bytecode as a graph property.
    ffg.graph["llvm_bytecode"] = bytecode

    batch.append((src_file_path, ffg))

  return batch
Example #4
0
def TryToCreateControlFlowGraphsFromLinuxSrc(
  path: pathlib.Path,
) -> typing.List[cfg.ControlFlowGraph]:
  """Try to create CFGs from a Linux C source file.

  On failure, an empty list is returned.

  Args:
    path: The path of the source file.

  Returns:
    A list of ControlFlowGraph instances.

  Raises:
    ClangException: If compiling to bytecode fails.
  """
  graphs = []

  try:
    bytecode, _ = BytecodeFromLinuxSrc(path, "-O0")
  except clang.ClangException:
    return graphs

  # Extract a dot sources from the bytecode.
  dot_generator = opt_util.DotControlFlowGraphsFromBytecode(bytecode)
  while True:
    try:
      dot = next(dot_generator)
      # Instantiate a CFG from the dot source.
      graph = llvm_util.ControlFlowGraphFromDotSource(dot)
      graph.ValidateControlFlowGraph(strict=False)
      graphs.append(graph)
    except (
      UnicodeDecodeError,
      cfg.MalformedControlFlowGraphError,
      ValueError,
      opt.OptException,
      pyparsing.ParseException,
    ):
      pass
    except StopIteration:
      break

  return graphs
Example #5
0
def CreateControlFlowGraphFromOpenClKernel(
        kernel_name: str,
        opencl_kernel: str) -> typing.Optional[cfg.ControlFlowGraph]:
    """Try to create a CFG proto from an opencl kernel.

  Args:
    kernel_name: The name of the OpenCL kernel defined in opencl_kernel.
    opencl_kernel: A string of OpenCL. This should contain a single kernel
      definition.

  Returns:
    A ControlFlowGraph instance, or None if compilation to bytecode fails.

  Raises:
    ClangException: If compiling to bytecode fails.
    ValueError: If opencl_kernel contains multiple functions.
  """
    bytecode, _ = BytecodeFromOpenClString(opencl_kernel, "-O0")

    # Extract a single dot source from the bytecode.
    dot_generator = opt_util.DotControlFlowGraphsFromBytecode(bytecode)
    dot = next(dot_generator)
    try:
        next(dot_generator)
        raise ValueError("Bytecode produced more than one dot source!")
    except StopIteration:
        pass

    # Instantiate a CFG from the dot source.
    graph = llvm_util.ControlFlowGraphFromDotSource(dot)

    # Set the name of the graph to the kernel name. This is because the src code
    # has been preprocessed, so that each kernel is named 'A'.
    graph.graph["name"] = kernel_name

    return graph
Example #6
0
  Returns:
    A list of ControlFlowGraph instances.

  Raises:
    ClangException: If compiling to bytecode fails.
  """
  graphs = []

  try:
    bytecode, _ = BytecodeFromLinuxSrc(path, "-O0")
  except clang.ClangException:
    return graphs

  # Extract a dot sources from the bytecode.
  dot_generator = opt_util.DotControlFlowGraphsFromBytecode(bytecode)
  while True:
    try:
      dot = next(dot_generator)
      # Instantiate a CFG from the dot source.
      graph = llvm_util.ControlFlowGraphFromDotSource(dot)
      graph.ValidateControlFlowGraph(strict=False)
      graphs.append(graph)
    except (
      UnicodeDecodeError,
      cfg.MalformedControlFlowGraphError,
      ValueError,
      opt.OptException,
      pyparsing.ParseException,
    ):
      pass
Example #7
0
def test_DotControlFlowGraphsFromBytecode_invalid_bytecode():
    """Test that exception is raised if bytecode is invalid."""
    with test.Raises(opt.OptException) as e_ctx:
        next(opt_util.DotControlFlowGraphsFromBytecode("invalid bytecode!"))
    assert e_ctx.value.returncode
    assert e_ctx.value.stderr