diff --git a/libbpf-tools/Makefile b/libbpf-tools/Makefile index 7c8b5f8e83a5..3883d0862c44 100644 --- a/libbpf-tools/Makefile +++ b/libbpf-tools/Makefile @@ -11,7 +11,9 @@ CFLAGS := -g -O2 -Wall BPFCFLAGS := -g -O2 -Wall INSTALL ?= install prefix ?= /usr/local -ARCH := $(shell uname -m | sed 's/x86_64/x86/' | sed 's/aarch64/arm64/' | sed 's/ppc64le/powerpc/' | sed 's/mips.*/mips/' | sed 's/riscv64/riscv/') +ARCH := $(shell uname -m | sed 's/x86_64/x86/' | sed 's/aarch64/arm64/' \ + | sed 's/ppc64le/powerpc/' | sed 's/mips.*/mips/' \ + | sed 's/riscv64/riscv/' | sed 's/loongarch.*/loongarch/') BTFHUB_ARCHIVE ?= $(abspath btfhub-archive) ifeq ($(wildcard $(ARCH)/),) diff --git a/src/cc/export/helpers.h b/src/cc/export/helpers.h index c02eb46fe49f..e6f69a998b38 100644 --- a/src/cc/export/helpers.h +++ b/src/cc/export/helpers.h @@ -1284,6 +1284,9 @@ int bpf_usdt_readarg_p(int argc, struct pt_regs *ctx, void *buf, u64 len) asm("l #elif defined(__TARGET_ARCH_riscv64) #define bpf_target_riscv64 #define bpf_target_defined +#elif defined(__TARGET_ARCH_loongarch) +#define bpf_target_loongarch +#define bpf_target_defined #else #undef bpf_target_defined #endif @@ -1302,6 +1305,8 @@ int bpf_usdt_readarg_p(int argc, struct pt_regs *ctx, void *buf, u64 len) asm("l #define bpf_target_mips #elif defined(__riscv) && (__riscv_xlen == 64) #define bpf_target_riscv64 +#elif defined(__loongarch__) +#define bpf_target_loongarch #endif #endif @@ -1376,6 +1381,18 @@ int bpf_usdt_readarg_p(int argc, struct pt_regs *ctx, void *buf, u64 len) asm("l #define PT_REGS_RC(x) (__PT_REGS_CAST(x)->a0) #define PT_REGS_SP(x) (__PT_REGS_CAST(x)->sp) #define PT_REGS_IP(x) (__PT_REGS_CAST(x)->pc) +#elif defined(bpf_target_loongarch) +#define PT_REGS_PARM1(x) ((x)->regs[4]) +#define PT_REGS_PARM2(x) ((x)->regs[5]) +#define PT_REGS_PARM3(x) ((x)->regs[6]) +#define PT_REGS_PARM4(x) ((x)->regs[7]) +#define PT_REGS_PARM5(x) ((x)->regs[8]) +#define PT_REGS_PARM6(x) ((x)->regs[9]) +#define PT_REGS_RET(x) ((x)->regs[1]) +#define PT_REGS_FP(x) ((x)->regs[22]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->regs[4]) +#define PT_REGS_SP(x) ((x)->regs[3]) +#define PT_REGS_IP(x) ((x)->csr_era) #else #error "bcc does not support this platform yet" #endif diff --git a/src/cc/frontends/clang/arch_helper.h b/src/cc/frontends/clang/arch_helper.h index 13037e85a771..c6bd5bef5a46 100644 --- a/src/cc/frontends/clang/arch_helper.h +++ b/src/cc/frontends/clang/arch_helper.h @@ -24,6 +24,7 @@ typedef enum { BCC_ARCH_ARM64, BCC_ARCH_MIPS, BCC_ARCH_RISCV64, + BCC_ARCH_LOONGARCH, BCC_ARCH_X86 } bcc_arch_t; @@ -49,6 +50,8 @@ static void *run_arch_callback(arch_callback_t fn, bool for_syscall = false) return fn(BCC_ARCH_MIPS, for_syscall); #elif defined(__riscv) && (__riscv_xlen == 64) return fn(BCC_ARCH_RISCV64, for_syscall); +#elif defined(__loongarch__) + return fn(BCC_ARCH_LOONGARCH, for_syscall); #else return fn(BCC_ARCH_X86, for_syscall); #endif @@ -69,6 +72,8 @@ static void *run_arch_callback(arch_callback_t fn, bool for_syscall = false) return fn(BCC_ARCH_MIPS, for_syscall); } else if (!strcmp(archenv, "riscv64")) { return fn(BCC_ARCH_RISCV64, for_syscall); + } else if (!strcmp(archenv, "loongarch")) { + return fn(BCC_ARCH_LOONGARCH, for_syscall); } else { return fn(BCC_ARCH_X86, for_syscall); } diff --git a/src/cc/frontends/clang/b_frontend_action.cc b/src/cc/frontends/clang/b_frontend_action.cc index 4fedde5c0a91..a4e05b16a38a 100644 --- a/src/cc/frontends/clang/b_frontend_action.cc +++ b/src/cc/frontends/clang/b_frontend_action.cc @@ -63,6 +63,10 @@ const char *calling_conv_regs_mips[] = {"regs[4]", "regs[5]", "regs[6]", const char *calling_conv_regs_riscv64[] = {"a0", "a1", "a2", "a3", "a4", "a5"}; +const char *calling_conv_regs_loongarch[] = {"regs[4]", "regs[5]", "regs[6]", + "regs[7]", "regs[8]", "regs[9]"}; + + void *get_call_conv_cb(bcc_arch_t arch, bool for_syscall) { const char **ret; @@ -84,6 +88,9 @@ void *get_call_conv_cb(bcc_arch_t arch, bool for_syscall) case BCC_ARCH_RISCV64: ret = calling_conv_regs_riscv64; break; + case BCC_ARCH_LOONGARCH: + ret = calling_conv_regs_loongarch; + break; default: if (for_syscall) ret = calling_conv_syscall_regs_x86; diff --git a/src/cc/frontends/clang/kbuild_helper.cc b/src/cc/frontends/clang/kbuild_helper.cc index 79eab8bd2971..933aec8e8574 100644 --- a/src/cc/frontends/clang/kbuild_helper.cc +++ b/src/cc/frontends/clang/kbuild_helper.cc @@ -38,7 +38,7 @@ int KBuildHelper::get_flags(const char *uname_machine, vector *cflags) { //uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ // -e s/sa110/arm/ -e s/s390x/s390/ -e s/parisc64/parisc/ // -e s/ppc.*/powerpc/ -e s/mips.*/mips/ -e s/sh[234].*/sh/ - // -e s/aarch64.*/arm64/ + // -e s/aarch64.*/arm64/ -e s/loongarch.*/loongarch/ string arch; const char *archenv = getenv("ARCH"); @@ -68,6 +68,8 @@ int KBuildHelper::get_flags(const char *uname_machine, vector *cflags) { arch = "mips"; } else if (!arch.compare(0, 5, "riscv")) { arch = "riscv"; + } else if (!arch.compare(0, 9, "loongarch")) { + arch = "loongarch"; } else if (!arch.compare(0, 2, "sh")) { arch = "sh"; } diff --git a/src/cc/frontends/clang/loader.cc b/src/cc/frontends/clang/loader.cc index 7803ffb48ceb..cbc83af443a5 100644 --- a/src/cc/frontends/clang/loader.cc +++ b/src/cc/frontends/clang/loader.cc @@ -363,6 +363,9 @@ void *get_clang_target_cb(bcc_arch_t arch, bool for_syscall) case BCC_ARCH_RISCV64: ret = "riscv64-unknown-linux-gnu"; break; + case BCC_ARCH_LOONGARCH: + ret = "loongarch64-unknown-linux-gnu"; + break; default: ret = "x86_64-unknown-linux-gnu"; } diff --git a/src/cc/usdt.h b/src/cc/usdt.h index 7370026d62be..ec9fd6c3269a 100644 --- a/src/cc/usdt.h +++ b/src/cc/usdt.h @@ -81,6 +81,7 @@ class Argument { friend class ArgumentParser; friend class ArgumentParser_aarch64; + friend class ArgumentParser_loongarch64; friend class ArgumentParser_powerpc64; friend class ArgumentParser_s390x; friend class ArgumentParser_x64; @@ -134,6 +135,17 @@ class ArgumentParser_aarch64 : public ArgumentParser { ArgumentParser_aarch64(const char *arg) : ArgumentParser(arg) {} }; +class ArgumentParser_loongarch64 : public ArgumentParser { + private: + bool parse_register(ssize_t pos, ssize_t &new_pos, std::string ®_name); + bool parse_size(ssize_t pos, ssize_t &new_pos, optional *arg_size); + bool parse_mem(ssize_t pos, ssize_t &new_pos, Argument *dest); + + public: + bool parse(Argument *dest); + ArgumentParser_loongarch64(const char *arg) : ArgumentParser(arg) {} +}; + class ArgumentParser_powerpc64 : public ArgumentParser { public: bool parse(Argument *dest); diff --git a/src/cc/usdt/usdt.cc b/src/cc/usdt/usdt.cc index c6f7f81ab21f..264447e1702c 100644 --- a/src/cc/usdt/usdt.cc +++ b/src/cc/usdt/usdt.cc @@ -38,6 +38,8 @@ Location::Location(uint64_t addr, const std::string &bin_path, const char *arg_f #ifdef __aarch64__ ArgumentParser_aarch64 parser(arg_fmt); +#elif __loongarch64 + ArgumentParser_loongarch64 parser(arg_fmt); #elif __powerpc64__ ArgumentParser_powerpc64 parser(arg_fmt); #elif __s390x__ diff --git a/src/cc/usdt/usdt_args.cc b/src/cc/usdt/usdt_args.cc index d74c8650140e..8312547229ce 100644 --- a/src/cc/usdt/usdt_args.cc +++ b/src/cc/usdt/usdt_args.cc @@ -266,6 +266,121 @@ bool ArgumentParser_aarch64::parse(Argument *dest) { return true; } +bool ArgumentParser_loongarch64::parse_register(ssize_t pos, ssize_t &new_pos, + std::string ®_name) { + if (arg_[pos] == '$' && arg_[pos + 1] == 'r') { + optional reg_num; + new_pos = parse_number(pos + 2, ®_num); + if (new_pos == pos + 2 || *reg_num < 0 || *reg_num > 31) + return error_return(pos + 2, pos + 2); + + if (*reg_num == 3) { + reg_name = "sp"; + } else { + reg_name = "regs[" + std::to_string(reg_num.value()) + "]"; + } + return true; + } else if (arg_[pos] == 's' && arg_[pos + 1] == 'p') { + reg_name = "sp"; + new_pos = pos + 2; + return true; + } else { + return error_return(pos, pos); + } +} + +bool ArgumentParser_loongarch64::parse_size(ssize_t pos, ssize_t &new_pos, + optional *arg_size) { + int abs_arg_size; + + new_pos = parse_number(pos, arg_size); + if (new_pos == pos) + return error_return(pos, pos); + + abs_arg_size = abs(arg_size->value()); + if (abs_arg_size != 1 && abs_arg_size != 2 && abs_arg_size != 4 && + abs_arg_size != 8) + return error_return(pos, pos); + return true; +} + +bool ArgumentParser_loongarch64::parse_mem(ssize_t pos, ssize_t &new_pos, + Argument *dest) { + std::string base_reg_name, index_reg_name; + + if (parse_register(pos, new_pos, base_reg_name) == false) + return false; + dest->base_register_name_ = base_reg_name; + + if (arg_[new_pos] == ',') { + pos = new_pos + 1; + new_pos = parse_number(pos, &dest->deref_offset_); + if (new_pos == pos) { + // offset isn't a number, so it should be a reg, + // which looks like: -1@[$r0, $r1], rather than -1@[$r0, 24] + skip_whitespace_from(pos); + pos = cur_pos_; + if (parse_register(pos, new_pos, index_reg_name) == false) + return error_return(pos, pos); + dest->index_register_name_ = index_reg_name; + dest->scale_ = 1; + dest->deref_offset_ = 0; + } + } + if (arg_[new_pos] != ']') + return error_return(new_pos, new_pos); + new_pos++; + return true; +} + +bool ArgumentParser_loongarch64::parse(Argument *dest) { + if (done()) + return false; + + // Support the following argument patterns: + // [-]@, [-]@, [-]@[], or + // [-]@[,] + // [-]@[,] + ssize_t cur_pos = cur_pos_, new_pos; + optional arg_size; + + // Parse [-] + if (parse_size(cur_pos, new_pos, &arg_size) == false) + return false; + dest->arg_size_ = arg_size; + + // Make sure '@' present + if (arg_[new_pos] != '@') + return error_return(new_pos, new_pos); + cur_pos = new_pos + 1; + + if (arg_[cur_pos] == '$' || arg_[cur_pos] == 's') { + // Parse ...@ + std::string reg_name; + if (parse_register(cur_pos, new_pos, reg_name) == false) + return false; + + cur_pos_ = new_pos; + dest->base_register_name_ = reg_name; + } else if (arg_[cur_pos] == '[') { + // Parse ...@[], ...@[] and ...@[,] + if (parse_mem(cur_pos + 1, new_pos, dest) == false) + return false; + cur_pos_ = new_pos; + } else { + // Parse ...@ + optional val; + new_pos = parse_number(cur_pos, &val); + if (cur_pos == new_pos) + return error_return(cur_pos, cur_pos); + cur_pos_ = new_pos; + dest->constant_ = val; + } + + skip_whitespace_from(cur_pos_); + return true; +} + bool ArgumentParser_powerpc64::parse(Argument *dest) { if (done()) return false; diff --git a/tests/cc/test_usdt_args.cc b/tests/cc/test_usdt_args.cc index 715328517b14..66f92f8f55f5 100644 --- a/tests/cc/test_usdt_args.cc +++ b/tests/cc/test_usdt_args.cc @@ -53,13 +53,16 @@ static void verify_register(USDT::ArgumentParser &parser, int arg_size, } /* supported arches only */ -#if defined(__aarch64__) || defined(__powerpc64__) || \ - defined(__s390x__) || defined(__x86_64__) +#if defined(__aarch64__) || defined(__loongarch64) || \ + defined(__powerpc64__) || defined(__s390x__) || \ + defined(__x86_64__) TEST_CASE("test usdt argument parsing", "[usdt]") { SECTION("parse failure") { #ifdef __aarch64__ USDT::ArgumentParser_aarch64 parser("4@[x32,200]"); +#elif __loongarch64 + USDT::ArgumentParser_loongarch64 parser("4@[$r32,200]"); #elif __powerpc64__ USDT::ArgumentParser_powerpc64 parser("4@-12(42)"); #elif __s390x__ @@ -86,6 +89,15 @@ TEST_CASE("test usdt argument parsing", "[usdt]") { verify_register(parser, -4, "regs[30]", -40); verify_register(parser, -4, "sp", -40); verify_register(parser, 8, "sp", 120); +#elif __loongarch64 + USDT::ArgumentParser_loongarch64 parser( + "-1@$r0 4@5 8@[$r12] -4@[$r30,-40] -4@[$r3,-40] 8@[sp, 120]"); + verify_register(parser, -1, "regs[0]"); + verify_register(parser, 4, 5); + verify_register(parser, 8, "regs[12]", 0); + verify_register(parser, -4, "regs[30]", -40); + verify_register(parser, -4, "sp", -40); + verify_register(parser, 8, "sp", 120); #elif __powerpc64__ USDT::ArgumentParser_powerpc64 parser( "-4@0 8@%r0 8@i0 4@0(%r0) -2@0(0) "