/* -*- c-file-style: "GNU" -*- */
/*
 * Copyright (C) CNRS, INRIA, Université Bordeaux 1, Télécom SudParis
 * See COPYING in top-level directory.
 *
 *
 * opcode.c
 *
 * Determining the size to override (by computing the size of instructions) using the opcode library
 *
 *  Created on: 2 August 2011
 *      Author: dmartin
 */

#include <opcodes.h>
#include <tracing.h>
#include <bfd.h>
#include <dis-asm.h>
#include <stdlib.h>

int dummy_print(void *stream, const char *fmt);


/*
 * This function determines the size of instructions that will be replaced.
 * Output is the size of the replacement
 */
ssize_t opcode_get_overridden_size(bfd *abfd, pid_t child, word_uint symbol,
				   size_t trampoline_size) {
  size_t max_size = trampoline_size * 2;
  bfd_byte *code;
  struct disassemble_info i;

  if (max_size < 10)
    max_size = 10;

  code = (bfd_byte*) malloc(max_size);
  trace_read(child, symbol, code, max_size);
  INIT_DISASSEMBLE_INFO(i, NULL, dummy_print);

  i.arch = bfd_get_arch(abfd);
  i.mach = bfd_get_mach(abfd);
#if HAVE_BINUTILS_2_28_OR_OLDER
  disassembler_ftype disassemble = disassembler(abfd);
#else
  disassembler_ftype disassemble = disassembler(i.arch, bfd_big_endian(abfd), i.mach, abfd);
#endif

  i.buffer = code;
  i.buffer_vma = (unsigned long) i.buffer;
  i.buffer_length = max_size;

  ssize_t j;
  for (j = 0; j < trampoline_size;) {
    j += disassemble(i.buffer_vma + j, &i);
  }
  free(code);

  return j;
}

ssize_t get_overridden_size(void* bin, pid_t child, word_uint symbol,
			    size_t trampoline_size) {
  return opcode_get_overridden_size((bfd*) bin, child, symbol, trampoline_size);
}
