Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/kernel/debug/kdb/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 11 kB image not shown  

Quelle  kdb_bp.c   Sprache: C

 
/*
 * Kernel Debugger Architecture Independent Breakpoint Handler
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (c) 1999-2004 Silicon Graphics, Inc.  All Rights Reserved.
 * Copyright (c) 2009 Wind River Systems, Inc.  All Rights Reserved.
 */


#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/kdb.h>
#include <linux/kgdb.h>
#include <linux/smp.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include "kdb_private.h"

/*
 * Table of kdb_breakpoints
 */

kdb_bp_t kdb_breakpoints[KDB_MAXBPT];

static void kdb_setsinglestep(struct pt_regs *regs)
{
 KDB_STATE_SET(DOING_SS);
}

static char *kdb_rwtypes[] = {
 "Instruction(i)",
 "Instruction(Register)",
 "Data Write",
 "I/O",
 "Data Access"
};

static char *kdb_bptype(kdb_bp_t *bp)
{
 if (bp->bp_type < 0 || bp->bp_type > 4)
  return "";

 return kdb_rwtypes[bp->bp_type];
}

static int kdb_parsebp(int argc, const char **argv, int *nextargp, kdb_bp_t *bp)
{
 int nextarg = *nextargp;
 int diag;

 bp->bph_length = 1;
 if ((argc + 1) != nextarg) {
  if (strncasecmp(argv[nextarg], "datar"sizeof("datar")) == 0)
   bp->bp_type = BP_ACCESS_WATCHPOINT;
  else if (strncasecmp(argv[nextarg], "dataw"sizeof("dataw")) == 0)
   bp->bp_type = BP_WRITE_WATCHPOINT;
  else if (strncasecmp(argv[nextarg], "inst"sizeof("inst")) == 0)
   bp->bp_type = BP_HARDWARE_BREAKPOINT;
  else
   return KDB_ARGCOUNT;

  bp->bph_length = 1;

  nextarg++;

  if ((argc + 1) != nextarg) {
   unsigned long len;

   diag = kdbgetularg((char *)argv[nextarg],
        &len);
   if (diag)
    return diag;


   if (len > 8)
    return KDB_BADLENGTH;

   bp->bph_length = len;
   nextarg++;
  }

  if ((argc + 1) != nextarg)
   return KDB_ARGCOUNT;
 }

 *nextargp = nextarg;
 return 0;
}

static int _kdb_bp_remove(kdb_bp_t *bp)
{
 int ret = 1;
 if (!bp->bp_installed)
  return ret;
 if (!bp->bp_type)
  ret = dbg_remove_sw_break(bp->bp_addr);
 else
  ret = arch_kgdb_ops.remove_hw_breakpoint(bp->bp_addr,
    bp->bph_length,
    bp->bp_type);
 if (ret == 0)
  bp->bp_installed = 0;
 return ret;
}

static void kdb_handle_bp(struct pt_regs *regs, kdb_bp_t *bp)
{
 if (KDB_DEBUG(BP))
  kdb_printf("regs->ip = 0x%lx\n", instruction_pointer(regs));

 /*
 * Setup single step
 */

 kdb_setsinglestep(regs);

 /*
 * Reset delay attribute
 */

 bp->bp_delay = 0;
 bp->bp_delayed = 1;
}

static int _kdb_bp_install(struct pt_regs *regs, kdb_bp_t *bp)
{
 int ret;
 /*
 * Install the breakpoint, if it is not already installed.
 */


 if (KDB_DEBUG(BP))
  kdb_printf("%s: bp_installed %d\n",
      __func__, bp->bp_installed);
 if (!KDB_STATE(SSBPT))
  bp->bp_delay = 0;
 if (bp->bp_installed)
  return 1;
 if (bp->bp_delay || (bp->bp_delayed && KDB_STATE(DOING_SS))) {
  if (KDB_DEBUG(BP))
   kdb_printf("%s: delayed bp\n", __func__);
  kdb_handle_bp(regs, bp);
  return 0;
 }
 if (!bp->bp_type)
  ret = dbg_set_sw_break(bp->bp_addr);
 else
  ret = arch_kgdb_ops.set_hw_breakpoint(bp->bp_addr,
    bp->bph_length,
    bp->bp_type);
 if (ret == 0) {
  bp->bp_installed = 1;
 } else {
  kdb_printf("%s: failed to set breakpoint at 0x%lx\n",
      __func__, bp->bp_addr);
  if (!bp->bp_type) {
   kdb_printf("Software breakpoints are unavailable.\n"
       " Boot the kernel with rodata=off\n"
       " OR use hw breaks: help bph\n");
  }
  return 1;
 }
 return 0;
}

