pike.git / src / modules / _Debug / debug.cmod

version» Context lines:

pike.git/src/modules/_Debug/debug.cmod:642:    pop_stack();    total++;    next = p->next;    sub_ref(p);    } else next = p->next;    p = next;    }    RETURN total;   }    + PIKECLASS debug_breakpoint { +  +  PIKEVAR program prog flags ID_PROTECTED|ID_PRIVATE; +  PIKEVAR string fname flags ID_PROTECTED|ID_PRIVATE; +  PIKEVAR string within_fname flags ID_PROTECTED|ID_PRIVATE; +  PIKEVAR int line_number flags ID_PROTECTED|ID_PRIVATE; +  PIKEVAR int enabled flags ID_PROTECTED|ID_PRIVATE; +  PIKEVAR int want_enabled flags ID_PROTECTED|ID_PRIVATE; +  +  CVAR struct debug_breakpoint * bp; +  +  PIKEFUN void create(string fname, int line_number) +  flags ID_PROTECTED; +  optflags OPT_SIDE_EFFECT; +  { +  THIS->fname = fname; +  THIS->within_fname = fname; +  THIS->line_number = line_number; +  add_ref(fname); +  add_ref(fname); +  } +  +  PIKEFUN void create(string fname, string within_fname, int line_number) +  flags ID_PROTECTED; +  optflags OPT_SIDE_EFFECT; +  { +  THIS->fname = fname; +  THIS->within_fname = within_fname; +  THIS->line_number = line_number; +  add_ref(fname); +  add_ref(within_fname); +  } +  +  PIKEFUN void create( + program p, string fname, int line_number) +  flags ID_PROTECTED; +  optflags OPT_SIDE_EFFECT; + { +  THIS->prog = p; +  THIS->fname = fname; +  THIS->within_fname = fname; +  THIS->line_number = line_number; +  add_ref(p); +  add_ref(fname); +  add_ref(fname); + } +  +  PIKEFUN void create( + program p, string fname, string within_file, int line_number) +  flags ID_PROTECTED; +  optflags OPT_SIDE_EFFECT; + { +  THIS->prog = p; +  THIS->fname = fname; +  THIS->within_fname = within_file; +  THIS->line_number = line_number; +  add_ref(p); +  add_ref(fname); +  add_ref(within_file); + } +  +  PIKEFUN program get_program() { +  if(THIS->prog) +  RETURN THIS->prog; +  else push_int(0); +  } +  +  PIKEFUN string get_filename() { +  add_ref(THIS->fname); /* it seems strange to need this, but whatever. */ +  RETURN THIS->fname; +  } +  +  PIKEFUN string get_within_file() { +  add_ref(THIS->within_fname); /* it seems strange to need this, but whatever. */ +  RETURN THIS->within_fname; +  } +  +  PIKEFUN int get_line_number() { +  RETURN THIS->line_number; +  } +  +  PIKEFUN int is_deferred() { +  RETURN ((THIS->prog) == NULL); +  } +  +  PIKEFUN int is_enabled() { +  RETURN THIS->enabled; +  } +  +  void low_disable_breakpoint() { +  struct debug_breakpoint * bp, *pbp; +  + #ifdef PIKE_DEBUG +  if((THIS->prog) && (bp = (THIS->prog->breakpoints)) != NULL) { +  while(bp != NULL) { +  if(bp == (THIS->bp)) { +  if(bp->next && bp->prev) { // somewhere in the middle, connect the previous and next. +  bp->prev->next = bp->next; +  bp->next->prev = bp->prev; +  } else if(bp->next) { // only next pointer: at the beginning, so make next the new first. +  bp->next->prev = NULL; +  THIS->prog->breakpoints = bp->next; +  } else if(bp->prev) { // only prev pointer: at the end, just unlink us. +  bp->prev->next = NULL; +  } else { +  THIS->prog->breakpoints = NULL; +  } +  pbp = bp; +  bp = bp->next; +  free(pbp); +  THIS->bp = NULL; +  } else { +  bp = bp->next; +  } +  }; +  } + #endif /* PIKE_DEBUG */ +  } +  +  ptrdiff_t low_add_breakpoint() { +  ptrdiff_t pc_offset; +  +  // TODO: we need to develop the line search further: a file can be included multiple times within a program, and so +  // in theory, a breakpoint for a line within a file could actually be multiple breakpoints. we stop at the first one. +  pc_offset = low_get_offset_for_line(THIS->prog, THIS->fname, THIS->line_number); +  if(!pc_offset) return -1; +  return pc_offset; +  } +  +  int low_enable_breakpoint() { +  ptrdiff_t offset; +  offset = low_get_offset_for_line(THIS->prog, THIS->within_fname, THIS->line_number); +  if(offset <= 0) return 0; +  + #ifdef PIKE_DEBUG +  struct debug_breakpoint * bp = malloc(sizeof(struct debug_breakpoint)); +  if(!bp) Pike_fatal("Unable to allocate memory for breakpoint\n"); +  if(THIS->prog->breakpoints) +  bp->next = THIS->prog->breakpoints; +  else +  bp->next = NULL; +  bp->prev = NULL; +  bp->offset = offset; +  THIS->prog->breakpoints = bp; +  THIS->bp = bp; +  THIS->enabled = 1; +  return 1; + #else +  return 0; + #endif /* PIKE_DEBUG */ +  } +  +  PIKEFUN int enable() { + #ifdef PIKE_DEBUG +  if(THIS->enabled) +  Pike_error("Breakpoint already enabled.\n"); +  /* This should eventually be a deferred breakpoint initialization. */ +  if(!(THIS->prog)) { +  THIS->want_enabled = 1; +  RETURN -1; +  } +  if (!low_enable_breakpoint()) RETURN 0; +  RETURN 1; + #else +  Pike_error("Cannot enable breakpoints if debug is not enabled.\n"); + #endif /*PIKE_DEBUG*/ +  } +  +  PIKEFUN int disable() { +  if(!(THIS->enabled)) +  Pike_error("Breakpoint not enabled.\n"); +  low_disable_breakpoint(); +  THIS->enabled = 0; +  } +  +  PIKEFUN int set_program(program prog) { +  // TODO it seems that entries for a given file in master()->programs can be set +  // multiple times, and that they are not always proper programs. we need to +  // attempt to understand that situation a little better. for now, this will weed +  // out attempts to set a program that we won't be able to look up an offset in. +  if(!(prog->program)) { +  RETURN 0; +  } +  +  if(THIS->enabled) { +  low_disable_breakpoint(); +  THIS->enabled = 0; +  } +  +  THIS->prog = prog; +  +  if(!low_enable_breakpoint()) +  RETURN 0; +  +  add_ref(prog); +  +  if(THIS->want_enabled) +  THIS->want_enabled = 0; +  +  RETURN 1; +  } +  +  EXIT { +  low_disable_breakpoint(); +  if(THIS->prog) +  free_program(THIS->prog); +  if(THIS->fname) +  free_string(THIS->fname); +  if(THIS->within_fname) +  free_string(THIS->within_fname); +  THIS->bp = NULL; /* should already have been freed by low_disable_breakpoint(). */ +  THIS->prog = NULL; +  THIS->fname = NULL; +  THIS->within_fname = NULL; +  THIS->line_number = 0; +  } + } +    /*! @endmodule    */      PIKE_MODULE_INIT   {    INIT;   #ifdef PIKE_DEBUG    ADD_INT_CONSTANT("HAVE_DEBUG", 1, 0);   #endif   }      PIKE_MODULE_EXIT   {    EXIT;   }