Exemple #1
0
/**
 * Signal handler for SIGTRAP 
 * @param signum
 * @param info
 * @param pcontext
 * @return
 */
void            e2dbg_sigtrap_handler(int signum, siginfo_t *info, void *pcontext)
{
  char		*argv[2];
  //ucontext_t	*context;
  e2dbgparams_t	params;

  CLRSIG;
  e2dbg_presence_set();

#if (__DEBUG_THREADS__ || __DEBUG_E2DBG__ || __DEBUG_MUTEX__)
  if (!e2dbg_presence_get())
    e2dbg_output(" [*] Debuggee in SIGTRAP handler\n");
  else 
    e2dbg_output(" [*] Debugger in SIGTRAP handler\n");
#endif

  //context = (ucontext_t *) pcontext;
  argv[0] = E2DBG_ARGV0;
  argv[1] = NULL;
  e2dbg_output(" [*] SIGTRAP : Entering E2dbg.\n");
  params.ac = 1;
  params.av = argv;
  e2dbg_entry(&params);
  e2dbg_presence_reset();
  SETSIG;
}
Exemple #2
0
/* Symbol matching on the stack content. Always useful */
int		e2dbg_stack_dump(uint32_t size, eresi_Addr start)
{
  long		*i;
  char		logbuf[BUFSIZ];
  char		*name;
  elfsh_SAddr	off;

  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);

  e2dbg_output(" .:: Stack ::.\n");
  
  /* Just a simple loop that dump resolved stack content */
  for (i = (long *) start; i < (long *) start + size; i++)
    {
      if ((eresi_Addr) i >= E2DBG_KERNELBASE)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__,
			  "Cannot dump anymore : end of stack", -1);

      name = revm_resolve(world.curjob->curfile, *i, &off);
      if (!name)
	name = "?";
      if (off)
	snprintf(logbuf, BUFSIZ - 1, " " XFMT " " XFMT " <%s + " DFMT "> \n", 
		 (eresi_Addr) i, (eresi_Addr) *i, name, off);
      else
	snprintf(logbuf, BUFSIZ - 1, " " XFMT " " XFMT " <%s> \n", 
		 (eresi_Addr) i, (eresi_Addr) *i, name);      
      e2dbg_output(logbuf);
    }
  e2dbg_output("\n");
  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0);
}
/* Watchpoint */
int		cmd_watch()
{
  int		idx;
  revmexpr_t	*addr;
  eresi_Addr	val;
  char		buff[BUFSIZ];

  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);

  /* List watchpoints */
  if (!world.curjob->curcmd->param[0])
    {
      e2dbg_output(" .:: Watchpoints ::.\n\n");
      for (idx = 0; e2dbgworld.tracedata[idx]; idx++)
	{
	  snprintf(buff, BUFSIZ, " [%u] %-40s ("XFMT")\n", 
		   idx, e2dbgworld.tracedstr[idx], e2dbgworld.tracedata[idx]);
	  e2dbg_output(buff);
	}
      PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0);
    }

  /* Put a new watchpoint */
  for (idx = 0; world.curjob->curcmd->param[idx]; idx++)
    {
      addr = revm_compute(world.curjob->curcmd->param[idx]);
      if (!addr || !addr->type || !addr->value)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		     "Invalid parameter", -1);
      if (addr->type->type != ASPECT_TYPE_LONG &&
	  addr->type->type != ASPECT_TYPE_CADDR &&
	  addr->type->type != ASPECT_TYPE_DADDR)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		     "Can watch only an address", -1);
      if (e2dbgworld.tdatanbr >= E2DBG_STEPCMD_MAX)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		     "Too many watch: cannot trace more", -1);
      val = (addr->value->immed ? addr->value->immed_val.ent : 
	     addr->value->get_obj(addr->value->parent));
      e2dbgworld.tracedata[e2dbgworld.tdatanbr] = val;
      e2dbgworld.tracedstr[e2dbgworld.tdatanbr] = strdup(world.curjob->curcmd->param[idx]);
      snprintf(buff, BUFSIZ, " [%u] Added watchpoint on address "XFMT" - (from %s)\n", 
	       e2dbgworld.tdatanbr, e2dbgworld.tracedata[e2dbgworld.tdatanbr], 
	       e2dbgworld.tracedstr[e2dbgworld.tdatanbr]);
      e2dbg_output(buff);
      e2dbgworld.tdatanbr++;
    }
  
  e2dbg_output("\n");
  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0);
}
Exemple #4
0
/* Print the registers state just before entering the breakpoint */
int		cmd_dumpregs()
{
  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);
  if (!e2dbgworld.curthread)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		      "No current thread available", (-1));
  if (!e2dbgworld.curthread->context)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		      "No context available", (-1));
  e2dbg_output(" .:: Registers ::. \n\n");
  e2dbg_setregs();
  e2dbg_printregs();
  e2dbg_output("\n");
  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (0));
}
Exemple #5
0
/** Reinstall a breakpoint */
void			e2dbg_breakpoint_reinstall()
{
  elfshbp_t		*bp;
  char			buf[32];
  int			ret;

  /* Test if we need to reinstall a breakpoint */
  snprintf(buf, sizeof(buf), XFMT, e2dbgworld.stoppedthread->past);
  bp = hash_get(&e2dbgworld.bp, buf);
  
  /* Call the architecture dependant hook for putting back the breakpoint */
  if (bp)
    {
      ret = e2dbg_setbreak(bp->obj, bp);
      if (ret < 0)
	{
	  e2dbg_output(" [E] Breakpoint reinsertion failed");
	  return;
	}
      
      //#if __DEBUG_BP__
      fprintf(stderr, " [D] Breakpoint reinserted at " AFMT " ! \n", bp->addr);
      //#endif
      
      e2dbgworld.stoppedthread->past = 0;
    }
  else
    fprintf(stderr, " [D] Breakpoint was deleted from " AFMT " : not reinstalling ! \n",
	    e2dbgworld.stoppedthread->past);
}
Exemple #6
0
/**
 * Signal handler for SIGSTOP 
 * @param signum
 * @param info
 * @param pcontext
 * @return
 */
