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

Quelle  kgdb.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * AArch64 KGDB support
 *
 * Based on arch/arm/kernel/kgdb.c
 *
 * Copyright (C) 2013 Cavium Inc.
 * Author: Vijaya Kumar K <vijaya.kumar@caviumnetworks.com>
 */


#include <linux/bug.h>
#include <linux/irq.h>
#include <linux/kdebug.h>
#include <linux/kgdb.h>
#include <linux/kprobes.h>
#include <linux/sched/task_stack.h>

#include <asm/debug-monitors.h>
#include <asm/insn.h>
#include <asm/text-patching.h>
#include <asm/traps.h>

struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = {
 { "x0", 8, offsetof(struct pt_regs, regs[0])},
 { "x1", 8, offsetof(struct pt_regs, regs[1])},
 { "x2", 8, offsetof(struct pt_regs, regs[2])},
 { "x3", 8, offsetof(struct pt_regs, regs[3])},
 { "x4", 8, offsetof(struct pt_regs, regs[4])},
 { "x5", 8, offsetof(struct pt_regs, regs[5])},
 { "x6", 8, offsetof(struct pt_regs, regs[6])},
 { "x7", 8, offsetof(struct pt_regs, regs[7])},
 { "x8", 8, offsetof(struct pt_regs, regs[8])},
 { "x9", 8, offsetof(struct pt_regs, regs[9])},
 { "x10", 8, offsetof(struct pt_regs, regs[10])},
 { "x11", 8, offsetof(struct pt_regs, regs[11])},
 { "x12", 8, offsetof(struct pt_regs, regs[12])},
 { "x13", 8, offsetof(struct pt_regs, regs[13])},
 { "x14", 8, offsetof(struct pt_regs, regs[14])},
 { "x15", 8, offsetof(struct pt_regs, regs[15])},
 { "x16", 8, offsetof(struct pt_regs, regs[16])},
 { "x17", 8, offsetof(struct pt_regs, regs[17])},
 { "x18", 8, offsetof(struct pt_regs, regs[18])},
 { "x19", 8, offsetof(struct pt_regs, regs[19])},
 { "x20", 8, offsetof(struct pt_regs, regs[20])},
 { "x21", 8, offsetof(struct pt_regs, regs[21])},
 { "x22", 8, offsetof(struct pt_regs, regs[22])},
 { "x23", 8, offsetof(struct pt_regs, regs[23])},
 { "x24", 8, offsetof(struct pt_regs, regs[24])},
 { "x25", 8, offsetof(struct pt_regs, regs[25])},
 { "x26", 8, offsetof(struct pt_regs, regs[26])},
 { "x27", 8, offsetof(struct pt_regs, regs[27])},
 { "x28", 8, offsetof(struct pt_regs, regs[28])},
 { "x29", 8, offsetof(struct pt_regs, regs[29])},
 { "x30", 8, offsetof(struct pt_regs, regs[30])},
 { "sp", 8, offsetof(struct pt_regs, sp)},
 { "pc", 8, offsetof(struct pt_regs, pc)},
 /*
 * struct pt_regs thinks PSTATE is 64-bits wide but gdb remote
 * protocol disagrees. Therefore we must extract only the lower
 * 32-bits. Look for the big comment in asm/kgdb.h for more
 * detail.
 */

 { "pstate", 4, offsetof(struct pt_regs, pstate)
#ifdef CONFIG_CPU_BIG_ENDIAN
       + 4
#endif
 },
 { "v0", 16, -1 },
 { "v1", 16, -1 },
 { "v2", 16, -1 },
 { "v3", 16, -1 },
 { "v4", 16, -1 },
 { "v5", 16, -1 },
 { "v6", 16, -1 },
 { "v7", 16, -1 },
 { "v8", 16, -1 },
 { "v9", 16, -1 },
 { "v10", 16, -1 },
 { "v11", 16, -1 },
 { "v12", 16, -1 },
 { "v13", 16, -1 },
 { "v14", 16, -1 },
 { "v15", 16, -1 },
 { "v16", 16, -1 },
 { "v17", 16, -1 },
 { "v18", 16, -1 },
 { "v19", 16, -1 },
 { "v20", 16, -1 },
 { "v21", 16, -1 },
 { "v22", 16, -1 },
 { "v23", 16, -1 },
 { "v24", 16, -1 },
 { "v25", 16, -1 },
 { "v26", 16, -1 },
 { "v27", 16, -1 },
 { "v28", 16, -1 },
 { "v29", 16, -1 },
 { "v30", 16, -1 },
 { "v31", 16, -1 },
 { "fpsr", 4, -1 },
 { "fpcr", 4, -1 },
};

char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs)
{
 if (regno >= DBG_MAX_REG_NUM || regno < 0)
  return NULL;

 if (dbg_reg_def[regno].offset != -1)
  memcpy(mem, (void *)regs + dbg_reg_def[regno].offset,
         dbg_reg_def[regno].size);
 else
  memset(mem, 0, dbg_reg_def[regno].size);
 return dbg_reg_def[regno].name;
}

int dbg_set_reg(int regno, void *mem, struct pt_regs *regs)
{
 if (regno >= DBG_MAX_REG_NUM || regno < 0)
  return -EINVAL;

 if (dbg_reg_def[regno].offset != -1)
  memcpy((void *)regs + dbg_reg_def[regno].offset, mem,
         dbg_reg_def[regno].size);
 return 0;
}

