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

Quelle  kgdb.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * kgdb support for ARC
 *
 * Copyright (C) 2012 Synopsys, Inc. (www.synopsys.com)
 */


#include <linux/kgdb.h>
#include <linux/sched.h>
#include <linux/sched/task_stack.h>
#include <asm/disasm.h>
#include <asm/cacheflush.h>

static void to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs,
   struct callee_regs *cregs)
{
 int regno;

 for (regno = 0; regno <= 26; regno++)
  gdb_regs[_R0 + regno] = get_reg(regno, kernel_regs, cregs);

 for (regno = 27; regno < GDB_MAX_REGS; regno++)
  gdb_regs[regno] = 0;

 gdb_regs[_FP]  = kernel_regs->fp;
 gdb_regs[__SP]  = kernel_regs->sp;
 gdb_regs[_BLINK] = kernel_regs->blink;
 gdb_regs[_RET]  = kernel_regs->ret;
 gdb_regs[_STATUS32] = kernel_regs->status32;
 gdb_regs[_LP_COUNT] = kernel_regs->lp_count;
 gdb_regs[_LP_END] = kernel_regs->lp_end;
 gdb_regs[_LP_START] = kernel_regs->lp_start;
 gdb_regs[_BTA]  = kernel_regs->bta;
 gdb_regs[_STOP_PC] = kernel_regs->ret;
}

static void from_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs,
   struct callee_regs *cregs)
{
 int regno;

 for (regno = 0; regno <= 26; regno++)
  set_reg(regno, gdb_regs[regno + _R0], kernel_regs, cregs);

 kernel_regs->fp  = gdb_regs[_FP];
 kernel_regs->sp  = gdb_regs[__SP];
 kernel_regs->blink = gdb_regs[_BLINK];
 kernel_regs->ret = gdb_regs[_RET];
 kernel_regs->status32 = gdb_regs[_STATUS32];
 kernel_regs->lp_count = gdb_regs[_LP_COUNT];
 kernel_regs->lp_end = gdb_regs[_LP_END];
 kernel_regs->lp_start = gdb_regs[_LP_START];
 kernel_regs->bta = gdb_regs[_BTA];
}


void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
{
 to_gdb_regs(gdb_regs, kernel_regs, (struct callee_regs *)
  current->thread.callee_reg);
}

void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *kernel_regs)
{
 from_gdb_regs(gdb_regs, kernel_regs, (struct callee_regs *)
  current->thread.callee_reg);
}

void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,
     struct task_struct *task)
{
 if (task)
  to_gdb_regs(gdb_regs, task_pt_regs(task),
   (struct callee_regs *) task->thread.callee_reg);
}

struct single_step_data_t {
 uint16_t opcode[2];
 unsigned long address[2];
 int is_branch;
 int armed;
} single_step_data;

static void undo_single_step(struct pt_regs *regs)
{
 if (single_step_data.armed) {
  int i;

  for (i = 0; i < (single_step_data.is_branch ? 2 : 1); i++) {
   memcpy((void *) single_step_data.address[i],
    &single_step_data.opcode[i],
    BREAK_INSTR_SIZE);

   flush_icache_range(single_step_data.address[i],
    single_step_data.address[i] +
    BREAK_INSTR_SIZE);
  }
  single_step_data.armed = 0;
 }
}

static void place_trap(unsigned long address, void *save)
{
 memcpy(save, (void *) address, BREAK_INSTR_SIZE);
 memcpy((void *) address, &arch_kgdb_ops.gdb_bpt_instr,
  BREAK_INSTR_SIZE);
 flush_icache_range(address, address + BREAK_INSTR_SIZE);
}

static void do_single_step(struct pt_regs *regs)
{
 single_step_data.is_branch = disasm_next_pc((unsigned long)
  regs->ret, regs, (struct callee_regs *)
  current->thread.callee_reg,
  &single_step_data.address[0],
  &single_step_data.address[1]);

 place_trap(single_step_data.address[0], &single_step_data.opcode[0]);

 if (single_step_data.is_branch) {
  place_trap(single_step_data.address[1],
   &single_step_data.opcode[1]);
 }

 single_step_data.armed++;
}

int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
          char *remcomInBuffer, char *remcomOutBuffer,
          struct pt_regs *regs)
{
 unsigned long addr;
 char *ptr;

 undo_single_step(regs);

 switch (remcomInBuffer[0]) {
 case 's':
 case 'c':
  ptr = &remcomInBuffer[1];
  if (kgdb_hex2long(&ptr, &addr))
   regs->ret = addr;
  fallthrough;

 case 'D':
 case 'k':
  atomic_set(&kgdb_cpu_doing_single_step, -1);

  if (remcomInBuffer[0] == 's') {
   do_single_step(regs);
   atomic_set(&kgdb_cpu_doing_single_step,
       smp_processor_id());
  }

  return 0;
 }
 return -1;
}

int kgdb_arch_init(void)
{
 single_step_data.armed = 0;
 return 0;
}

void kgdb_trap(struct pt_regs *regs)
{
 /* trap_s 3 is used for breakpoints that overwrite existing
 * instructions, while trap_s 4 is used for compiled breakpoints.
 *
 * with trap_s 3 breakpoints the original instruction needs to be
 * restored and continuation needs to start at the location of the
 * breakpoint.
 *
 * with trap_s 4 (compiled) breakpoints, continuation needs to
 * start after the breakpoint.
 */

 if (regs->ecr.param == 3)
  instruction_pointer(regs) -= BREAK_INSTR_SIZE;

 kgdb_handle_exception(1, SIGTRAP, 0, regs);
}

void kgdb_arch_exit(void)
{
}

void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
{
 instruction_pointer(regs) = ip;
}

void kgdb_call_nmi_hook(void *ignored)
{
 /* Default implementation passes get_irq_regs() but we don't */
 kgdb_nmicallback(raw_smp_processor_id(), NULL);
}

const struct kgdb_arch arch_kgdb_ops = {
 /* breakpoint instruction: TRAP_S 0x3 */
#ifdef CONFIG_CPU_BIG_ENDIAN
 .gdb_bpt_instr  = {0x78, 0x7e},
#else
 .gdb_bpt_instr  = {0x7e, 0x78},
#endif
};

Messung V0.5
C=99 H=89 G=94

¤ 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.