enum mix_cmd_result
mix_cmd_break_insert (char *command, char **argv, int argc)
{
  char *address = NULL;
  enum bp_type type = REG_BP;
  int temp_p = 0;
  int thread = -1;
  int ignore_count = 0;
  char *condition = NULL;
  char *requested_shlib = NULL;
  char realpath_buf[PATH_MAX];
  enum gdb_rc rc;
  int *indices = NULL;
  int pending = 0;
  struct gdb_exception e;
  struct gdb_events *old_hooks;
  enum opt
    {
      HARDWARE_OPT, TEMP_OPT /*, REGEXP_OPT */ , CONDITION_OPT,
      IGNORE_COUNT_OPT, THREAD_OPT, PENDING_OPT, SHLIB_OPT, LIST_OPT
    };
  static struct mix_opt opts[] =
  {
    {"h", HARDWARE_OPT, 0},
    {"t", TEMP_OPT, 0},
    {"c", CONDITION_OPT, 1},
    {"i", IGNORE_COUNT_OPT, 1},
    {"p", THREAD_OPT, 1},
    {"f", PENDING_OPT, 0},
    {"s", SHLIB_OPT, 1},
    {"l", LIST_OPT, 1},
    { 0, 0, 0 }
  };

  /* Parse arguments. It could be -r or -h or -t, <location> or ``--''
     to denote the end of the option list. */
  int optind = 0;
  char *optarg;
  struct cleanup *indices_cleanup = NULL;
  while (1)
    {
      int opt = mix_getopt ("mix_cmd_break_insert", argc, argv, opts, &optind, &optarg);
      if (opt < 0)
        break;
      switch ((enum opt) opt)
        {
        case TEMP_OPT:
          temp_p = 1;
          break;
        case HARDWARE_OPT:
          type = HW_BP;
          break;
#if 0
        case REGEXP_OPT:
          type = REGEXP_BP;
          break;
#endif
        case CONDITION_OPT:
          condition = optarg;
          break;
        case IGNORE_COUNT_OPT:
          ignore_count = atol (optarg);
          /* APPLE LOCAL: Same behavior as set_ignore_count().  */
          if (ignore_count < 0)
            ignore_count = 0;
          break;
        case THREAD_OPT:
          thread = atol (optarg);
          break;
        case PENDING_OPT:
          pending = 1;
          break;
        case SHLIB_OPT:
          requested_shlib = optarg;
          break;
        case LIST_OPT:
          {
            char *numptr;
            int nelem = 0, i;
            /* First count the number of elements, which is the
               number of spaces plus one.  */
            numptr = optarg;
            while (*numptr)
              {
                if (*numptr != ' ')
                  {
                    nelem++;
                    while (*numptr != ' ' && *numptr != '\0')
                      numptr++;
                  }
                else
                  numptr++;
              }

            if (nelem == 0)
              error ("mix_cmd_break_insert: Got index with no elements");

            indices = (int *) xmalloc ((nelem + 1) * sizeof (int *));
            indices_cleanup = make_cleanup (xfree, indices);

            /* Now extract the elements.  */

            numptr = optarg;
            i = 0;
            errno = 0;
            while (*numptr != '\0')
              {
                indices[i++] = strtol (numptr, &numptr, 10);
                if (errno == EINVAL)
                    error ("mix_cmd_break_insert: bad index at \"%s\"", numptr);
              }

            /* Since we aren't passing a number of elements, we terminate the
               indices by putting in a -1 element.  */
            
            indices[i] = -1;

            break;
          }
        }
    }

  if (optind >= argc)
    error (_("mix_cmd_break_insert: Missing <location>"));
  if (optind < argc - 1)
    error (_("mix_cmd_break_insert: Garbage following <location>"));
  address = argv[optind];

  /* APPLE LOCAL: realpath() the incoming shlib name, as we do with all
     objfile/dylib/executable names.  NB this condition is incorrect if
     we're passed something like "./foo.dylib", "../foo.dylib", or
     "~/bin/foo.dylib", but that shouldn't happen....  */
  if (requested_shlib && IS_ABSOLUTE_PATH (requested_shlib))
    {
      realpath (requested_shlib, realpath_buf);
      /* It'll be xstrdup()'ed down in the breakpoint command, so just point
         to the stack array until then. */
      requested_shlib = realpath_buf; 
    }

  /* Now we have what we need, let's insert the breakpoint! */
  if (! mi_breakpoint_observers_installed)
    {
      observer_attach_breakpoint_created (breakpoint_notify);
      observer_attach_breakpoint_modified (breakpoint_notify);
      observer_attach_breakpoint_deleted (breakpoint_notify);
      mi_breakpoint_observers_installed = 1;
    }

  mi_can_breakpoint_notify = 1;
  /* Make sure we restore hooks even if exception is thrown.  */
  TRY_CATCH (e, RETURN_MASK_ALL)
    {
      switch (type)
        {
        case REG_BP:
          set_breakpoint (address, condition,
                          0 /*hardwareflag */, temp_p,
                          thread, ignore_count,
                          pending);
          break;
        case HW_BP:
          set_breakpoint (address, condition,
                          1 /*hardwareflag */, temp_p,
                          thread, ignore_count,
                          pending);
          break;
#if 0
        case REGEXP_BP:
          if (temp_p)
            error (_("mix_cmd_break_insert: Unsupported tempoary regexp breakpoint"));
          else
            rbreak_command_wrapper (address, FROM_TTY);
          return MIX_CMD_DONE;
          break;
#endif
        default:
          internal_error (__FILE__, __LINE__,
                          _("mix_cmd_break_insert: Bad switch."));
        }
    }
  mi_can_breakpoint_notify = 0;
  if (e.reason < 0)
    throw_exception (e);

  return MIX_CMD_DONE;
}
Exemplo n.º 2
0
static void process_events(PluginData* data, PDReader* reader, PDWriter* writer) {
    uint32_t event;

    while ((event = PDRead_get_event(reader))) {
        switch (event) {
            //case PDEventType_getExceptionLocation : setExceptionLocation(plugin, writer); break;
            //case PDEventType_getCallstack : set_callstack(plugin, writer); break;

            case PDEventType_GetRegisters:
            {
                get_registers(data);
                break;
            }

            case PDEventType_GetCallstack:
            {
                if (should_send_command(data))
                    set_callstack(data, reader, writer);

                break;
            }

            case PDEventType_GetDisassembly:
            {
                if (should_send_command(data))
                    get_disassembly(data, reader, writer);

                break;
            }

            case PDEventType_GetMemory:
            {
                if (should_send_command(data))
                    get_memory(data, reader, writer);
                break;
            }

            case PDEventType_MenuEvent:
            {
                on_menu(data, reader);
                break;
            }

            case PDEventType_SetBreakpoint:
            {
                set_breakpoint(data, reader, writer);

                // if we add a breakpoint to VICE it will always stop but if we are already running when
                // adding the breakpoint we just force VICE to run again

                if (data->state == PDDebugState_Running)
                    send_command(data, "ret\n");

                break;
            }

            case PDEventType_DeleteBreakpoint:
            {
                del_breakpoint(data, reader, writer);
                break;
            }

            case PDEventType_SetExecutable:
            {
                //if (should_send_command(data))
                set_executable(data, reader);

                break;
            }
        }
    }
}
Exemplo n.º 3
0
void debugger_proc(pid_t child_proc, struct execute_context *ctx)
{
    /* about child process */
    int child_stat;
    kern_return_t kret;
    mach_port_t task;
    int wait_cnt = 0;
    char **args = ctx->passing_args;

    /* related analysys of target process binary. */
    int i;
    int nsym;
    int text_section;
    uint64_t text_section_offset;
    uint64_t text_section_size;
    uint64_t text_section_vmaddr;
    struct symbol_info *psymbol_table;
    int init = 0;
    struct breakpoint_entry top;

    int stack_depth = 0;

    /* error check */
    if (child_proc == 0 || child_proc == -1)	return;

    /* initialize */
    memset(&top, 0x00, sizeof(top));

    /* open the port (do as an administrator) */
    kret = task_for_pid(mach_task_self(), child_proc, &task);
    if (kret != KERN_SUCCESS) {
        fprintf(stderr, "task_for_pid() failed\n");
        fprintf(stderr, "%s\n", mach_error_string(kret));
        exit(0);
    }

    fprintf(stderr, "[Tracer] child_proc: %d\n", child_proc);
    /* main loop */
    while(waitpid(child_proc, &child_stat, WUNTRACED)) {    /* {{{ */
        char buffer[128];
        char w_buf[128];
        w_buf[0] = 0x90;	/* nop */

        if (WIFEXITED(child_stat)) {
            /* Child Process Terminated */
            fprintf(stderr, "[Tracer]  Process :%d Terminated\n", child_proc);
            return;
        }
        memset(buffer, 0x00, 128);
        if(wait_cnt == 0) {
            /* The First time trapped   {{{ */
            /* -- The debugee program has not been expanded.-- */
            /* -- 	lookup named symbol	-- */
            struct file_info bininfo;
            ud_t ud_obj;
            uint64_t previous_eip;
            uint64_t func_start_addr;
            uint64_t func_end_addr;

            nsym = get_func_table(args[0], &psymbol_table, &text_section, &text_section_offset, &text_section_size, &text_section_vmaddr);
            debug_printf("nsym: %d\n", nsym);
            debug_printf("text section = %d\n", text_section);
            debug_printf("text section offset: 0x%llx\n", text_section_offset);
            debug_printf("text section size: 0x%llx\n", text_section_size);
            debug_printf("text section vmaddr: 0x%llx\n", text_section_vmaddr);

            qsort(psymbol_table, nsym, sizeof(struct symbol_info), symbolinfo_comp);

            /* XXX for debugging  */
            /*display_symbol_table(psymbol_table, nsym);  */

            /* code analysys */
            map_binary(args[0], &bininfo);
            ud_init(&ud_obj);
            ud_set_input_buffer(&ud_obj, bininfo.top + text_section_offset, text_section_size);
            ud_set_mode(&ud_obj, 64);

            previous_eip = text_section_vmaddr;
            /* set breakpoint at the entry and exit points of functions */
            for(i = 0; i < nsym; i++) {
                /* Set breakpoints {{{ */
                if (is_exclude_func(psymbol_table + i) == 1) {
                    continue;
                }
                /* 1, specifying the region of the function */
                func_start_addr = psymbol_table[i].nlist64.n_value;
                if (i != nsym - 1) {
                    /* next section's entry point - 1 */
                    func_end_addr = psymbol_table[i + 1].nlist64.n_value;
                } else {
                    func_end_addr = text_section_vmaddr + text_section_size + 1;
                }
                printf("%s: 0x%llx --> 0x%llx\n", psymbol_table[i].name, func_start_addr, func_end_addr);
                /*
                if (strstr(psymbol_table[i].name, "main") != NULL) {
                    __asm__("int3");
                }
                */
                psymbol_table[i].ret_address_num = 0;

                previous_eip = ud_obj.pc + text_section_vmaddr;

                while(ud_disassemble(&ud_obj) && previous_eip < func_start_addr) {
                    previous_eip = ud_obj.pc + text_section_vmaddr;
                }
                while(ud_disassemble(&ud_obj) && previous_eip < func_end_addr) {
                    if (func_start_addr <= previous_eip && ud_obj.mnemonic == UD_Iret) {
                        set_breakpoint(task, previous_eip, &top);
                        psymbol_table[i].ret_inst_address[ psymbol_table[i].ret_address_num ] = previous_eip;
                        psymbol_table[i].ret_address_num++;
                    }
                    previous_eip = ud_obj.pc + text_section_vmaddr;
                }
                /*
                if (0 < psymbol_table[i].ret_address_num) {
                    set_breakpoint(task, psymbol_table[i].nlist64.n_value, &top);
                }
                */
                set_breakpoint(task, psymbol_table[i].nlist64.n_value, &top);
                /* }}} */
            }
            debug_printf("break point insert\n");
            unmap_binary(&bininfo);
            /* }}} */
        } else {
            /* {{{ */
            /* break point */
            /* 1, Get current address from RIP value.
            * 2, Find current function name by EIP, and Logging.
            * 3, Substitute original instruction code for current break point code(0x90).
            * 4, Decrement EIP value.
            * 5, Execute only one op-code.
            * 6, Substitute 0x90 for oroginal code (located in entrance of function).
            * */
            uint64_t rip;
            read_process_register_64(task, RIP, &rip);
            if (is_breakpoint(rip - 1, &top) == 1) {
                stack_depth = breakpoint_handler(task, rip - 1, psymbol_table, nsym, stack_depth);
                write_process_register_64(task, RIP, RELATIVE_VAL, -1);
                disable_breakpoint(task, rip - 1, &top);
                ptrace(PT_STEP, child_proc, (caddr_t)1, 0);
                set_breakpoint(task, rip - 1, &top);
            }
            /* }}} */
        }
        wait_cnt++;
        ptrace(PT_CONTINUE, child_proc, (caddr_t)1, 0);
    }   /* }}} */
}
Exemplo n.º 4
0
static struct breakpoint *
set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int size, int *err)
{
  struct breakpoint *bp;
  enum bkpt_type type;
  enum raw_bkpt_type raw_type;

  /* If we see GDB inserting a second code breakpoint at the same
     address, then either: GDB is updating the breakpoint's conditions
     or commands; or, the first breakpoint must have disappeared due
     to a shared library unload.  On targets where the shared
     libraries are handled by userspace, like SVR4, for example,
     GDBserver can't tell if a library was loaded or unloaded.  Since
     we refcount raw breakpoints, we must be careful to make sure GDB
     breakpoints never contribute more than one reference.  if we
     didn't do this, in case the previous breakpoint is gone due to a
     shared library unload, we'd just increase the refcount of the
     previous breakpoint at this address, but the trap was not planted
     in the inferior anymore, thus the breakpoint would never be hit.
     Note this must be careful to not create a window where
     breakpoints are removed from the target, for non-stop, in case
     the target can poke at memory while the program is running.  */
  if (z_type == Z_PACKET_SW_BP
      || z_type == Z_PACKET_HW_BP)
    {
      bp = find_gdb_breakpoint (z_type, addr, -1);

      if (bp != NULL)
	{
	  if (bp->raw->size != size)
	    {
	      /* A different size than previously seen.  The previous
		 breakpoint must be gone then.  */
	      bp->raw->inserted = -1;
	      delete_breakpoint (bp);
	      bp = NULL;
	    }
	  else if (z_type == Z_PACKET_SW_BP)
	    {
	      /* Check if the breakpoint is actually gone from the
		 target, due to an solib unload, for example.  Might
		 as well validate _all_ breakpoints.  */
	      validate_breakpoints ();

	      /* Breakpoints that don't pass validation are
		 deleted.  */
	      bp = find_gdb_breakpoint (z_type, addr, -1);
	    }
	}
    }
  else
    {
      /* Data breakpoints for the same address but different size are
	 expected.  GDB doesn't merge these.  The backend gets to do
	 that if it wants/can.  */
      bp = find_gdb_breakpoint (z_type, addr, size);
    }

  if (bp != NULL)
    {
      /* We already know about this breakpoint, there's nothing else
	 to do - GDB's reference is already accounted for.  Note that
	 whether the breakpoint inserted is left as is - we may be
	 stepping over it, for example, in which case we don't want to
	 force-reinsert it.  */
      return bp;
    }

  raw_type = Z_packet_to_raw_bkpt_type (z_type);
  type = Z_packet_to_bkpt_type (z_type);
  return set_breakpoint (type, raw_type, addr, size, NULL, err);
}