diff options
Diffstat (limited to 'tools/testing/selftests/bpf/trace_helpers.c')
| -rw-r--r-- | tools/testing/selftests/bpf/trace_helpers.c | 87 | 
1 files changed, 87 insertions, 0 deletions
diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c index 1bbd1d9830c8..e7a19b04d4ea 100644 --- a/tools/testing/selftests/bpf/trace_helpers.c +++ b/tools/testing/selftests/bpf/trace_helpers.c @@ -136,3 +136,90 @@ void read_trace_pipe(void)  		}  	}  } + +#if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2 + +#define OP_RT_RA_MASK   0xffff0000UL +#define LIS_R2          0x3c400000UL +#define ADDIS_R2_R12    0x3c4c0000UL +#define ADDI_R2_R2      0x38420000UL + +ssize_t get_uprobe_offset(const void *addr, ssize_t base) +{ +	u32 *insn = (u32 *)(uintptr_t)addr; + +	/* +	 * A PPC64 ABIv2 function may have a local and a global entry +	 * point. We need to use the local entry point when patching +	 * functions, so identify and step over the global entry point +	 * sequence. +	 * +	 * The global entry point sequence is always of the form: +	 * +	 * addis r2,r12,XXXX +	 * addi  r2,r2,XXXX +	 * +	 * A linker optimisation may convert the addis to lis: +	 * +	 * lis   r2,XXXX +	 * addi  r2,r2,XXXX +	 */ +	if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) || +	     ((*insn & OP_RT_RA_MASK) == LIS_R2)) && +	    ((*(insn + 1) & OP_RT_RA_MASK) == ADDI_R2_R2)) +		return (ssize_t)(insn + 2) - base; +	else +		return (uintptr_t)addr - base; +} + +#else + +ssize_t get_uprobe_offset(const void *addr, ssize_t base) +{ +	return (uintptr_t)addr - base; +} + +#endif + +ssize_t get_base_addr(void) +{ +	size_t start, offset; +	char buf[256]; +	FILE *f; + +	f = fopen("/proc/self/maps", "r"); +	if (!f) +		return -errno; + +	while (fscanf(f, "%zx-%*x %s %zx %*[^\n]\n", +		      &start, buf, &offset) == 3) { +		if (strcmp(buf, "r-xp") == 0) { +			fclose(f); +			return start - offset; +		} +	} + +	fclose(f); +	return -EINVAL; +} + +ssize_t get_rel_offset(uintptr_t addr) +{ +	size_t start, end, offset; +	char buf[256]; +	FILE *f; + +	f = fopen("/proc/self/maps", "r"); +	if (!f) +		return -errno; + +	while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &offset) == 4) { +		if (addr >= start && addr < end) { +			fclose(f); +			return (size_t)addr - start + offset; +		} +	} + +	fclose(f); +	return -EINVAL; +}  | 