/*
 * kdb_bp_install
 *
 * Install kdb_breakpoints prior to returning from the
 * kernel debugger.  This allows the kdb_breakpoints to be set
 * upon functions that are used internally by kdb, such as
 * printk().  This function is only called once per kdb session.
 */

void kdb_bp_install(struct pt_regs *regs)
{
 int i;

 for (i = 0; i < KDB_MAXBPT; i++) {
  kdb_bp_t *bp = &kdb_breakpoints[i];

  if (KDB_DEBUG(BP)) {
   kdb_printf("%s: bp %d bp_enabled %d\n",
       __func__, i, bp->bp_enabled);
  }
  if (bp->bp_enabled)
   _kdb_bp_install(regs, bp);
 }
}

/*
 * kdb_bp_remove
 *
 * Remove kdb_breakpoints upon entry to the kernel debugger.
 *
 * Parameters:
 * None.
 * Outputs:
 * None.
 * Returns:
 * None.
 * Locking:
 * None.
 * Remarks:
 */

void kdb_bp_remove(void)
{
 int i;

 for (i = KDB_MAXBPT - 1; i >= 0; i--) {
  kdb_bp_t *bp = &kdb_breakpoints[i];

  if (KDB_DEBUG(BP)) {
   kdb_printf("%s: bp %d bp_enabled %d\n",
       __func__, i, bp->bp_enabled);
  }
  if (bp->bp_enabled)
   _kdb_bp_remove(bp);
 }
}


/*
 * kdb_printbp
 *
 * Internal function to format and print a breakpoint entry.
 *
 * Parameters:
 * None.
 * Outputs:
 * None.
 * Returns:
 * None.
 * Locking:
 * None.
 * Remarks:
 */


static void kdb_printbp(kdb_bp_t *bp, int i)
{
 kdb_printf("%s ", kdb_bptype(bp));
 kdb_printf("BP #%d at ", i);
 kdb_symbol_print(bp->bp_addr, NULL, KDB_SP_DEFAULT);

 if (bp->bp_enabled)
  kdb_printf("\n is enabled ");
 else
  kdb_printf("\n is disabled");

 kdb_printf(" addr at %016lx, hardtype=%d installed=%d\n",
     bp->bp_addr, bp->bp_type, bp->bp_installed);

 kdb_printf("\n");
}

/*
 * kdb_bp
 *
 * Handle the bp commands.
 *
 * [bp|bph] <addr-expression> [DATAR|DATAW]
 *
 * Parameters:
 * argc Count of arguments in argv
 * argv Space delimited command line arguments
 * Outputs:
 * None.
 * Returns:
 * Zero for success, a kdb diagnostic if failure.
 * Locking:
 * None.
 * Remarks:
 *
 * bp Set breakpoint on all cpus.  Only use hardware assist if need.
 * bph Set breakpoint on all cpus.  Force hardware register
 */


