arch/arc/kernel/kgdb.c

Source file repositories/reference/linux-study-clean/arch/arc/kernel/kgdb.c

File Facts

System
Linux kernel
Corpus path
arch/arc/kernel/kgdb.c
Extension
.c
Size
5080 bytes
Lines
207
Domain
Architecture Layer
Bucket
arch/arc
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

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)

Annotation

Implementation Notes