mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-13 23:34:05 +08:00
kgdb,kdb: individual register set and and get API
The kdb shell specification includes the ability to get and set architecture specific registers by name. For the time being individual register get and set will be implemented on a per architecture basis. If an architecture defines DBG_MAX_REG_NUM > 0 then kdb and the gdbstub will use the capability for individually getting and setting architecture specific registers. Signed-off-by: Jason Wessel <jason.wessel@windriver.com>
This commit is contained in:
parent
84a0bd5b28
commit
534af10823
@ -90,6 +90,19 @@ struct kgdb_bkpt {
|
||||
enum kgdb_bpstate state;
|
||||
};
|
||||
|
||||
struct dbg_reg_def_t {
|
||||
char *name;
|
||||
int size;
|
||||
int offset;
|
||||
};
|
||||
|
||||
#ifndef DBG_MAX_REG_NUM
|
||||
#define DBG_MAX_REG_NUM 0
|
||||
#else
|
||||
extern struct dbg_reg_def_t dbg_reg_def[];
|
||||
extern char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs);
|
||||
extern int dbg_set_reg(int regno, void *mem, struct pt_regs *regs);
|
||||
#endif
|
||||
#ifndef KGDB_MAX_BREAKPOINTS
|
||||
# define KGDB_MAX_BREAKPOINTS 1000
|
||||
#endif
|
||||
|
@ -328,6 +328,32 @@ static int kgdb_ebin2mem(char *buf, char *mem, int count)
|
||||
return probe_kernel_write(mem, c, size);
|
||||
}
|
||||
|
||||
#if DBG_MAX_REG_NUM > 0
|
||||
void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
int idx = 0;
|
||||
char *ptr = (char *)gdb_regs;
|
||||
|
||||
for (i = 0; i < DBG_MAX_REG_NUM; i++) {
|
||||
dbg_get_reg(i, ptr + idx, regs);
|
||||
idx += dbg_reg_def[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
|
||||
{
|
||||
int i;
|
||||
int idx = 0;
|
||||
char *ptr = (char *)gdb_regs;
|
||||
|
||||
for (i = 0; i < DBG_MAX_REG_NUM; i++) {
|
||||
dbg_set_reg(i, ptr + idx, regs);
|
||||
idx += dbg_reg_def[i].size;
|
||||
}
|
||||
}
|
||||
#endif /* DBG_MAX_REG_NUM > 0 */
|
||||
|
||||
/* Write memory due to an 'M' or 'X' packet. */
|
||||
static int write_mem_msg(int binary)
|
||||
{
|
||||
|
@ -312,7 +312,7 @@ int kdbgetularg(const char *arg, unsigned long *value)
|
||||
|
||||
if (endp == arg) {
|
||||
/*
|
||||
* Try base 16, for us folks too lazy to type the
|
||||
* Also try base 16, for us folks too lazy to type the
|
||||
* leading 0x...
|
||||
*/
|
||||
val = simple_strtoul(arg, &endp, 16);
|
||||
@ -325,6 +325,25 @@ int kdbgetularg(const char *arg, unsigned long *value)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kdbgetu64arg(const char *arg, u64 *value)
|
||||
{
|
||||
char *endp;
|
||||
u64 val;
|
||||
|
||||
val = simple_strtoull(arg, &endp, 0);
|
||||
|
||||
if (endp == arg) {
|
||||
|
||||
val = simple_strtoull(arg, &endp, 16);
|
||||
if (endp == arg)
|
||||
return KDB_BADINT;
|
||||
}
|
||||
|
||||
*value = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* kdb_set - This function implements the 'set' command. Alter an
|
||||
* existing environment variable or create a new one.
|
||||
@ -1770,11 +1789,65 @@ static int kdb_go(int argc, const char **argv)
|
||||
*/
|
||||
static int kdb_rd(int argc, const char **argv)
|
||||
{
|
||||
int diag = kdb_check_regs();
|
||||
if (diag)
|
||||
return diag;
|
||||
int len = kdb_check_regs();
|
||||
#if DBG_MAX_REG_NUM > 0
|
||||
int i;
|
||||
char *rname;
|
||||
int rsize;
|
||||
u64 reg64;
|
||||
u32 reg32;
|
||||
u16 reg16;
|
||||
u8 reg8;
|
||||
|
||||
if (len)
|
||||
return len;
|
||||
|
||||
for (i = 0; i < DBG_MAX_REG_NUM; i++) {
|
||||
rsize = dbg_reg_def[i].size * 2;
|
||||
if (rsize > 16)
|
||||
rsize = 2;
|
||||
if (len + strlen(dbg_reg_def[i].name) + 4 + rsize > 80) {
|
||||
len = 0;
|
||||
kdb_printf("\n");
|
||||
}
|
||||
if (len)
|
||||
len += kdb_printf(" ");
|
||||
switch(dbg_reg_def[i].size * 8) {
|
||||
case 8:
|
||||
rname = dbg_get_reg(i, ®8, kdb_current_regs);
|
||||
if (!rname)
|
||||
break;
|
||||
len += kdb_printf("%s: %02x", rname, reg8);
|
||||
break;
|
||||
case 16:
|
||||
rname = dbg_get_reg(i, ®16, kdb_current_regs);
|
||||
if (!rname)
|
||||
break;
|
||||
len += kdb_printf("%s: %04x", rname, reg16);
|
||||
break;
|
||||
case 32:
|
||||
rname = dbg_get_reg(i, ®32, kdb_current_regs);
|
||||
if (!rname)
|
||||
break;
|
||||
len += kdb_printf("%s: %08x", rname, reg32);
|
||||
break;
|
||||
case 64:
|
||||
rname = dbg_get_reg(i, ®64, kdb_current_regs);
|
||||
if (!rname)
|
||||
break;
|
||||
len += kdb_printf("%s: %016llx", rname, reg64);
|
||||
break;
|
||||
default:
|
||||
len += kdb_printf("%s: ??", dbg_reg_def[i].name);
|
||||
}
|
||||
}
|
||||
kdb_printf("\n");
|
||||
#else
|
||||
if (len)
|
||||
return len;
|
||||
|
||||
kdb_dumpregs(kdb_current_regs);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1782,32 +1855,67 @@ static int kdb_rd(int argc, const char **argv)
|
||||
* kdb_rm - This function implements the 'rm' (register modify) command.
|
||||
* rm register-name new-contents
|
||||
* Remarks:
|
||||
* Currently doesn't allow modification of control or
|
||||
* debug registers.
|
||||
* Allows register modification with the same restrictions as gdb
|
||||
*/
|
||||
static int kdb_rm(int argc, const char **argv)
|
||||
{
|
||||
#if DBG_MAX_REG_NUM > 0
|
||||
int diag;
|
||||
int ind = 0;
|
||||
unsigned long contents;
|
||||
const char *rname;
|
||||
int i;
|
||||
u64 reg64;
|
||||
u32 reg32;
|
||||
u16 reg16;
|
||||
u8 reg8;
|
||||
|
||||
if (argc != 2)
|
||||
return KDB_ARGCOUNT;
|
||||
/*
|
||||
* Allow presence or absence of leading '%' symbol.
|
||||
*/
|
||||
if (argv[1][0] == '%')
|
||||
ind = 1;
|
||||
rname = argv[1];
|
||||
if (*rname == '%')
|
||||
rname++;
|
||||
|
||||
diag = kdbgetularg(argv[2], &contents);
|
||||
diag = kdbgetu64arg(argv[2], ®64);
|
||||
if (diag)
|
||||
return diag;
|
||||
|
||||
diag = kdb_check_regs();
|
||||
if (diag)
|
||||
return diag;
|
||||
|
||||
diag = KDB_BADREG;
|
||||
for (i = 0; i < DBG_MAX_REG_NUM; i++) {
|
||||
if (strcmp(rname, dbg_reg_def[i].name) == 0) {
|
||||
diag = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!diag) {
|
||||
switch(dbg_reg_def[i].size * 8) {
|
||||
case 8:
|
||||
reg8 = reg64;
|
||||
dbg_set_reg(i, ®8, kdb_current_regs);
|
||||
break;
|
||||
case 16:
|
||||
reg16 = reg64;
|
||||
dbg_set_reg(i, ®16, kdb_current_regs);
|
||||
break;
|
||||
case 32:
|
||||
reg32 = reg64;
|
||||
dbg_set_reg(i, ®32, kdb_current_regs);
|
||||
break;
|
||||
case 64:
|
||||
dbg_set_reg(i, ®64, kdb_current_regs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return diag;
|
||||
#else
|
||||
kdb_printf("ERROR: Register set currently not implemented\n");
|
||||
return 0;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_MAGIC_SYSRQ)
|
||||
|
Loading…
Reference in New Issue
Block a user