static int kdb_bp(int argc, const char **argv)
{
 int i, bpno;
 kdb_bp_t *bp, *bp_check;
 int diag;
 char *symname = NULL;
 long offset = 0ul;
 int nextarg;
 kdb_bp_t template = {0};

 if (argc == 0) {
  /*
 * Display breakpoint table
 */

  for (bpno = 0, bp = kdb_breakpoints; bpno < KDB_MAXBPT;
       bpno++, bp++) {
   if (bp->bp_free)
    continue;
   kdb_printbp(bp, bpno);
  }

  return 0;
 }

 nextarg = 1;
 diag = kdbgetaddrarg(argc, argv, &nextarg, &template.bp_addr,
        &offset, &symname);
 if (diag)
  return diag;
 if (!template.bp_addr)
  return KDB_BADINT;

 /*
 * This check is redundant (since the breakpoint machinery should
 * be doing the same check during kdb_bp_install) but gives the
 * user immediate feedback.
 */

 diag = kgdb_validate_break_address(template.bp_addr);
 if (diag)
  return diag;

 /*
 * Find an empty bp structure to allocate
 */

 for (bpno = 0, bp = kdb_breakpoints; bpno < KDB_MAXBPT; bpno++, bp++) {
  if (bp->bp_free)
   break;
 }

 if (bpno == KDB_MAXBPT)
  return KDB_TOOMANYBPT;

 if (strcmp(argv[0], "bph") == 0) {
  template.bp_type = BP_HARDWARE_BREAKPOINT;
  diag = kdb_parsebp(argc, argv, &nextarg, &template);
  if (diag)
   return diag;
 } else {
  template.bp_type = BP_BREAKPOINT;
 }

 /*
 * Check for clashing breakpoints.
 *
 * Note, in this design we can't have hardware breakpoints
 * enabled for both read and write on the same address.
 */

 for (i = 0, bp_check = kdb_breakpoints; i < KDB_MAXBPT;
      i++, bp_check++) {
  if (!bp_check->bp_free &&
      bp_check->bp_addr == template.bp_addr) {
   kdb_printf("You already have a breakpoint at "
       kdb_bfd_vma_fmt0 "\n"template.bp_addr);
   return KDB_DUPBPT;
  }
 }

 template.bp_enabled = 1;

 /*
 * Actually allocate the breakpoint found earlier
 */

 *bp = template;
 bp->bp_free = 0;

 kdb_printbp(bp, bpno);

 return 0;
}

/*
 * kdb_bc
 *
 * Handles the 'bc', 'be', and 'bd' commands
 *
 * [bd|bc|be] <breakpoint-number>
 * [bd|bc|be] *
 *
 * Parameters:
 * argc Count of arguments in argv
 * argv Space delimited command line arguments
 * Outputs:
 * None.
 * Returns:
 * Zero for success, a kdb diagnostic for failure
 * Locking:
 * None.
 * Remarks:
 */

static int kdb_bc(int argc, const char **argv)
{
 unsigned long addr;
 kdb_bp_t *bp = NULL;
 int lowbp = KDB_MAXBPT;
 int highbp = 0;
 int done = 0;
 int i;
 int diag = 0;

 int cmd;   /* KDBCMD_B? */
#define KDBCMD_BC 0
#define KDBCMD_BE 1
#define KDBCMD_BD 2

 if (strcmp(argv[0], "be") == 0)
  cmd = KDBCMD_BE;
 else if (strcmp(argv[0], "bd") == 0)
  cmd = KDBCMD_BD;
 else
  cmd = KDBCMD_BC;

 if (argc != 1)
  return KDB_ARGCOUNT;

 if (strcmp(argv[1], "*") == 0) {
  lowbp = 0;
  highbp = KDB_MAXBPT;
 } else {
  diag = kdbgetularg(argv[1], &addr);
  if (diag)
   return diag;

  /*
 * For addresses less than the maximum breakpoint number,
 * assume that the breakpoint number is desired.
 */

  if (addr < KDB_MAXBPT) {
   lowbp = highbp = addr;
   highbp++;
  } else {
   for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT;
       i++, bp++) {
    if (bp->bp_addr == addr) {
     lowbp = highbp = i;
     highbp++;
     break;
    }
   }
  }
 }

 /*
 * Now operate on the set of breakpoints matching the input
 * criteria (either '*' for all, or an individual breakpoint).
 */

 for (bp = &kdb_breakpoints[lowbp], i = lowbp;
     i < highbp;
     i++, bp++) {
  if (bp->bp_free)
   continue;

  done++;

  switch (cmd) {
  case KDBCMD_BC:
   bp->bp_enabled = 0;

   kdb_printf("Breakpoint %d at "
       kdb_bfd_vma_fmt " cleared\n",
       i, bp->bp_addr);

   bp->bp_addr = 0;
   bp->bp_free = 1;

   break;
  case KDBCMD_BE:
   if (bp->bp_enabled)
    break;

   bp->bp_enabled = 1;

   kdb_printf("Breakpoint %d at "
       kdb_bfd_vma_fmt " enabled\n",
       i, bp->bp_addr);

   break;
  case KDBCMD_BD:
   if (!bp->bp_enabled)
    break;

   bp->bp_enabled = 0;

   kdb_printf("Breakpoint %d at "
       kdb_bfd_vma_fmt " disabled\n",
       i, bp->bp_addr);

   break;
  }
  if (bp->bp_delay && (cmd == KDBCMD_BC || cmd == KDBCMD_BD)) {
   bp->bp_delay = 0;
   KDB_STATE_CLEAR(SSBPT);
  }
 }

 return (!done) ? KDB_BPTNOTFOUND : 0;
}