void            e2dbg_sigstop_handler(int signum, siginfo_t *info, void *pcontext)
{
  char		*argv[2];
  e2dbgparams_t	params;
  e2dbgthread_t	*curthread;
  char		key[15];

  CLRSIG;
  e2dbg_presence_set();

#if __DEBUG_THREADS__
  printf("\n [*] SIGSTOP handler for thread %u \n", (unsigned int) e2dbg_self());
#endif

  /* Get the current thread */
  snprintf(key, sizeof(key), "%u", (unsigned int) e2dbg_self());
  curthread = hash_get(&e2dbgworld.threads, key);
  curthread->context = (ucontext_t *) pcontext;

  /* Set all registers as variables and get PC */
  //e2dbgworld.context = (ucontext_t *) pcontext;

  e2dbg_user_hooks_install();
  e2dbg_getregs();
  argv[0] = E2DBG_ARGV0;
  argv[1] = NULL;
  e2dbg_output(" [*] Interrupted, entering E2dbg ...\n");
  params.ac = 1;
  params.av = argv;
  e2dbg_entry(&params);
  e2dbg_presence_reset();
  SETSIG;
}
/* Find a breakpoint by various ways */
elfshbp_t	*e2dbg_breakpoint_lookup(char *name)
{
  eresi_Addr	addr;
  elfshbp_t	*bp;
  uint16_t	bpid;
  char		straddr[32];
  char		logbuf[BUFSIZ];

  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);
  bp = NULL;
  
  /* Lookup by vaddr */
  if (IS_VADDR(name))
    {
      
      if (sscanf(name + 2, AFMT, &addr) != 1)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__,
			  "Invalid virtual address requested", 
			  NULL);
    }

  /* Try to lookup by ID */
  else if (revm_isnbr(name))
    {
      bpid = atoi(name);
      bp   = e2dbg_breakpoint_from_id(bpid);
      if (!bp)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__,
                          "Invalid breakpoint ID", NULL);
    }

  /* Resolve symbol */
  /* Here we fix symbols on the disk only ! This avoid a mprotect */
  else
    {      
      addr = e2dbg_breakpoint_find_addr(name);
      if (!addr)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__,
			  "Requested symbol address unknown",
			  NULL);
    }

  /* Get the breakpoint */
  if (!bp)
    {
      snprintf(straddr, sizeof(straddr), XFMT, addr);
      bp = hash_get(&e2dbgworld.bp, straddr);
      if (!bp)
	{
	  snprintf(logbuf, BUFSIZ, 
		   "\n [!] No breakpoint set at addr " AFMT " \n\n", addr);
	  e2dbg_output(logbuf);
	  PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		       "No breakpoint at this address", NULL);
	}
    }

  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, bp);
}
Exemple #8
0
void		e2dbg_watch_check_ia32_sysv(u_int regidx, char *regstr)
{
  char		buff[BUFSIZ];
  u_int		idx;

  for (idx = 0; idx < E2DBG_STEPCMD_MAX && e2dbgworld.tracedata[idx]; idx++)
    if (e2dbgworld.curthread->context->uc_mcontext.gregs[regidx] == e2dbgworld.tracedata[idx])
      {
	snprintf(buff, BUFSIZ, " [*] TRACED %s ("XFMT") found in register %s \n", 
		 e2dbgworld.tracedstr[idx], e2dbgworld.tracedata[idx], regstr);
	e2dbg_output(buff);

	/* Disable stepping and tracing */
	if (e2dbgworld.curthread->trace)
	  e2dbg_step();
	e2dbgworld.curthread->trace = 0;
      }
}
Exemple #9
0
/** 
 * Load linkmap 
 * @param name
 * @return
 */