void
sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task)
{
 struct cpu_context *cpu_context = &task->thread.cpu_context;

 /* Initialize to zero */
 memset((char *)gdb_regs, 0, NUMREGBYTES);

 gdb_regs[19] = cpu_context->x19;
 gdb_regs[20] = cpu_context->x20;
 gdb_regs[21] = cpu_context->x21;
 gdb_regs[22] = cpu_context->x22;
 gdb_regs[23] = cpu_context->x23;
 gdb_regs[24] = cpu_context->x24;
 gdb_regs[25] = cpu_context->x25;
 gdb_regs[26] = cpu_context->x26;
 gdb_regs[27] = cpu_context->x27;
 gdb_regs[28] = cpu_context->x28;
 gdb_regs[29] = cpu_context->fp;

 gdb_regs[31] = cpu_context->sp;
 gdb_regs[32] = cpu_context->pc;
}

void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc)
{
 regs->pc = pc;
}

static int compiled_break;

static void kgdb_arch_update_addr(struct pt_regs *regs,
    char *remcom_in_buffer)
{
 unsigned long addr;
 char *ptr;

 ptr = &remcom_in_buffer[1];
 if (kgdb_hex2long(&ptr, &addr))
  kgdb_arch_set_pc(regs, addr);
 else if (compiled_break == 1)
  kgdb_arch_set_pc(regs, regs->pc + 4);

 compiled_break = 0;
}

int kgdb_arch_handle_exception(int exception_vector, int signo,
          int err_code, char *remcom_in_buffer,
          char *remcom_out_buffer,
          struct pt_regs *linux_regs)
{
 int err;

 switch (remcom_in_buffer[0]) {
 case 'D':
 case 'k':
  /*
 * Packet D (Detach), k (kill). No special handling
 * is required here. Handle same as c packet.
 */

 case 'c':
  /*
 * Packet c (Continue) to continue executing.
 * Set pc to required address.
 * Try to read optional parameter and set pc.
 * If this was a compiled breakpoint, we need to move
 * to the next instruction else we will just breakpoint
 * over and over again.
 */

  kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
  atomic_set(&kgdb_cpu_doing_single_step, -1);
  kgdb_single_step =  0;

  /*
 * Received continue command, disable single step
 */

  if (kernel_active_single_step())
   kernel_disable_single_step();

  err = 0;
  break;
 case 's':
  /*
 * Update step address value with address passed
 * with step packet.
 * On debug exception return PC is copied to ELR
 * So just update PC.
 * If no step address is passed, resume from the address
 * pointed by PC. Do not update PC
 */

  kgdb_arch_update_addr(linux_regs, remcom_in_buffer);
  atomic_set(&kgdb_cpu_doing_single_step, raw_smp_processor_id());
  kgdb_single_step =  1;

  /*
 * Enable single step handling
 */

  if (!kernel_active_single_step())
   kernel_enable_single_step(linux_regs);
  else
   kernel_rewind_single_step(linux_regs);
  err = 0;
  break;
 default:
  err = -1;
 }
 return err;
}

int kgdb_brk_handler(struct pt_regs *regs, unsigned long esr)
{
 kgdb_handle_exception(1, SIGTRAP, 0, regs);
 return DBG_HOOK_HANDLED;
}
NOKPROBE_SYMBOL(kgdb_brk_handler)

int kgdb_compiled_brk_handler(struct pt_regs *regs, unsigned long esr)
{
 compiled_break = 1;
 kgdb_handle_exception(1, SIGTRAP, 0, regs);

 return DBG_HOOK_HANDLED;
}
NOKPROBE_SYMBOL(kgdb_compiled_brk_handler);

int kgdb_single_step_handler(struct pt_regs *regs, unsigned long esr)
{
 if (!kgdb_single_step)
  return DBG_HOOK_ERROR;

 kgdb_handle_exception(0, SIGTRAP, 0, regs);
 return DBG_HOOK_HANDLED;
}
NOKPROBE_SYMBOL(kgdb_single_step_handler);

static int __kgdb_notify(struct die_args *args, unsigned long cmd)
{
 struct pt_regs *regs = args->regs;

 if (kgdb_handle_exception(1, args->signr, cmd, regs))
  return NOTIFY_DONE;
 return NOTIFY_STOP;
}

static int
kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr)
{
 unsigned long flags;
 int ret;

 local_irq_save(flags);
 ret = __kgdb_notify(ptr, cmd);
 local_irq_restore(flags);

 return ret;
}

static struct notifier_block kgdb_notifier = {
 .notifier_call = kgdb_notify,
 /*
 * Want to be lowest priority
 */

 .priority = -INT_MAX,
};

/*
 * kgdb_arch_init - Perform any architecture specific initialization.
 * This function will handle the initialization of any architecture
 * specific callbacks.
 */

int kgdb_arch_init(void)
{
 return register_die_notifier(&kgdb_notifier);
}

/*
 * kgdb_arch_exit - Perform any architecture specific uninitalization.
 * This function will handle the uninitalization of any architecture
 * specific callbacks, for dynamic registration and unregistration.
 */

void kgdb_arch_exit(void)
{
 unregister_die_notifier(&kgdb_notifier);
}

const struct kgdb_arch arch_kgdb_ops;

int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
{
 int err;

 BUILD_BUG_ON(AARCH64_INSN_SIZE != BREAK_INSTR_SIZE);

 err = aarch64_insn_read((void *)bpt->bpt_addr, (u32 *)bpt->saved_instr);
 if (err)
  return err;

 return aarch64_insn_write((void *)bpt->bpt_addr,
   (u32)AARCH64_BREAK_KGDB_DYN_DBG);
}

int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
{
 return aarch64_insn_write((void *)bpt->bpt_addr,
   *(u32 *)bpt->saved_instr);
}

Messung V0.5
C=83 H=97 G=90

¤ Dauer der Verarbeitung: 0.3 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.