# ptrace와 hardware debug register

v6.18.37 / arch/riscv/kernel/ptrace.c

디버거가 보는 레지스터는 임의의 순간에 다른 CPU의 레지스터를 그대로 훔쳐 읽은 값이 아닙니다. 정지한 task의 저장 상태와 아키텍처별 regset ABI를 통해 읽습니다. arm64는 GPR·FPSIMD/SVE 등, x86은 GPR·xstate 등, RISC-V는 GPR·FP/Vector 등을 정의합니다. 아래는 RISC-V GPR 읽기와 쓰기 함수입니다.

## riscv_gpr_get / riscv_gpr_set

```c

static int riscv_gpr_get(struct task_struct *target,
			 const struct user_regset *regset,
			 struct membuf to)
{
	return membuf_write(&to, task_pt_regs(target),
			    sizeof(struct user_regs_struct));
}

static int riscv_gpr_set(struct task_struct *target,
			 const struct user_regset *regset,
			 unsigned int pos, unsigned int count,
			 const void *kbuf, const void __user *ubuf)
{
	struct pt_regs *regs;

	regs = task_pt_regs(target);
	return user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 0, -1);
}

```

### 36행

```c

static int riscv_gpr_get(struct task_struct *target,

```

대상 task의 일반 레지스터 regset을 읽는 콜백입니다. 정지·동기화 조건은 상위 ptrace 경로가 확보합니다.

### 37행

```c

			 const struct user_regset *regset,

```

어떤 regset ABI를 처리하는지 나타내는 서술자를 콜백 인수로 받습니다.

### 38행

```c

			 struct membuf to)

```

결과를 적을 membuf를 받습니다. 출력 버퍼의 위치와 남은 용량을 관리하는 추상화입니다.

### 40행

```c

	return membuf_write(&to, task_pt_regs(target),

```

task_pt_regs로 대상의 저장 프레임을 찾고 그 내용을 membuf로 복사합니다. 다른 CPU의 살아 있는 레지스터를 직접 읽는 명령은 아닙니다.

### 41행

```c

			    sizeof(struct user_regs_struct));

```

사용자 ABI가 정의한 일반 레지스터 구조체의 크기만 출력합니다. 커널 내부 pt_regs의 모든 부가 필드를 노출하는 것이 아닙니다.

### 44행

```c

static int riscv_gpr_set(struct task_struct *target,

```

이번에는 대상 task의 일반 레지스터 저장 상태를 바꾸는 콜백입니다.

### 45행

```c

			 const struct user_regset *regset,

```

쓰기 대상인 regset의 서술자를 받습니다.

### 46행

```c

			 unsigned int pos, unsigned int count,

```

사용자가 갱신하려는 바이트 시작 위치와 길이를 받습니다. 항상 전체 레지스터를 한 번에 바꾸는 요청만 있는 것은 아닙니다.

### 47행

```c

			 const void *kbuf, const void __user *ubuf)

```

입력의 출처가 커널 버퍼인지 사용자 버퍼인지 구분합니다. __user는 사용자 주소 포인터임을 나타냅니다.

### 49행

```c

	struct pt_regs *regs;

```

수정할 pt_regs의 위치를 보관할 포인터를 선언합니다.

### 51행

```c

	regs = task_pt_regs(target);

```

대상 task의 저장 프레임 주소를 얻습니다.

### 52행

```c

	return user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 0, -1);

```

공통 regset 복사 helper가 pos/count와 입력 포인터를 갱신하며 요청 범위를 프레임에 씁니다. 실제 사용자 복귀는 이후 이 저장 상태를 바탕으로 진행합니다.