/*
 * kdb_ss
 *
 * Process the 'ss' (Single Step) command.
 *
 * ss
 *
 * Parameters:
 * argc Argument count
 * argv Argument vector
 * Outputs:
 * None.
 * Returns:
 * KDB_CMD_SS for success, a kdb error if failure.
 * Locking:
 * None.
 * Remarks:
 *
 * Set the arch specific option to trigger a debug trap after the next
 * instruction.
 */


static int kdb_ss(int argc, const char **argv)
{
 if (argc != 0)
  return KDB_ARGCOUNT;
 /*
 * Set trace flag and go.
 */

 KDB_STATE_SET(DOING_SS);
 return KDB_CMD_SS;
}

static kdbtab_t bptab[] = {
 { .name = "bp",
  .func = kdb_bp,
  .usage = "[]",
  .help = "Set/Display breakpoints",
  .flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS,
 },
 { .name = "bl",
  .func = kdb_bp,
  .usage = "[]",
  .help = "Display breakpoints",
  .flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS,
 },
 { .name = "bc",
  .func = kdb_bc,
  .usage = "",
  .help = "Clear Breakpoint",
  .flags = KDB_ENABLE_FLOW_CTRL,
 },
 { .name = "be",
  .func = kdb_bc,
  .usage = "",
  .help = "Enable Breakpoint",
  .flags = KDB_ENABLE_FLOW_CTRL,
 },
 { .name = "bd",
  .func = kdb_bc,
  .usage = "",
  .help = "Disable Breakpoint",
  .flags = KDB_ENABLE_FLOW_CTRL,
 },
 { .name = "ss",
  .func = kdb_ss,
  .usage = "",
  .help = "Single Step",
  .minlen = 1,
  .flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS,
 },
};

static kdbtab_t bphcmd = {
 .name = "bph",
 .func = kdb_bp,
 .usage = "[]",
 .help = "[datar [length]|dataw [length]] Set hw brk",
 .flags = KDB_ENABLE_FLOW_CTRL | KDB_REPEAT_NO_ARGS,
};

/* Initialize the breakpoint table and register breakpoint commands. */

void __init kdb_initbptab(void)
{
 int i;
 kdb_bp_t *bp;

 /*
 * First time initialization.
 */

 memset(&kdb_breakpoints, '\0'sizeof(kdb_breakpoints));

 for (i = 0, bp = kdb_breakpoints; i < KDB_MAXBPT; i++, bp++)
  bp->bp_free = 1;

 kdb_register_table(bptab, ARRAY_SIZE(bptab));
 if (arch_kgdb_ops.flags & KGDB_HW_BREAKPOINT)
  kdb_register_table(&bphcmd, 1);
}

Messung V0.5
C=90 H=100 G=95

¤ Dauer der Verarbeitung: 0.5 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.