int			e2dbg_linkmap_load(char *name)
{
  static int		done	= 0;
  elfshsect_t		*got;
  eresi_Addr		*linkmap_entry;
  void			*data;
#if defined(sun)
  Link_map		*actual;
#else
  elfshlinkmap_t	*actual;
#endif
  char			*gotname;
  char			*ename;
  elfsh_Ehdr		*hdr;
  u_int			elftypenum;
  elfsh_Sym		*endsym;
  char			buff[64];

  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);
  if (done)
    PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0);    

#if __DEBUG_LINKMAP__
  fprintf(stderr, "[e2dbg] Starting Loading LINKMAP !! \n");
#endif

  e2dbg_user_hooks_install();
  revm_config(E2DBG_CONFIG);

  /* Load debugged file */
  if (name)
    {

      /* No need to fill ET_EXEC base addr */
      if (!revm_is_loaded(name) && revm_file_load(name, 0, NULL) < 0)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
			  "Cannot load file", -1);
      
#if __DEBUG_LINKMAP__
      fprintf(stderr, "[e2dbg_linkmap_load] file %s loaded\n", name);
#endif
      
      world.curjob->curfile->linkmap = E2DBG_DYNAMIC_LINKMAP;
      world.curjob->curfile->iotype  = ELFSH_IOTYPE_EMBEDDED;
      world.curjob->curfile->running = 0;
    }
  
#if __DEBUG_LINKMAP__
  fprintf(stderr, "[e2dbg_linkmap_load] Before switch\n");
#endif
  
  /* Switch to obj 1 */
  if (revm_doswitch(1) < 0)
    PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		 "Cannot switch on object 1", -1);    
  
#if __DEBUG_LINKMAP__
  fprintf(stderr, "[e2dbg_linkmap_load] After switch \n");
#endif
  
  /* Base address for PIE binaries have to be imported */
  if (world.curjob->curfile->hdr->e_type == ET_DYN &&
      !world.curjob->curfile->rhdr.base)
    {
#if __DEBUG_LINKMAP__
      fprintf(stderr, "[e2dbg_linkmap_load] Inside ET_DYN condition\n");
#endif

      endsym = elfsh_get_symbol_by_name(world.curjob->curfile, "_end");

      fprintf(stderr, "endsym = " AFMT " \n", (eresi_Addr) endsym);
      sleep(1);

#if __DEBUG_LINKMAP__
      fprintf(stderr, "[e2dbg_linkmap_load] Filling PIE base"
	      " (_end ondisk = " AFMT " / _end in memory = " AFMT ") ! \n",
	      endsym->st_value, e2dbgworld.syms.piebase);
#endif 

      world.curjob->curfile->rhdr.base = e2dbgworld.syms.piebase -
	endsym->st_value;
    }

  /* Get ALTGOT or GOT if we used LD_PRELOAD */
  if (!e2dbgworld.preloaded)
    {
      gotname = ELFSH_SECTION_NAME_ALTGOT;
      got = elfsh_get_section_by_name(world.curjob->curfile, 
				      gotname, NULL, NULL, NULL);
    }
  else
    got = elfsh_get_gotsct(world.curjob->curfile);

