Пример #1
0
static CORE_ADDR
amd64_skip_prologue (CORE_ADDR start_pc)
{
  struct x86_frame_cache cache;
  CORE_ADDR pc, endaddr;

  x86_initialize_frame_cache (&cache, 8);

  if (find_pc_partial_function_no_inlined (start_pc, NULL, NULL, &endaddr) == 0)
    endaddr = start_pc + 512;  /* 512 bytes is more than enough.  */
  endaddr = refine_prologue_limit (start_pc, endaddr, 3);
  pc = x86_analyze_prologue (start_pc, endaddr, &cache);

  return pc;
}
Пример #2
0
enum mi_cmd_result
mi_cmd_disassemble (char *command, char **argv, int argc)
{
  int mixed_source_and_assembly;
  struct symtab *s;

  /* Which options have we processed ... */
  int file_seen = 0;
  int line_seen = 0;
  int start_seen = 0;
  int end_seen = 0;
  int num_seen = 0;
  int prev_seen = 0;
  int peeklimit_seen = 0;

  /* ... and their corresponding value. */
  char *file_string = NULL;
  int line_num = -1;
  int how_many = -1;
  CORE_ADDR low = 0;
  CORE_ADDR high = 0;
  CORE_ADDR start = 0;
  int prev = 0;
  int peeklimit = -1;

  /* Options processing stuff. */
  int optind = 0;
  char *optarg;
  enum opt
  {
    FILE_OPT, LINE_OPT, NUM_OPT, START_OPT, END_OPT, PREV_OPT, PEEKLIMIT_OPT
  };
  static struct mi_opt opts[] = {
    { "f", FILE_OPT, 1 },
    { "l", LINE_OPT, 1 },
    { "n", NUM_OPT, 1 },
    { "s", START_OPT, 1 },
    { "e", END_OPT, 1 },
    { "p", PREV_OPT, 1 },
    { "P", PEEKLIMIT_OPT, 1 },
    { NULL, 0, 0 }
  };

  /* Get the options with their arguments. Keep track of what we
     encountered. */
  while (1)
    {
      int opt = mi_getopt ("mi_cmd_disassemble", argc, argv, opts,
			   &optind, &optarg);
      if (opt < 0)
	break;
      switch ((enum opt)opt)
	{
	case FILE_OPT:
	  file_string = xstrdup(optarg);
	  file_seen = 1;
	  break;
	case LINE_OPT:
	  line_num = atoi(optarg);
	  line_seen = 1;
	  break;
	case NUM_OPT:
	  how_many = atoi(optarg);
	  num_seen = 1;
	  break;
	case START_OPT:
	  start = parse_and_eval_address(optarg);
	  start_seen = 1;
	  break;
	case END_OPT:
	  high = parse_and_eval_address(optarg);
	  end_seen = 1;
	  break;
	case PREV_OPT:
	  prev = atoi(optarg);
	  prev_seen = 1;
	  break;
	case PEEKLIMIT_OPT:
	  peeklimit = atoi(optarg);
	  peeklimit_seen = 1;
	  break;
	default:
	  break;
	}
    }
  argv += optind;
  argc -= optind;

  if (argc < 1)
    mi_cmd_disassemble_usage ("Must specify mixed mode argument.");
  if (argc > 1)
    mi_cmd_disassemble_usage ("Extra arguments present.");

  if ((argv[0][0] == '\0') || (argv[0][1] != '\0'))
    mi_cmd_disassemble_usage ("Mixed mode argument must be 0 or 1.");
  if ((argv[0][0] != '0') && (argv[0][0] != '1'))
    mi_cmd_disassemble_usage ("Mixed mode argument must be 0 or 1.");
  mixed_source_and_assembly = (argv[0][0] == '1');

  if (start_seen && line_seen)
    mi_cmd_disassemble_usage ("May not specify both a line number and a start address.");

  if ((line_seen && !file_seen) || (file_seen && !line_seen))
    mi_cmd_disassemble_usage ("File and line number must be specified together.");

  if (line_seen && file_seen)
    {
      s = lookup_symtab (file_string);
      if (s == NULL)
	error ("mi_cmd_disassemble: Invalid filename.");
      if (! find_line_pc (s, line_num, &start))
	error ("mi_cmd_disassemble: Invalid line number.");
    }
  else if (! start_seen)
    mi_cmd_disassemble_usage ("No starting point specified.");

  if (end_seen)
    {
      if (num_seen || prev_seen)
	mi_cmd_disassemble_usage ("May not specify both an ending address and -n or -p.");

      gdb_disassembly (uiout, start, high, mixed_source_and_assembly, how_many);
      return MI_CMD_DONE;
    }

  if (find_pc_partial_function_no_inlined (start, NULL, &low, &high) == 0)
    error ("mi_cmd_disassemble: No function contains the specified address.");

  if (! num_seen)
    {
      /* If only the start address is given, disassemble the entire
	 function around the start address.  */

      gdb_disassembly(uiout, low, high, mixed_source_and_assembly, how_many);
      return MI_CMD_DONE;
    }

  /* And finally, now we know start_seen, !line_seen, !file_seen, !end_seen, and num_seen. */

  if (prev_seen)
    {
      CORE_ADDR tmp;
      int ret;

      if (peeklimit_seen >= 1)
        ret = find_pc_offset(start, &tmp, -prev, 1, peeklimit);
      else
        ret = find_pc_offset(start, &tmp, -prev, 1, -1);
      if ((ret != -1) && (tmp != INVALID_ADDRESS))
	start = tmp;
    }

  gdb_disassembly(uiout, start, high, mixed_source_and_assembly, how_many);
  return MI_CMD_DONE;
}
Пример #3
0
int
find_pc_offset(CORE_ADDR start, CORE_ADDR *result, int offset,
               int funclimit, int peeklimit)
{
  CORE_ADDR low = INVALID_ADDRESS;
  CORE_ADDR high = INVALID_ADDRESS;
  CORE_ADDR cur;
  CORE_ADDR constrained;

  int length;

  struct disassemble_info di = gdb_disassemble_info_null(current_gdbarch);
  CORE_ADDR *addrs = NULL;
  unsigned int index;
  struct cleanup *cleanup = NULL;

  *result = INVALID_ADDRESS;
  cur = start;

  /* If we are constraining the address to stay in the same function,
     we need to be able to find its boundaries. */

  if (funclimit)
    {
      if (find_pc_partial_function_no_inlined(start, NULL, &low, &high) == 0)
	{
	  /* We were unable to find the start of the function. */
	  return -1;
	}
    }

  /* If the architecture has fixed-sized instructions, just use simple
     arithmetic. */

  length = gdbarch_instruction_length(current_gdbarch);
  if (length > 0)
    {
      cur = (start + (length * offset));

      /* Constrain to be within the function limits if appropriate. */
      if (funclimit && (cur > high))
	constrained = high;
      else if (funclimit && (cur < low))
	constrained = low;
      else
	constrained = cur;

      /* Return 1 if we constrained the address; 0 otherwise. */
      *result = constrained;
      return (constrained != cur);
    }

  /* From here, we must assume variable-sized instructions. */

  if ((! funclimit) && (offset < 0))
    {
      /* FIXME: We don't support seeking backwards past the beginning
	 of a function. */
      return -1;
    }

  /* If we have a positive offset, start seeking forward until we are
     either done, or reach the end of the function. */

  cur = start;
  while (offset > 0)
    {
      cur += TARGET_PRINT_INSN(cur, &di);
      offset--;

      if (funclimit && (cur > high))
	{
	  /* We went past the end of the function without ever
	     reaching the purportedly final instruction. */
	  return -1;
	}

      if (funclimit && (cur == high))
	{
	  /* We reached the end of the function.  Return 1 if we had
	     to constrain the address; 0 otherwise. */
	  *result = cur;
	  return (offset > 0);
	}
    }

  if (offset == 0)
    {
      *result = cur;
      return 0;
    }

  /* From here out we can assume we are doing a negative offset. */

  gdb_assert(low <= start);
  gdb_assert(offset < 0);

  /* A sanity check:  If we've stepped into some area of memory where
     gdb doesn't have symbols and the GUI requests we disassemble from $pc,
     gdb can come up with very large LOW-HIGH regions of memory to disassemble
     through.  As a sanity check, if this function starts four pages before
     the given $pc and we're in MI mode (so we have a GUI that may be
     requesting nonsensical things), shortcircuit this operation.  */

  if (((off_t)(start - low) > -offset) && ((start - low) > 16384)
      && ui_out_is_mi_like_p(uiout))
    {
      *result = start;
      return 1;
    }

  /* There's no point searching for more instructions slots than there
     are bytes.  If we were given a PEEKLIMIT of -1, or a PEEKLIMIT
     higher than we need, set it to the number of bytes from the start
     of the function. */

  if ((peeklimit < 0) || ((CORE_ADDR)peeklimit > (start - low)))
    peeklimit = (int)(start - low);

  /* If PEEKLIMIT is less than (start - low), we can still attempt the
     search --- maybe enough of the instruction stream will be
     multi-byte that we'll find our address regardless. */

  addrs = (CORE_ADDR *)xmalloc(peeklimit * sizeof(CORE_ADDR));
  cleanup = make_cleanup(xfree, addrs);

  /* We can assume that we are constrained to the current function at
     this point (see the comment above). */

  gdb_assert(funclimit);

  cur = low;
  index = 0;

  /* Seek forward until we either reach our starting point, or reach
     PEEKLIMIT. */

  for (;;)
    {
      if (cur >= start)
	break;
      if (index >= (unsigned int)peeklimit)
	break;

      gdb_assert((int)index < peeklimit);
      addrs[index++] = cur;
      cur += TARGET_PRINT_INSN(cur, &di);
    }

  if (cur == start)
    {
      /* We were able to seek all the way forward to the start address. */

      gdb_assert(funclimit);
      gdb_assert(offset < 0);

      if ((off_t)index < -offset)
	{
	  /* We weren't able to go far enough back; return the earliest
             instruction of the function.  */
	  *result = low;
	  do_cleanups(cleanup);
	  return 1;
	}
      else
	{
	  *result = addrs[index + offset];
	  do_cleanups(cleanup);
	  return 0;
	}
    }

  if (cur > start)
    {
      /* We seeked forward right past the start address, without ever
	 hitting it. */
      do_cleanups(cleanup);
      return -1;
    }

  if (index >= (unsigned int)peeklimit)
    {
      /* We went past PEEKLIMIT instructions, and hence, weren't able
	 to complete the backwards seek.  */
      do_cleanups(cleanup);
      return -1;
    }

  internal_error(__FILE__, __LINE__, "should never have reached here");
  do_cleanups(cleanup);
  return -1;
}