#if __DEBUG_LINKMAP__
  fprintf(stderr, "[e2dbg_linkmap_load] %s section at " XFMT "\n",
	  got->name, got->shdr->sh_addr);
  fprintf(stderr, "[e2dbg_linkmap_load] BASE = %08x\n", 
	  world.curjob->curfile->rhdr.base);
#endif
  
  
  /* Fix first file linkmap entry */
  if (world.curjob->curfile->linkmap == E2DBG_DYNAMIC_LINKMAP)
    {
      /* Fix first file linkmap entry */
      hdr = elfsh_get_hdr(world.curjob->curfile);
      if (!hdr)
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
			  "Cannot get ELF header", -1);    
      elftypenum = elfsh_get_objtype(hdr);
      
      //fprintf(stderr, "[e2dbg_linkmap_load] after ELF header \n");

      /* Get ALTGOT entry */
      data          = elfsh_readmem(got);

      //fprintf(stderr, "[e2dbg_linkmap_load] after get_raw (data = %08X) \n", data);

      linkmap_entry = elfsh_get_got_entry_by_index(data, 1);
      
      //fprintf(stderr, "[e2dbg_linkmap_load] after entry_by_index (linkmap_entry = %08x)\n",
      //      linkmap_entry);

#if defined(__FreeBSD__) || defined(__NetBSD__)
      world.curjob->curfile->linkmap = (elfshlinkmap_t *)
	&((Obj_Entry *) elfsh_get_got_val(linkmap_entry))->linkmap;
#elif defined(sun)
      world.curjob->curfile->linkmap = e2dbgworld.syms.map;
#else
      world.curjob->curfile->linkmap = (elfshlinkmap_t *) elfsh_get_got_val(linkmap_entry);
#endif
      
    }
  
#if __DEBUG_LINKMAP__
  else
    fprintf(stderr, "[e2dbg_linkmap_load] Linkmap was -NOT- dynamic\n");

  fprintf(stderr, "[e2dbg_linkmap_load] LINKMAP Found at " XFMT "\n", 
	 world.curjob->curfile->linkmap);
#endif

  revm_doswitch(1);
  
  /* now load all linkmap's files */
  for (actual = elfsh_linkmap_get_lprev(world.curjob->curfile->linkmap);
       actual != NULL; 
       actual = elfsh_linkmap_get_lprev(actual))
    {
      
#if __DEBUG_LINKMAP__
      fprintf(stderr, "[e2dbg_linkmap_load] Running on LINKMAP PREV " XFMT "\n", 
	     actual);
#endif
      
      ename = elfsh_linkmap_get_lname(actual);
      if (ename && *ename && !revm_is_loaded(ename))
	{
	  if (revm_file_load(ename,
			     elfsh_linkmap_get_laddr(actual), 
			     world.curjob->curfile->linkmap) < 0)
	    e2dbg_output(" [EE] Loading failed");
	  world.curjob->curfile->iotype  = ELFSH_IOTYPE_EMBEDDED;
	}      
    }

#if __DEBUG_LINKMAP__
  fprintf(stderr, "[e2dbg_linkmap_load] Running on LINKMAP NEXT\n");
#endif
  
  for (actual = elfsh_linkmap_get_lnext(world.curjob->curfile->linkmap);
       actual != NULL; 
       actual = elfsh_linkmap_get_lnext(actual))
    {

      ename = elfsh_linkmap_get_lname(actual);
     
#if __DEBUG_LINKMAP__
      fprintf(stderr, "[e2dbg_linkmap_load] Running on LINKMAP NEXT " XFMT " (%s baseaddr %08X) \n", 
	      actual, ename, actual->laddr);
#endif

      if (ename && *ename && !revm_is_loaded(ename))
	{
	  if (revm_file_load(ename, elfsh_linkmap_get_laddr(actual), 
			     world.curjob->curfile->linkmap) < 0)
	    e2dbg_output(" [EE] Loading failed");
	  world.curjob->curfile->iotype  = ELFSH_IOTYPE_EMBEDDED;
	}      
    }

  /* Everything was OK */
  e2dbg_output("\n");
  //elfsh_set_runtime_mode();
  revm_doswitch(1);

  snprintf(buff, sizeof(buff), " [*] Target PID = %u \n", getpid());
  e2dbg_output(buff);

  done = 1;
  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, 0);
}
Exemple #10
0
/**
 * SIGTRAP signal handler (The breakpoint routine). Save registers and callback. Multi-thread safe.
 * @param signum Received signal number.
 * @param info Signal info structure from breakpoint.
 * @param pcontext Context data pointer containing register values and more.
 * @return
*/
void			e2dbg_generic_breakpoint(int		signum, 
						 siginfo_t	*info, 
						 void		*pcontext)
{
  ucontext_t		*context;
  char			key[15];
  pthread_t		stopped;

  /* Do not allow processing of 2 breakpoint at the same time */
  /* We update the current thread information */
  e2dbg_presence_set();
  revm_proc_init();

  if (!e2dbgworld.curbp || e2dbgworld.curbp->tid != e2dbg_self())
    {
      e2dbg_mutex_lock(&e2dbgworld.dbgbp);

#if (__DEBUG_THREADS__ || __DEBUG_E2DBG__ || __DEBUG_MUTEX__ || __DEBUG_BP__)
      //e2dbg_output("-------------- ON-BREAK REGISTERS ----------------------->\n");
      //cmd_dumpregs();
      //e2dbg_output("<------------------------------------------------------\n");
      e2dbg_output("------------------------------------->\n");
      e2dbg_output(" [*] BP MUTEX LOCKED [e2dbg_generic_breakpoint] \n");
      //e2dbg_threads_print();
#endif
    }

  /* Get the current thread */
  stopped = (pthread_t) e2dbg_self();
  snprintf(key, sizeof(key), "%u", (unsigned int) stopped);
  e2dbgworld.curthread = hash_get(&e2dbgworld.threads, key);
  e2dbgworld.stoppedthread = e2dbgworld.curthread;
  
#if (__DEBUG_THREADS__ || __DEBUG_E2DBG__ || __DEBUG_MUTEX__ || __DEBUG_BP__)
  fprintf(stderr, "\n [*] Thread entering generic breakpoint (ID %u) \n",
	 (unsigned int) e2dbgworld.stoppedthread->tid);
  fflush(stdout);
#endif
  
  e2dbgworld.stoppedthread->state = E2DBG_THREAD_BREAKING;
  context = (ucontext_t *) pcontext;
  e2dbgworld.stoppedthread->context = context;

  /* We first get contexts for all other threads (except debugger) using SIGUSR2 */
  /* Then we stop all threads */
  /* We do this only at the first state (count = 0) of the breakpoint */
  if (!e2dbgworld.stoppedthread->count)
    {
      if (e2dbg_thread_stopall(SIGUSR2))
	usleep(100000);
    }
#if (__DEBUG_THREADS__ || __DEBUG_E2DBG__ || __DEBUG_MUTEX__ || __DEBUG_BP__)
  else
    fprintf(stderr, " NOT COLLECTING THREADS CONTEXTS (stopped thread %u state count = %u) \n", 
	    (u_int) e2dbgworld.stoppedthread->tid, e2dbgworld.stoppedthread->count);
#endif

  /* Call the real breakpoint code */
  e2dbg_breakpoint_process();

  /* Continue all threads */
  if (e2dbgworld.stoppedthread->count == E2DBG_BREAK_FINISHED || 
      e2dbgworld.curthread->step || e2dbgworld.curthread->was_step)
    {
      e2dbg_thread_contall();
      e2dbgworld.curthread->was_step = 0;
      e2dbgworld.stoppedthread->count = E2DBG_BREAK_NONE;
      e2dbgworld.curbp                = NULL;
  
      fprintf(stderr, " [D] Thread ID %lu now has Count = 0 (NONE) \n", e2dbgworld.curthread->tid);

      /* Allow another breakpoint to be processed */
      if (e2dbg_mutex_unlock(&e2dbgworld.dbgbp) != 0)
	e2dbg_output(" [*] Debuggee Cannot unlock breakpoint mutex ! \n");
#if (__DEBUG_THREADS__ || __DEBUG_E2DBG__ || __DEBUG_MUTEX__ || __DEBUG_BP__)
      else
	{
	  e2dbg_output(" [*] BP MUTEX UNLOCKED [e2dbg_generic_breakpoint] \n");
	  e2dbg_output("<-------------------------------------\n");
	}
#endif
    }

#if (__DEBUG_THREADS__ || __DEBUG_E2DBG__ || __DEBUG_MUTEX__ || __DEBUG_BP__)
  else
    fprintf(stderr, " [D] No SIGCONT as thread (%u) is stopped with state count = %u \n", 
	    (u_int) e2dbgworld.stoppedthread->tid, e2dbgworld.stoppedthread->count);
#endif

  e2dbgworld.stoppedthread->state = E2DBG_THREAD_RUNNING;
  e2dbg_presence_reset();
  SETSIG;

#if __DEBUG_BP__
  fprintf(stderr, " [D] Returning from generic signal handler\n");
#endif
}
/* Breakpoint command */
int		cmd_bp()
{
  char		*str;
  int		ret;
  eresi_Addr	addr;
  char		logbuf[BUFSIZ];
  int		idx;
  int		index;
  elfsh_SAddr	off = 0;
  char		*name;
  elfshbp_t	*cur;
  char		**keys;
  int		keynbr;

  PROFILER_IN(__FILE__, __FUNCTION__, __LINE__);

  /* build argc */
  for (idx = 0; world.curjob->curcmd->param[idx] != NULL; idx++);
  str = revm_lookup_string(world.curjob->curcmd->param[0]);

  /* Select subcommand */
  switch (idx)
    {
      
      /* List breakpoints */
      case 0:
	e2dbg_output(" .:: Breakpoints ::.\n\n");	      
	keys = hash_get_keys(&e2dbgworld.bp, &keynbr);
	for (index = 0; index < keynbr; index++)
	  {
	    cur = hash_get(&e2dbgworld.bp, keys[index]);
	    name = revm_resolve(world.curjob->curfile, 
				(eresi_Addr) cur->addr, &off);
	    if (off)
	      snprintf(logbuf, BUFSIZ, " %c [%02u] " XFMT " <%s + " UFMT ">\n", 
		       (e2dbg_is_watchpoint(cur) ? 'W' : 'B'),
		       cur->id, cur->addr, name, off);
	    else
	      snprintf(logbuf, BUFSIZ, " %c [%02u] " XFMT " <%s>\n", 
		       (e2dbg_is_watchpoint(cur) ? 'W' : 'B'),
		       cur->id, cur->addr, name);
	    e2dbg_output(logbuf);
	  }
	hash_free_keys(keys);
	if (!index)
	  e2dbg_output(" [*] No breakpoints\n");
	e2dbg_output("\n");
	break;
      
	/* Supply a new breakpoint */
      case 1:
	if (!elfsh_is_runtime_mode())
	  PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__,
		       "Not in dynamic or debugger mode", -1);
	if (!str || !(*str))
	  PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		       "Invalid argument", -1);
      
	/* Break on a supplied virtual address */
	if (IS_VADDR(str))
	  {
	    if (sscanf(str + 2, AFMT, &addr) != 1)
	      PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
			   "Invalid virtual address requested", (-1));
	  }
      
	/* Resolve first a function name */
	else
	  {
	    addr = e2dbg_breakpoint_find_addr(str);
	    if (addr == 0)
	      PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
			   "Requested symbol address unknown", -1);
	  }
      
	/* Add the breakpoint */
	ret = e2dbg_breakpoint_add(addr);
	if (ret < 0)
	  PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		       "Breakpoint insertion failed\n", (-1));
	if (ret >= 0)
	  {
	    name = revm_resolve(world.curjob->curfile, addr, &off);
	    if (!off)
	      snprintf(logbuf, BUFSIZ - 1, 
		       " [*] Breakpoint added at <%s> (" XFMT ")\n\n", name, addr);
	    else
	      snprintf(logbuf, BUFSIZ - 1, 
		       " [*] Breakpoint added at <%s + " UFMT "> (" XFMT ")\n\n", 
		       name, off, addr);
	    e2dbg_output(logbuf);
	  }
	break;

	/* Wrong command syntax */
      default:
	PROFILER_ERR(__FILE__, __FUNCTION__, __LINE__, 
		     "Wrong arg number", (-1));
    }

  PROFILER_ROUT(__FILE__, __FUNCTION__, __LINE__, (ret));
}