From nobody Fri Apr 17 01:39:38 2026 Received: from mail-dy1-f202.google.com (mail-dy1-f202.google.com [74.125.82.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 586C13A0B18 for ; Tue, 24 Feb 2026 14:29:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943395; cv=none; b=O6VqFxGwH+PKt86ljJs/wdF8qqeXek2Pm6SRWVa3e6hUY2D5NYZzK0Alkci/tfJG7ycqDu6KbAiQ8ZNtgb8GRgVXQTCC7mNUQMgSBHzrFnuWb7AeMhBVwKcDFpKjOJ+sI3LEMDN2gzfJ3MGSLCqJMfUI9tHpbBHiKnRdrNF+IGY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943395; c=relaxed/simple; bh=3N895u+2tlaQb85Zb8QwBo8mu6vlTBkoztDSjnXlzWg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=BX3TfP4IZXyigc5AxJZ0ohsHWPT382R7+ASOrBkKQkIvjZOANxuLCPZ40EG7/fSyd1v24BzQjNZrKKSCBE8WCSZME6BjOzYq8KcE+AG6CO2o1GDIDhjCcg7KtdvFDxCH7NYlqixaLTzF5LGMQ17dIUF3EGrg6TGV3xqCn9Ifuu0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=evhb+Mcm; arc=none smtp.client-ip=74.125.82.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="evhb+Mcm" Received: by mail-dy1-f202.google.com with SMTP id 5a478bee46e88-2bda4fd1dd0so15664592eec.1 for ; Tue, 24 Feb 2026 06:29:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1771943392; x=1772548192; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=l6zGB6KXVZgGBJvevzesELin0ooFg0kJVSoJ6gwXlmk=; b=evhb+Mcm1AZ034S4cgcO0f0bu8gkn+oqY1jMdJwLGN2JOq2dnT4uT/q3cHM/UiuL0v Ua9WzF5vsxU1AwGks7VLjagN/6UO2x5NDZatVhIvGMby73Imi7CKPEiXpHlx0RlGrjir MwK5XnXNpEUFGeGvq/+/T5/00IMDetAzZrnllCXe9OXgFYvNPiyoJR/MonxuyhBhMnxT vjiSBTzTaQJEI02bXe3W/K6TAAnsYq+Vt1uuyp2n9Q3Lvr1VeNXgWHocHpj3ERlrVxTz dVlXfo0HTCNXy6PtBfnfteh9mWc6PyFgna3F90Ai/0Y7Aqd1VAJ16qf0Gx8BxQSlBzLQ 6D+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771943392; x=1772548192; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=l6zGB6KXVZgGBJvevzesELin0ooFg0kJVSoJ6gwXlmk=; b=c5LZ5xSQN0qm/KABixaGUNekOhvRXQ+Ikbp1+kzvyFuBeBIhGWGAlOg/acQvvhoS9q BZH51NrBmFX5AqdPEoFeJZm6FUho+GvtEHF9aZiB3rTishjyP/SzzgwSx8mz1h/dJvNl e56xU8Nqt8HdUvmnLzDEDO6lTXtz8187fFW1MAqzoeBiKweozBs5elgeuLmFBirG0I8K GkEnJguwc6iksl6XnoVlHxhXhS54aw2pCEeEV08qbnR0B1mLk033kIqc5AVSTtwtwtsk aBTERy7frFKJ8FwbF1Zmu0kOOVXy4wq9JUa3ZWMrg7Q4D5OMUw75Cmt7mxPzeeQFhM8A rbYw== X-Forwarded-Encrypted: i=1; AJvYcCVcvA9av2qejiA2ty1ZzY+N9m+dvVki9ZG9LvgaAOMODJnZ/hm3RMBZTDQ6qF4Q1PmELMZTUEo6VEhs008=@vger.kernel.org X-Gm-Message-State: AOJu0Yy1t4KHakMragl6BB0X833uOyhU1ZtaDDUNzP9dolh/wVX5GCq1 1qW/A5gefmi87p1/CuK4npg3GEpMuQ9qCVeTdQi/pDeN8Yrb2C4HWNOh/DM4y8awyi6APrTF6d+ ac7v4wSRMNQ== X-Received: from dybgx25.prod.google.com ([2002:a05:7301:2419:b0:2ba:7b4a:c331]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:7491:b0:2b7:2f29:648c with SMTP id 5a478bee46e88-2bd7b9efb89mr5937089eec.8.1771943392130; Tue, 24 Feb 2026 06:29:52 -0800 (PST) Date: Tue, 24 Feb 2026 06:29:31 -0800 In-Reply-To: <20260224142938.26088-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260224142938.26088-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.371.g1d285c8824-goog Message-ID: <20260224142938.26088-2-irogers@google.com> Subject: [RFC PATCH v1 1/7] tools build: Deduplicate test-libunwind for different architectures From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , John Garry , Will Deacon , Leo Yan , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Dmitrii Dolgov <9erthalion6@gmail.com>, Blake Jones , Tomas Glozar , Yuzhuo Jing , Dapeng Mi , Shimin Guo , Athira Rajeev , Chun-Tse Shao , Howard Chu , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-riscv@lists.infradead.org, Thomas Richter , libunwind-devel@nongnu.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The separate test files only exist to pass a different #include, instead have a single source file and pass -include to $(CC) to include the relevant header file for the architecture being tested. Generate the rules using a foreach loop. Include tests for all current libunwind architectures. Signed-off-by: Ian Rogers --- tools/build/feature/Makefile | 38 +++++++++---------- tools/build/feature/test-libunwind-aarch64.c | 27 ------------- tools/build/feature/test-libunwind-arm.c | 28 -------------- .../test-libunwind-debug-frame-aarch64.c | 17 --------- .../feature/test-libunwind-debug-frame-arm.c | 17 --------- .../feature/test-libunwind-debug-frame.c | 1 - tools/build/feature/test-libunwind-x86.c | 28 -------------- tools/build/feature/test-libunwind-x86_64.c | 28 -------------- tools/build/feature/test-libunwind.c | 1 - 9 files changed, 19 insertions(+), 166 deletions(-) delete mode 100644 tools/build/feature/test-libunwind-aarch64.c delete mode 100644 tools/build/feature/test-libunwind-arm.c delete mode 100644 tools/build/feature/test-libunwind-debug-frame-aarch64.c delete mode 100644 tools/build/feature/test-libunwind-debug-frame-arm.c delete mode 100644 tools/build/feature/test-libunwind-x86.c delete mode 100644 tools/build/feature/test-libunwind-x86_64.c diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 1fbcb3ce74d2..a0b40e826688 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile @@ -204,27 +204,27 @@ $(OUTPUT)test-numa_num_possible_cpus.bin: $(BUILD) -lnuma =20 $(OUTPUT)test-libunwind.bin: - $(BUILD) -lelf -llzma + $(BUILD) -include libunwind.h -lelf -llzma -lunwind =20 $(OUTPUT)test-libunwind-debug-frame.bin: - $(BUILD) -lelf -llzma -$(OUTPUT)test-libunwind-x86.bin: - $(BUILD) -lelf -llzma -lunwind-x86 - -$(OUTPUT)test-libunwind-x86_64.bin: - $(BUILD) -lelf -llzma -lunwind-x86_64 - -$(OUTPUT)test-libunwind-arm.bin: - $(BUILD) -lelf -llzma -lunwind-arm - -$(OUTPUT)test-libunwind-aarch64.bin: - $(BUILD) -lelf -llzma -lunwind-aarch64 - -$(OUTPUT)test-libunwind-debug-frame-arm.bin: - $(BUILD) -lelf -llzma -lunwind-arm - -$(OUTPUT)test-libunwind-debug-frame-aarch64.bin: - $(BUILD) -lelf -llzma -lunwind-aarch64 + $(BUILD) -include libunwind.h -lelf -llzma -lunwind + +LIBUNWIND_ARCHS:=3Daarch64 arm loongarch64 mips ppc32 ppc64 riscv s390x x8= 6 x86_64 +define LIBUNWIND_RULE +$$(OUTPUT)test-libunwind-$(1).bin: + $$(CC) $$(CFLAGS) -MD -Wall -Werror -include libunwind-$(1).h -o $$@ \ + test-libunwind.c $$(LDFLAGS) -lelf -llzma -lunwind-$(1) \ + > $$(@:.bin=3D.make.output) 2>&1 + +$$(OUTPUT)test-libunwind-debug-frame-$(1).bin: + $$(CC) $$(CFLAGS) -MD -Wall -Werror -include libunwind-$(1).h -o $$@ \ + test-libunwind-debug-frame.c $$(LDFLAGS) -lelf -llzma -lunwind-$(1) \ + > $$(@:.bin=3D.make.output) 2>&1 + +endef +$(foreach arch,$(LIBUNWIND_ARCHS), \ + $(eval $(call LIBUNWIND_RULE,$(arch))) \ +) =20 $(OUTPUT)test-libslang.bin: $(BUILD) -lslang diff --git a/tools/build/feature/test-libunwind-aarch64.c b/tools/build/fea= ture/test-libunwind-aarch64.c deleted file mode 100644 index 323803f49212..000000000000 --- a/tools/build/feature/test-libunwind-aarch64.c +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, - unw_word_t ip, - unw_dyn_info_t *di, - unw_proc_info_t *pi, - int need_unwind_info, void *arg); - -#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) - -static unw_accessors_t accessors; - -int main(void) -{ - unw_addr_space_t addr_space; - - addr_space =3D unw_create_addr_space(&accessors, 0); - if (addr_space) - return 0; - - unw_init_remote(NULL, addr_space, NULL); - dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); - - return 0; -} diff --git a/tools/build/feature/test-libunwind-arm.c b/tools/build/feature= /test-libunwind-arm.c deleted file mode 100644 index cb378b7d6866..000000000000 --- a/tools/build/feature/test-libunwind-arm.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, - unw_word_t ip, - unw_dyn_info_t *di, - unw_proc_info_t *pi, - int need_unwind_info, void *arg); - - -#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) - -static unw_accessors_t accessors; - -int main(void) -{ - unw_addr_space_t addr_space; - - addr_space =3D unw_create_addr_space(&accessors, 0); - if (addr_space) - return 0; - - unw_init_remote(NULL, addr_space, NULL); - dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); - - return 0; -} diff --git a/tools/build/feature/test-libunwind-debug-frame-aarch64.c b/too= ls/build/feature/test-libunwind-debug-frame-aarch64.c deleted file mode 100644 index 36d6646c185e..000000000000 --- a/tools/build/feature/test-libunwind-debug-frame-aarch64.c +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -extern int -UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, - unw_word_t ip, unw_word_t segbase, - const char *obj_name, unw_word_t start, - unw_word_t end); - -#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) - -int main(void) -{ - dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); - return 0; -} diff --git a/tools/build/feature/test-libunwind-debug-frame-arm.c b/tools/b= uild/feature/test-libunwind-debug-frame-arm.c deleted file mode 100644 index 8696e48e1268..000000000000 --- a/tools/build/feature/test-libunwind-debug-frame-arm.c +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -extern int -UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, - unw_word_t ip, unw_word_t segbase, - const char *obj_name, unw_word_t start, - unw_word_t end); - -#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) - -int main(void) -{ - dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); - return 0; -} diff --git a/tools/build/feature/test-libunwind-debug-frame.c b/tools/build= /feature/test-libunwind-debug-frame.c index efb55cdd8d01..4c57e37004b3 100644 --- a/tools/build/feature/test-libunwind-debug-frame.c +++ b/tools/build/feature/test-libunwind-debug-frame.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include #include =20 extern int diff --git a/tools/build/feature/test-libunwind-x86.c b/tools/build/feature= /test-libunwind-x86.c deleted file mode 100644 index e5e0f6c89637..000000000000 --- a/tools/build/feature/test-libunwind-x86.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, - unw_word_t ip, - unw_dyn_info_t *di, - unw_proc_info_t *pi, - int need_unwind_info, void *arg); - - -#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) - -static unw_accessors_t accessors; - -int main(void) -{ - unw_addr_space_t addr_space; - - addr_space =3D unw_create_addr_space(&accessors, 0); - if (addr_space) - return 0; - - unw_init_remote(NULL, addr_space, NULL); - dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); - - return 0; -} diff --git a/tools/build/feature/test-libunwind-x86_64.c b/tools/build/feat= ure/test-libunwind-x86_64.c deleted file mode 100644 index 62ae4db597dc..000000000000 --- a/tools/build/feature/test-libunwind-x86_64.c +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include - -extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, - unw_word_t ip, - unw_dyn_info_t *di, - unw_proc_info_t *pi, - int need_unwind_info, void *arg); - - -#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) - -static unw_accessors_t accessors; - -int main(void) -{ - unw_addr_space_t addr_space; - - addr_space =3D unw_create_addr_space(&accessors, 0); - if (addr_space) - return 0; - - unw_init_remote(NULL, addr_space, NULL); - dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); - - return 0; -} diff --git a/tools/build/feature/test-libunwind.c b/tools/build/feature/tes= t-libunwind.c index 53fd26614ff0..5af5dc3a73d4 100644 --- a/tools/build/feature/test-libunwind.c +++ b/tools/build/feature/test-libunwind.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0 -#include #include =20 extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, --=20 2.53.0.371.g1d285c8824-goog From nobody Fri Apr 17 01:39:38 2026 Received: from mail-dl1-f73.google.com (mail-dl1-f73.google.com [74.125.82.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C60C13A0B1B for ; Tue, 24 Feb 2026 14:29:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943397; cv=none; b=XOMrN1YD5MYuOOpyeCcFpWZLU7x1lZjBxsKN+sUwvgXvg5WEQ4VhZCCZt4NxTKPqSozUyWk/cezi6Q4HgRN3JwD2ncpduPiiJUWsqRAwLJZ3haj85yMS2+Z3Dn3UtdzTYz1ZFp5HUe1XrbqL96DnJF/VQDTdNchkcDX6oYh7JyE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943397; c=relaxed/simple; bh=v94O3JjXPcJB1/50e3xsc3yMO7ti8meuAFol0lM4KwQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=kaHKpXZpbMe6VyfYPoui7GOn7vvLWslGaL5+gSUPsTa1KD5Jp1T7lW1CtXtk+KByFPY3TxJTMCtrfGC+aamj6JA+6423MmRTSn8310nvFqeFaTVkn2/ULzmP3+tLWYYvTpMte2LPSe11pOYyKh0vJO0g6IVxx1vk1zoqMKx3wGU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=lSk7kvyN; arc=none smtp.client-ip=74.125.82.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="lSk7kvyN" Received: by mail-dl1-f73.google.com with SMTP id a92af1059eb24-12776bebeb3so9248362c88.1 for ; Tue, 24 Feb 2026 06:29:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1771943395; x=1772548195; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=SNCm7zq/RiIwV6cs6qsg5em/PwRpDVdooQ9sojmKhT8=; b=lSk7kvyNGfOiE+AHGV1Nv+IDVcuQFWiSTcvvcdoK3fovT14UXvs04uRmMBtHOefvPj K84t5MXhwGdGJfiUCvIUO4nJcmq2861Ta0aNf1UnKV0u2pLC3y+K3nLYmPJr1B60F68b 8sFyifQwjQp9aAWSi4IB8XWlYjbuN987o/ylxKrdsAjXf/5tNiJmr8OV3ObpkrfvLZrU cwvuJaUDz56aXHRI1Ic1gY2zx8RV/2sDl6L0RazKUtN8vTYATyKfOEf7quV5LeBf/o/g Apbn43iaawRNa3S+EiMJTzM6yErVAw2nJ0hN2Yqb/zVZz4D5bBTz41GHEpbWBwcYTeky MGtg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771943395; x=1772548195; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=SNCm7zq/RiIwV6cs6qsg5em/PwRpDVdooQ9sojmKhT8=; b=E7pVkv6jSbGc/8TYicn4IUNYR+JbACoNMB2X+GZjxSDq6mulNFWDg/SpsN5zhkD25P zn+N1UiSHPih26SxHvXvkzxvaFbnvpYja37ZD7hFQw/lMtFcsRVGXMBP7COnzl9JolSh iHzo+s82daKQf4lcl1BTh7An+oKEEsb4xyGtqiBFMWlTG9+GZcV/qBy6YL9oF9A7lpMN 7M1j7vsjJhfpl4EfdkyhACY7E3kQZ54/vg97hjSWFXY+UbWFwkWoIq1o+WRsyHm2tJnR AVLyfU9QhbBrbRBIzutqt5Hw3R3V24t8VmMoF4pH2xav/DfKJbGy3PxNHyMLK4pGgIeo ZJjw== X-Forwarded-Encrypted: i=1; AJvYcCVXWihfAosm0imixyDmAUAr6W9c5UIwvhBgajj1a72v/j7QldclnbmCsJbatHeYZjVeu8nX+6/N1uvRWVE=@vger.kernel.org X-Gm-Message-State: AOJu0Yy+/Q1gBt0y8SiDCbg1vgOmb82pGzZHKMGfEVv2YmiD86v6kP/d Tjy3ZmBbE/u0lu4bOjaTM49L4y28lSq+D3sNB5UjdGQLI27fgpuJtjTla4zV3NsY5vQajtzhaa9 9MlIHmySEFg== X-Received: from dlai14.prod.google.com ([2002:a05:701b:270e:b0:127:2bdd:909]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:6b8d:b0:11d:f440:b758 with SMTP id a92af1059eb24-1276ad18a01mr5321398c88.25.1771943394553; Tue, 24 Feb 2026 06:29:54 -0800 (PST) Date: Tue, 24 Feb 2026 06:29:32 -0800 In-Reply-To: <20260224142938.26088-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260224142938.26088-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.371.g1d285c8824-goog Message-ID: <20260224142938.26088-3-irogers@google.com> Subject: [RFC PATCH v1 2/7] perf build: Be more programmatic when setting up libunwind variables From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , John Garry , Will Deacon , Leo Yan , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Dmitrii Dolgov <9erthalion6@gmail.com>, Blake Jones , Tomas Glozar , Yuzhuo Jing , Dapeng Mi , Shimin Guo , Athira Rajeev , Chun-Tse Shao , Howard Chu , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-riscv@lists.infradead.org, Thomas Richter , libunwind-devel@nongnu.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Iterate LIBUNWIND_ARCHS when setting up CONFIG_ and HAVE_ definitions rather than treating each architecture individually. This sets up the libunwind build variables and C definitions beyond x86 and arm/aarch64. The existing naming convention is followed for compatibility. Signed-off-by: Ian Rogers --- tools/perf/Makefile.config | 215 +++++++++++++++---------------------- 1 file changed, 89 insertions(+), 126 deletions(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index a8dc72cfe48e..f38213ecce08 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -65,95 +65,83 @@ $(call detected_var,SRCARCH) =20 CFLAGS +=3D -I$(OUTPUT)arch/$(SRCARCH)/include/generated =20 -# Additional ARCH settings for ppc -ifeq ($(SRCARCH),powerpc) - ifndef NO_LIBUNWIND - LIBUNWIND_LIBS :=3D -lunwind -lunwind-ppc64 - endif -endif - # Additional ARCH settings for x86 ifeq ($(SRCARCH),x86) $(call detected,CONFIG_X86) ifeq (${IS_64_BIT}, 1) CFLAGS +=3D -DHAVE_ARCH_X86_64_SUPPORT ARCH_INCLUDE =3D ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/mem= set_64.S - ifndef NO_LIBUNWIND - LIBUNWIND_LIBS =3D -lunwind-x86_64 -lunwind -llzma - endif $(call detected,CONFIG_X86_64) - else - ifndef NO_LIBUNWIND - LIBUNWIND_LIBS =3D -lunwind-x86 -llzma -lunwind - endif endif endif =20 -ifeq ($(SRCARCH),arm) - ifndef NO_LIBUNWIND - LIBUNWIND_LIBS =3D -lunwind -lunwind-arm - endif +ifeq ($(ARCH),s390) + CFLAGS +=3D -fPIC endif =20 -ifeq ($(SRCARCH),arm64) - ifndef NO_LIBUNWIND - LIBUNWIND_LIBS =3D -lunwind -lunwind-aarch64 - endif +ifneq ($(LIBUNWIND),1) + NO_LIBUNWIND :=3D 1 endif =20 -ifeq ($(SRCARCH),loongarch) - ifndef NO_LIBUNWIND +ifndef NO_LIBUNWIND + ifeq ($(SRCARCH),arm) + LIBUNWIND_LIBS =3D -lunwind -lunwind-arm + endif + ifeq ($(SRCARCH),arm64) + LIBUNWIND_LIBS =3D -lunwind -lunwind-aarch64 + endif + ifeq ($(SRCARCH),loongarch) LIBUNWIND_LIBS =3D -lunwind -lunwind-loongarch64 endif -endif - -ifeq ($(ARCH),s390) - CFLAGS +=3D -fPIC -endif - -ifeq ($(ARCH),mips) - ifndef NO_LIBUNWIND + ifeq ($(ARCH),mips) LIBUNWIND_LIBS =3D -lunwind -lunwind-mips endif + ifeq ($(SRCARCH),powerpc) + LIBUNWIND_LIBS :=3D -lunwind -lunwind-ppc64 + endif + ifeq ($(SRCARCH),riscv) + LIBUNWIND_LIBS :=3D -lunwind -lunwind-riscv + endif + ifeq ($(SRCARCH),s390) + LIBUNWIND_LIBS :=3D -lunwind -lunwind-s390x + endif + ifeq ($(SRCARCH),x86) + ifeq (${IS_64_BIT}, 1) + LIBUNWIND_LIBS =3D -lunwind-x86_64 -lunwind -llzma + else + LIBUNWIND_LIBS =3D -lunwind-x86 -lunwind -llzma + endif + endif + ifeq ($(LIBUNWIND_LIBS),) + NO_LIBUNWIND :=3D 1 + endif endif =20 -ifneq ($(LIBUNWIND),1) - NO_LIBUNWIND :=3D 1 -endif - -ifeq ($(LIBUNWIND_LIBS),) - NO_LIBUNWIND :=3D 1 -endif # # For linking with debug library, run like: # # make DEBUG=3D1 LIBUNWIND_DIR=3D/opt/libunwind/ # - -libunwind_arch_set_flags =3D $(eval $(libunwind_arch_set_flags_code)) -define libunwind_arch_set_flags_code - FEATURE_CHECK_CFLAGS-libunwind-$(1) =3D -I$(LIBUNWIND_DIR)/include - FEATURE_CHECK_LDFLAGS-libunwind-$(1) =3D -L$(LIBUNWIND_DIR)/lib -endef - -ifdef LIBUNWIND_DIR - LIBUNWIND_CFLAGS =3D -I$(LIBUNWIND_DIR)/include - LIBUNWIND_LDFLAGS =3D -L$(LIBUNWIND_DIR)/lib - LIBUNWIND_ARCHS =3D x86 x86_64 arm aarch64 debug-frame-arm debug-frame-a= arch64 loongarch - $(foreach libunwind_arch,$(LIBUNWIND_ARCHS),$(call libunwind_arch_set_fl= ags,$(libunwind_arch))) -endif +LIBUNWIND_ARCHS:=3Daarch64 arm loongarch64 mips ppc32 ppc64 riscv s390x x8= 6 x86_64 =20 ifndef NO_LIBUNWIND - # Set per-feature check compilation flags FEATURE_CHECK_CFLAGS-libunwind =3D $(LIBUNWIND_CFLAGS) FEATURE_CHECK_LDFLAGS-libunwind =3D $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIB= S) FEATURE_CHECK_CFLAGS-libunwind-debug-frame =3D $(LIBUNWIND_CFLAGS) FEATURE_CHECK_LDFLAGS-libunwind-debug-frame =3D $(LIBUNWIND_LDFLAGS) $(L= IBUNWIND_LIBS) - =20 - FEATURE_CHECK_LDFLAGS-libunwind-arm +=3D -lunwind -lunwind-arm - FEATURE_CHECK_LDFLAGS-libunwind-aarch64 +=3D -lunwind -lunwind-aarch64 - FEATURE_CHECK_LDFLAGS-libunwind-x86 +=3D -lunwind -llzma -lunwind-x86 - FEATURE_CHECK_LDFLAGS-libunwind-x86_64 +=3D -lunwind -llzma -lunwind-x86= _64 + + ifdef LIBUNWIND_DIR + LIBUNWIND_CFLAGS =3D -I$(LIBUNWIND_DIR)/include + LIBUNWIND_LDFLAGS =3D -L$(LIBUNWIND_DIR)/lib + + define libunwind_arch_set_flags + FEATURE_CHECK_CFLAGS-libunwind-$(1) =3D -I$(LIBUNWIND_DIR)/include + FEATURE_CHECK_LDFLAGS-libunwind-$(1) =3D -L$(LIBUNWIND_DIR)/lib + endef + $(foreach arch,$(LIBUNWIND_ARCHS), \ + $(eval $(call libunwind_arch_set_flags,$(arch))) \ + ) + endif endif =20 ifdef CSINCLUDES @@ -637,49 +625,6 @@ ifeq ($(SRCARCH),powerpc) endif endif =20 -ifndef NO_LIBUNWIND - have_libunwind :=3D - - $(call feature_check,libunwind) - - $(call feature_check,libunwind-x86) - ifeq ($(feature-libunwind-x86), 1) - $(call detected,CONFIG_LIBUNWIND_X86) - CFLAGS +=3D -DHAVE_LIBUNWIND_X86_SUPPORT - LDFLAGS +=3D -lunwind-x86 - EXTLIBS_LIBUNWIND +=3D -lunwind-x86 - have_libunwind =3D 1 - endif - - $(call feature_check,libunwind-aarch64) - ifeq ($(feature-libunwind-aarch64), 1) - $(call detected,CONFIG_LIBUNWIND_AARCH64) - CFLAGS +=3D -DHAVE_LIBUNWIND_AARCH64_SUPPORT - LDFLAGS +=3D -lunwind-aarch64 - EXTLIBS_LIBUNWIND +=3D -lunwind-aarch64 - have_libunwind =3D 1 - $(call feature_check,libunwind-debug-frame-aarch64) - ifneq ($(feature-libunwind-debug-frame-aarch64), 1) - $(warning No debug_frame support found in libunwind-aarch64) - CFLAGS +=3D -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64 - endif - endif - - ifneq ($(feature-libunwind), 1) - $(warning No libunwind found. Please install libunwind-dev[el] >=3D 1.= 1 and/or set LIBUNWIND_DIR and set LIBUNWIND=3D1 in the make command line a= s it is opt-in now) - NO_LOCAL_LIBUNWIND :=3D 1 - else - have_libunwind :=3D 1 - $(call detected,CONFIG_LOCAL_LIBUNWIND) - endif - - ifneq ($(have_libunwind), 1) - NO_LIBUNWIND :=3D 1 - endif -else - NO_LOCAL_LIBUNWIND :=3D 1 -endif - ifndef NO_LIBBPF ifneq ($(feature-bpf), 1) $(warning BPF API too old. Please install recent kernel headers. BPF s= upport in 'perf record' is disabled.) @@ -738,6 +683,49 @@ ifndef GEN_VMLINUX_H VMLINUX_H=3D$(src-perf)/util/bpf_skel/vmlinux/vmlinux.h endif =20 +ifndef NO_LIBUNWIND + have_libunwind :=3D + + $(call feature_check,libunwind) + ifneq ($(feature-libunwind), 1) + $(warning No libunwind found. Please install libunwind-dev[el] >=3D 1.= 1 and/or set LIBUNWIND_DIR and set LIBUNWIND=3D1 in the make command line a= s it is opt-in now) + NO_LOCAL_LIBUNWIND :=3D 1 + else + have_libunwind :=3D 1 + $(call detected,CONFIG_LOCAL_LIBUNWIND) + CFLAGS +=3D -DHAVE_LIBUNWIND_SUPPORT + CFLAGS +=3D $(LIBUNWIND_CFLAGS) + LDFLAGS +=3D $(LIBUNWIND_LDFLAGS) + EXTLIBS +=3D $(EXTLIBS_LIBUNWIND) + $(call feature_check,libunwind-debug-frame) + ifneq ($(feature-libunwind-debug-frame), 1) + CFLAGS +=3D -DNO_LIBUNWIND_DEBUG_FRAME + endif + endif + + define PROCESS_REMOTE_LIBUNWIND_ARCH + $(call feature_check,libunwind-$(1)) + + ifeq ($$(feature-libunwind-$(1)), 1) + upper_arch :=3D $$(shell echo $(1) | tr '[:lower:]' '[:upper:]') + $$(call detected,CONFIG_LIBUNWIND_$$(upper_arch)) + + CFLAGS +=3D -DHAVE_LIBUNWIND_$$(upper_arch)_SUPPORT + LDFLAGS +=3D -lunwind-$(1) + EXTLIBS_LIBUNWIND +=3D -lunwind-$(1) + have_libunwind :=3D 1 + + $$(call feature_check,libunwind-debug-frame-$(1)) + ifneq ($$(feature-libunwind-debug-frame-$(1)), 1) + CFLAGS +=3D -DNO_LIBUNWIND_DEBUG_FRAME_$$(upper_arch) + endif + endif + endef + $(foreach arch,$(LIBUNWIND_ARCHS), \ + $(eval $(call PROCESS_REMOTE_LIBUNWIND_ARCH,$(arch))) \ + ) +endif + dwarf-post-unwind :=3D 1 dwarf-post-unwind-text :=3D BUG =20 @@ -760,31 +748,6 @@ ifeq ($(dwarf-post-unwind),1) $(call detected,CONFIG_DWARF_UNWIND) endif =20 -ifndef NO_LIBUNWIND - ifndef NO_LOCAL_LIBUNWIND - ifeq ($(SRCARCH),$(filter $(SRCARCH),arm arm64)) - $(call feature_check,libunwind-debug-frame) - ifneq ($(feature-libunwind-debug-frame), 1) - $(warning No debug_frame support found in libunwind) - CFLAGS +=3D -DNO_LIBUNWIND_DEBUG_FRAME - endif - else - # non-ARM has no dwarf_find_debug_frame() function: - CFLAGS +=3D -DNO_LIBUNWIND_DEBUG_FRAME - endif - EXTLIBS +=3D $(LIBUNWIND_LIBS) - LDFLAGS +=3D $(LIBUNWIND_LIBS) - endif - ifeq ($(findstring -static,${LDFLAGS}),-static) - # gcc -static links libgcc_eh which contans piece of libunwind - LIBUNWIND_LDFLAGS +=3D -Wl,--allow-multiple-definition - endif - CFLAGS +=3D -DHAVE_LIBUNWIND_SUPPORT - CFLAGS +=3D $(LIBUNWIND_CFLAGS) - LDFLAGS +=3D $(LIBUNWIND_LDFLAGS) - EXTLIBS +=3D $(EXTLIBS_LIBUNWIND) -endif - ifneq ($(NO_LIBTRACEEVENT),1) $(call detected,CONFIG_TRACE) endif --=20 2.53.0.371.g1d285c8824-goog From nobody Fri Apr 17 01:39:38 2026 Received: from mail-dl1-f74.google.com (mail-dl1-f74.google.com [74.125.82.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D4CE53A0B1C for ; Tue, 24 Feb 2026 14:29:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943400; cv=none; b=n2cA9jYwc1u/3VvS2p4AmITBBo0wH0p7Q5qWnNoxfFD532UcOqwi5aCTCVZUL29VduWKOVm9CQ4BnRPADhXbAb+N9c4bBn5WSSiYIKkqRvrFnM05wMZiYxBQLiT7HrEr4QqlLkdhiruiLhC4diBVURMOPWuecNRQ8UMdPZvI/hc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943400; c=relaxed/simple; bh=xx5fsw89/QByPMFgYJOkVtu4aTQQD2MRLUD3f/OCMPQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=Bl4t0WOrOTktar8cu4mFlgEgC2rtvkiq3XItYKFVGrX6BymDBqtjWUCmeGBq+3ZqeQkLTAzWRZUVEAXgxi058O2Ikqje9yBI2hSeRLrQBJERHNPre/4oTgpMTsBc9hlhBilc2882t1VCsR9Ksgc+eWHlWwYN3nQzUzuga+j+PlU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=D8NqQVut; arc=none smtp.client-ip=74.125.82.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="D8NqQVut" Received: by mail-dl1-f74.google.com with SMTP id a92af1059eb24-124a95b6f61so11362998c88.0 for ; Tue, 24 Feb 2026 06:29:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1771943397; x=1772548197; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=SF/9HIjbc6rTAg6numLxHr5OltI8HDgFivsZ6NrsbUM=; b=D8NqQVut3bxykiI5q6sQkLJOTnxySusMQZtdN3IHMlLiI3fqxqeIy8ii9xFWSbiGl6 y9v4/54TpRm8zuLbewH6zgAeZI6HG6Jggsm0uX8+vMQ+KD8LQVzB/j3pTvtmT51UisCi 6XIJO0pNQCGF1Wa23oloANPJ90lcMoRod32rctmJ8pn8hsuhaYQiyIzJrtrhB+xnqH3A gHKi+RZ8yPh56SsFx+zH70lOt81zQKptsZjUl/XhSfeDQ8ZWRSqYfu63YwNPQoZvfjrW sVyMbKVKIXhPS6iT7rJQCtEsOTJMofPp5a04kIsMIdjVEoZsN22sDIv3B4QWpaQ1/bvx iDRA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771943397; x=1772548197; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=SF/9HIjbc6rTAg6numLxHr5OltI8HDgFivsZ6NrsbUM=; b=oP9iSCQ2WKtBto5owwjADa8RyWDRLFKKbQ6vBEVbTYnTylJkuF30DKwj90RmYoe+Fr 5HHWW5CaTeRKZph+OviGb5FDiV03jkWF5wciIEJf95XitdupI1Bhl/z1EEwf5262FIKp tF42Ua6n8TZaXuq/iBzY+17iGWeBwUfaeVD/Zm4aUUdiHdmcmjbsaKZb2NzzqasHnmhB wJ/YqNsnJ1sBeHnCle+b6KwvIOFk8DHpWy7tSLwMcweldUrotWkkYH81csfPE1b6ieKk i1mDsJj3QV29G9EQ4HlfZGImfN0uKbq/rpqkyLcBJ59jR/DBulvTh+MsJFnwKvPyIZ8/ 8ARA== X-Forwarded-Encrypted: i=1; AJvYcCWU8B39cywBDRPfmaNBvjebtAuku6ujZzPRZu4K3GfYZMlfIjOxLbc/Pg3wIAZCIX6cmm9SBrSal9cMFb4=@vger.kernel.org X-Gm-Message-State: AOJu0Yzn+GI+mq5INSuzvQNsk333A7q4Shwc1zLD6czQxUlNVsbpyM3q DQUPIADpiQfpmD0j1aIlFCsEI7h6H5xsYIHA1nNClQow8fGstXMYJtpTOBoba2Uyp2Yq/jqppr4 wARtBXv08TA== X-Received: from dybgx25.prod.google.com ([2002:a05:7301:2419:b0:2ba:7b4a:c331]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7300:6428:b0:2ba:6458:b325 with SMTP id 5a478bee46e88-2bd7bd0974cmr5588226eec.23.1771943396789; Tue, 24 Feb 2026 06:29:56 -0800 (PST) Date: Tue, 24 Feb 2026 06:29:33 -0800 In-Reply-To: <20260224142938.26088-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260224142938.26088-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.371.g1d285c8824-goog Message-ID: <20260224142938.26088-4-irogers@google.com> Subject: [RFC PATCH v1 3/7] perf build loongarch: Remove reference to missing file From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , John Garry , Will Deacon , Leo Yan , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Dmitrii Dolgov <9erthalion6@gmail.com>, Blake Jones , Tomas Glozar , Yuzhuo Jing , Dapeng Mi , Shimin Guo , Athira Rajeev , Chun-Tse Shao , Howard Chu , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-riscv@lists.infradead.org, Thomas Richter , libunwind-devel@nongnu.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The file was removed in commit e62fae9d9e85 ("perf unwind-libdw: Fix a cross-arch unwinding bug") but the Build file not updated. Fixes: commit e62fae9d9e85 ("perf unwind-libdw: Fix a cross-arch unwinding = bug") Signed-off-by: Ian Rogers --- tools/perf/arch/loongarch/util/Build | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongar= ch/util/Build index 3ad73d0289f3..8d91e78d31c9 100644 --- a/tools/perf/arch/loongarch/util/Build +++ b/tools/perf/arch/loongarch/util/Build @@ -1,4 +1,3 @@ perf-util-y +=3D header.o =20 perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind.o -perf-util-$(CONFIG_LIBDW_DWARF_UNWIND) +=3D unwind-libdw.o --=20 2.53.0.371.g1d285c8824-goog From nobody Fri Apr 17 01:39:38 2026 Received: from mail-dy1-f201.google.com (mail-dy1-f201.google.com [74.125.82.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3ACBA3A0B16 for ; Tue, 24 Feb 2026 14:30:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943404; cv=none; b=Vgnjky3os6T3fQEJf8OlCYm0C3I8oB7S2kg3dHIta9Is4YBBxOHLBuf+7+aRg66NOyw1oPLvGMD3Sd46Bzgn1O+zlylMtStUtYVlSmK7ayyApsaNpfGHoOQY20WhDCik3BqEDbRBQmHKXw6ZxUApL3oLiqjknL4PtnYC7MIfwmk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943404; c=relaxed/simple; bh=fwpUjZ8dcHz9IRLtP325pPghYies7CghjH+ibosLys4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=MsvfjXJjDw/zOV3651XnznGDS4WdmheVZKxh9BXEYe4fL/RyBgP9zsstTDLIcZv8lOJo6A6tK+jZWwnusCLp0rECdiO9LRGqGSt0jMhHTfK65Gcp3f2YpdDhRsSdyZCXacLh/UR3qV9nS6F56JMjtkdiWa57V1rfkfbiprFSGhQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=S0P7rAzq; arc=none smtp.client-ip=74.125.82.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="S0P7rAzq" Received: by mail-dy1-f201.google.com with SMTP id 5a478bee46e88-2bd3bf5dde4so5328455eec.1 for ; Tue, 24 Feb 2026 06:30:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1771943399; x=1772548199; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=FeOT2lexYs+97IZnXpc3HeWNsXW02+k7VA4Ykdp3+qo=; b=S0P7rAzqKWyemlHNFKovbSi8yk9iAYrm6/W2niYC4MIWOU23Ppr1MkhmYLOMi5A/og gY1z18iQ7WwKyYCbBkVjhmAk0l4APLeUsgYLZZ56dINQa2Kpd/8T4mI1q+S/tXTgv7fW 8rw7Xl3vRefAvEk4Ztl6EA0JMsGXhUWfIMkXAQTZHoEh6VL6uW3aGXPlmeYggND2bO4H gDlrEK3NDpZLpd0J6HCI+V6JpTT9bDwrnZ80x6oNyYCo5GrodepXBSzktEEj5EozzwIN QNiNRIkInWvApJ5tOrN3F+7m8JAd3UBAiN4Vv3vFz4oVlJBUR/rZZuI6y3wEhH6OK4qV 0PQg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771943399; x=1772548199; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=FeOT2lexYs+97IZnXpc3HeWNsXW02+k7VA4Ykdp3+qo=; b=N+B/GOg9Nt4cCr6+D39snkmREXi1EKhSr8PEGuyNZHvnQq20ltjwol9xVoTJJbUrP1 yMvAh0SvTrRXlZRxnNky3QCaV3aI7PQjP3ohR+lTenRW1RyJjJXytDDIsePOQuJ1dOMv ghBv32c78ZSigIIzZTlpf6fBmcQRG52LXTeb/MOZChE63KsDAyNF4ZTN1GUOGfoV0Jae tpBc3Jz+aTLXMqTHvZoY+frAQ0LUU+92UJWwcr/a67u9aoAsLDp45PkObvNRNkcjrIeJ VS7xXLehafLxgPVceWcA5S9/g+82vEc+VsZ/n5/SaS26slrJl4rlEjSRkqX5SbmNihog I11w== X-Forwarded-Encrypted: i=1; AJvYcCXEgFVvQcIcke8qT6N5ittOdKO5AXyTw0pEmi5xcKf9ljMPxMnCvfy/4w4iaDI8omGd1nqAbAFOJhdld6k=@vger.kernel.org X-Gm-Message-State: AOJu0YwIPinAuVdfpiomesxS6wizGHryKpm9ppPVeqBqMLPhr8fNzBH5 DRizrB8YbwOylYdgXBKhc6naa7DnHS9goQSPuZZAjk2SN4zjj+Mq3WccMNr4gKZ/BZN+k+MoBXb fMUc3uY4gbA== X-Received: from dybue8.prod.google.com ([2002:a05:7300:f648:b0:2bd:b7c2:1881]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:693c:2c17:b0:2ba:8aa8:9bd4 with SMTP id 5a478bee46e88-2bd7b9d54a1mr4543072eec.5.1771943399099; Tue, 24 Feb 2026 06:29:59 -0800 (PST) Date: Tue, 24 Feb 2026 06:29:34 -0800 In-Reply-To: <20260224142938.26088-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260224142938.26088-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.371.g1d285c8824-goog Message-ID: <20260224142938.26088-5-irogers@google.com> Subject: [RFC PATCH v1 4/7] perf unwind-libunwind: Make libunwind register reading cross platform From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , John Garry , Will Deacon , Leo Yan , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Dmitrii Dolgov <9erthalion6@gmail.com>, Blake Jones , Tomas Glozar , Yuzhuo Jing , Dapeng Mi , Shimin Guo , Athira Rajeev , Chun-Tse Shao , Howard Chu , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-riscv@lists.infradead.org, Thomas Richter , libunwind-devel@nongnu.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move the libunwind register to perf register mapping functions in arch/../util/unwind-libunwind.c into a new libunwind-arch directory. Rename the functions to __get_perf_regnum_for_unw_regnum_. Add untested ppc32 and s390 functions. Add a get_perf_regnum_for_unw_regnum function that takes an ELF machine as well as a register number and chooses the appropriate architecture implementation. Split the x86 and powerpc 32 and 64-bit implementations apart so that a single libunwind-.h header is included. Move the e_machine into the unwind_info struct to make it easier to pass. Signed-off-by: Ian Rogers --- tools/perf/arch/arm/util/Build | 2 - tools/perf/arch/arm/util/unwind-libunwind.c | 50 -------- tools/perf/arch/arm64/util/Build | 1 - tools/perf/arch/arm64/util/unwind-libunwind.c | 17 --- tools/perf/arch/loongarch/util/Build | 2 - .../arch/loongarch/util/unwind-libunwind.c | 82 ------------- tools/perf/arch/mips/Build | 1 - tools/perf/arch/mips/util/Build | 1 - tools/perf/arch/mips/util/unwind-libunwind.c | 22 ---- tools/perf/arch/powerpc/util/Build | 1 - .../perf/arch/powerpc/util/unwind-libunwind.c | 92 -------------- tools/perf/arch/x86/util/Build | 3 - tools/perf/arch/x86/util/unwind-libunwind.c | 115 ------------------ tools/perf/util/Build | 1 + tools/perf/util/libunwind-arch/Build | 10 ++ .../perf/util/libunwind-arch/libunwind-arch.c | 32 +++++ .../perf/util/libunwind-arch/libunwind-arch.h | 16 +++ .../perf/util/libunwind-arch/libunwind-arm.c | 15 +++ .../util/libunwind-arch/libunwind-arm64.c | 14 +++ .../perf/util/libunwind-arch/libunwind-i386.c | 43 +++++++ .../util/libunwind-arch/libunwind-loongarch.c | 27 ++++ .../perf/util/libunwind-arch/libunwind-mips.c | 29 +++++ .../util/libunwind-arch/libunwind-ppc32.c | 31 +++++ .../util/libunwind-arch/libunwind-ppc64.c | 33 +++++ .../perf/util/libunwind-arch/libunwind-s390.c | 29 +++++ .../util/libunwind-arch/libunwind-x86_64.c | 52 ++++++++ tools/perf/util/libunwind/arm64.c | 5 - tools/perf/util/libunwind/x86_32.c | 12 -- tools/perf/util/unwind-libunwind-local.c | 12 +- tools/perf/util/unwind.h | 5 - 30 files changed, 338 insertions(+), 417 deletions(-) delete mode 100644 tools/perf/arch/arm/util/unwind-libunwind.c delete mode 100644 tools/perf/arch/arm64/util/unwind-libunwind.c delete mode 100644 tools/perf/arch/loongarch/util/unwind-libunwind.c delete mode 100644 tools/perf/arch/mips/Build delete mode 100644 tools/perf/arch/mips/util/Build delete mode 100644 tools/perf/arch/mips/util/unwind-libunwind.c delete mode 100644 tools/perf/arch/powerpc/util/unwind-libunwind.c delete mode 100644 tools/perf/arch/x86/util/unwind-libunwind.c create mode 100644 tools/perf/util/libunwind-arch/Build create mode 100644 tools/perf/util/libunwind-arch/libunwind-arch.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-arch.h create mode 100644 tools/perf/util/libunwind-arch/libunwind-arm.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-arm64.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-i386.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-loongarch.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-mips.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-ppc32.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-ppc64.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-s390.c create mode 100644 tools/perf/util/libunwind-arch/libunwind-x86_64.c diff --git a/tools/perf/arch/arm/util/Build b/tools/perf/arch/arm/util/Build index b94bf3c5279a..768ae5d16553 100644 --- a/tools/perf/arch/arm/util/Build +++ b/tools/perf/arch/arm/util/Build @@ -1,3 +1 @@ -perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind.o - perf-util-y +=3D pmu.o auxtrace.o cs-etm.o diff --git a/tools/perf/arch/arm/util/unwind-libunwind.c b/tools/perf/arch/= arm/util/unwind-libunwind.c deleted file mode 100644 index 438906bf0014..000000000000 --- a/tools/perf/arch/arm/util/unwind-libunwind.c +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include "perf_regs.h" -#include "../../../util/unwind.h" -#include "../../../util/debug.h" - -int libunwind__arch_reg_id(int regnum) -{ - switch (regnum) { - case UNW_ARM_R0: - return PERF_REG_ARM_R0; - case UNW_ARM_R1: - return PERF_REG_ARM_R1; - case UNW_ARM_R2: - return PERF_REG_ARM_R2; - case UNW_ARM_R3: - return PERF_REG_ARM_R3; - case UNW_ARM_R4: - return PERF_REG_ARM_R4; - case UNW_ARM_R5: - return PERF_REG_ARM_R5; - case UNW_ARM_R6: - return PERF_REG_ARM_R6; - case UNW_ARM_R7: - return PERF_REG_ARM_R7; - case UNW_ARM_R8: - return PERF_REG_ARM_R8; - case UNW_ARM_R9: - return PERF_REG_ARM_R9; - case UNW_ARM_R10: - return PERF_REG_ARM_R10; - case UNW_ARM_R11: - return PERF_REG_ARM_FP; - case UNW_ARM_R12: - return PERF_REG_ARM_IP; - case UNW_ARM_R13: - return PERF_REG_ARM_SP; - case UNW_ARM_R14: - return PERF_REG_ARM_LR; - case UNW_ARM_R15: - return PERF_REG_ARM_PC; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } - - return -EINVAL; -} diff --git a/tools/perf/arch/arm64/util/Build b/tools/perf/arch/arm64/util/= Build index 4e06a08d281a..4b70c4788c80 100644 --- a/tools/perf/arch/arm64/util/Build +++ b/tools/perf/arch/arm64/util/Build @@ -1,4 +1,3 @@ -perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind.o perf-util-y +=3D ../../arm/util/auxtrace.o perf-util-y +=3D ../../arm/util/cs-etm.o perf-util-y +=3D ../../arm/util/pmu.o diff --git a/tools/perf/arch/arm64/util/unwind-libunwind.c b/tools/perf/arc= h/arm64/util/unwind-libunwind.c deleted file mode 100644 index 871af5992298..000000000000 --- a/tools/perf/arch/arm64/util/unwind-libunwind.c +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include - -#ifndef REMOTE_UNWIND_LIBUNWIND -#include -#include "perf_regs.h" -#include "../../../util/unwind.h" -#endif -#include "../../../util/debug.h" - -int LIBUNWIND__ARCH_REG_ID(int regnum) -{ - if (regnum < 0 || regnum >=3D PERF_REG_ARM64_EXTENDED_MAX) - return -EINVAL; - - return regnum; -} diff --git a/tools/perf/arch/loongarch/util/Build b/tools/perf/arch/loongar= ch/util/Build index 8d91e78d31c9..2328fb9a30a3 100644 --- a/tools/perf/arch/loongarch/util/Build +++ b/tools/perf/arch/loongarch/util/Build @@ -1,3 +1 @@ perf-util-y +=3D header.o - -perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind.o diff --git a/tools/perf/arch/loongarch/util/unwind-libunwind.c b/tools/perf= /arch/loongarch/util/unwind-libunwind.c deleted file mode 100644 index f693167b86ef..000000000000 --- a/tools/perf/arch/loongarch/util/unwind-libunwind.c +++ /dev/null @@ -1,82 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include "perf_regs.h" -#include "../../util/unwind.h" -#include "util/debug.h" - -int libunwind__arch_reg_id(int regnum) -{ - switch (regnum) { - case UNW_LOONGARCH64_R1: - return PERF_REG_LOONGARCH_R1; - case UNW_LOONGARCH64_R2: - return PERF_REG_LOONGARCH_R2; - case UNW_LOONGARCH64_R3: - return PERF_REG_LOONGARCH_R3; - case UNW_LOONGARCH64_R4: - return PERF_REG_LOONGARCH_R4; - case UNW_LOONGARCH64_R5: - return PERF_REG_LOONGARCH_R5; - case UNW_LOONGARCH64_R6: - return PERF_REG_LOONGARCH_R6; - case UNW_LOONGARCH64_R7: - return PERF_REG_LOONGARCH_R7; - case UNW_LOONGARCH64_R8: - return PERF_REG_LOONGARCH_R8; - case UNW_LOONGARCH64_R9: - return PERF_REG_LOONGARCH_R9; - case UNW_LOONGARCH64_R10: - return PERF_REG_LOONGARCH_R10; - case UNW_LOONGARCH64_R11: - return PERF_REG_LOONGARCH_R11; - case UNW_LOONGARCH64_R12: - return PERF_REG_LOONGARCH_R12; - case UNW_LOONGARCH64_R13: - return PERF_REG_LOONGARCH_R13; - case UNW_LOONGARCH64_R14: - return PERF_REG_LOONGARCH_R14; - case UNW_LOONGARCH64_R15: - return PERF_REG_LOONGARCH_R15; - case UNW_LOONGARCH64_R16: - return PERF_REG_LOONGARCH_R16; - case UNW_LOONGARCH64_R17: - return PERF_REG_LOONGARCH_R17; - case UNW_LOONGARCH64_R18: - return PERF_REG_LOONGARCH_R18; - case UNW_LOONGARCH64_R19: - return PERF_REG_LOONGARCH_R19; - case UNW_LOONGARCH64_R20: - return PERF_REG_LOONGARCH_R20; - case UNW_LOONGARCH64_R21: - return PERF_REG_LOONGARCH_R21; - case UNW_LOONGARCH64_R22: - return PERF_REG_LOONGARCH_R22; - case UNW_LOONGARCH64_R23: - return PERF_REG_LOONGARCH_R23; - case UNW_LOONGARCH64_R24: - return PERF_REG_LOONGARCH_R24; - case UNW_LOONGARCH64_R25: - return PERF_REG_LOONGARCH_R25; - case UNW_LOONGARCH64_R26: - return PERF_REG_LOONGARCH_R26; - case UNW_LOONGARCH64_R27: - return PERF_REG_LOONGARCH_R27; - case UNW_LOONGARCH64_R28: - return PERF_REG_LOONGARCH_R28; - case UNW_LOONGARCH64_R29: - return PERF_REG_LOONGARCH_R29; - case UNW_LOONGARCH64_R30: - return PERF_REG_LOONGARCH_R30; - case UNW_LOONGARCH64_R31: - return PERF_REG_LOONGARCH_R31; - case UNW_LOONGARCH64_PC: - return PERF_REG_LOONGARCH_PC; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } - - return -EINVAL; -} diff --git a/tools/perf/arch/mips/Build b/tools/perf/arch/mips/Build deleted file mode 100644 index e63eabc2c8f4..000000000000 --- a/tools/perf/arch/mips/Build +++ /dev/null @@ -1 +0,0 @@ -perf-util-y +=3D util/ diff --git a/tools/perf/arch/mips/util/Build b/tools/perf/arch/mips/util/Bu= ild deleted file mode 100644 index 818b808a8247..000000000000 --- a/tools/perf/arch/mips/util/Build +++ /dev/null @@ -1 +0,0 @@ -perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind.o diff --git a/tools/perf/arch/mips/util/unwind-libunwind.c b/tools/perf/arch= /mips/util/unwind-libunwind.c deleted file mode 100644 index 0d8c99c29da6..000000000000 --- a/tools/perf/arch/mips/util/unwind-libunwind.c +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include -#include "perf_regs.h" -#include "../../util/unwind.h" -#include "util/debug.h" - -int libunwind__arch_reg_id(int regnum) -{ - switch (regnum) { - case UNW_MIPS_R1 ... UNW_MIPS_R25: - return regnum - UNW_MIPS_R1 + PERF_REG_MIPS_R1; - case UNW_MIPS_R28 ... UNW_MIPS_R31: - return regnum - UNW_MIPS_R28 + PERF_REG_MIPS_R28; - case UNW_MIPS_PC: - return PERF_REG_MIPS_PC; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } -} diff --git a/tools/perf/arch/powerpc/util/Build b/tools/perf/arch/powerpc/u= til/Build index d66574cbb9a9..ae928050e07a 100644 --- a/tools/perf/arch/powerpc/util/Build +++ b/tools/perf/arch/powerpc/util/Build @@ -6,5 +6,4 @@ perf-util-y +=3D evsel.o =20 perf-util-$(CONFIG_LIBDW) +=3D skip-callchain-idx.o =20 -perf-util-$(CONFIG_LIBUNWIND) +=3D unwind-libunwind.o perf-util-y +=3D auxtrace.o diff --git a/tools/perf/arch/powerpc/util/unwind-libunwind.c b/tools/perf/a= rch/powerpc/util/unwind-libunwind.c deleted file mode 100644 index 90a6beda20de..000000000000 --- a/tools/perf/arch/powerpc/util/unwind-libunwind.c +++ /dev/null @@ -1,92 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Copyright 2016 Chandan Kumar, IBM Corporation. - */ - -#include -#include -#include -#include "../../util/unwind.h" -#include "../../util/debug.h" - -int libunwind__arch_reg_id(int regnum) -{ - switch (regnum) { - case UNW_PPC64_R0: - return PERF_REG_POWERPC_R0; - case UNW_PPC64_R1: - return PERF_REG_POWERPC_R1; - case UNW_PPC64_R2: - return PERF_REG_POWERPC_R2; - case UNW_PPC64_R3: - return PERF_REG_POWERPC_R3; - case UNW_PPC64_R4: - return PERF_REG_POWERPC_R4; - case UNW_PPC64_R5: - return PERF_REG_POWERPC_R5; - case UNW_PPC64_R6: - return PERF_REG_POWERPC_R6; - case UNW_PPC64_R7: - return PERF_REG_POWERPC_R7; - case UNW_PPC64_R8: - return PERF_REG_POWERPC_R8; - case UNW_PPC64_R9: - return PERF_REG_POWERPC_R9; - case UNW_PPC64_R10: - return PERF_REG_POWERPC_R10; - case UNW_PPC64_R11: - return PERF_REG_POWERPC_R11; - case UNW_PPC64_R12: - return PERF_REG_POWERPC_R12; - case UNW_PPC64_R13: - return PERF_REG_POWERPC_R13; - case UNW_PPC64_R14: - return PERF_REG_POWERPC_R14; - case UNW_PPC64_R15: - return PERF_REG_POWERPC_R15; - case UNW_PPC64_R16: - return PERF_REG_POWERPC_R16; - case UNW_PPC64_R17: - return PERF_REG_POWERPC_R17; - case UNW_PPC64_R18: - return PERF_REG_POWERPC_R18; - case UNW_PPC64_R19: - return PERF_REG_POWERPC_R19; - case UNW_PPC64_R20: - return PERF_REG_POWERPC_R20; - case UNW_PPC64_R21: - return PERF_REG_POWERPC_R21; - case UNW_PPC64_R22: - return PERF_REG_POWERPC_R22; - case UNW_PPC64_R23: - return PERF_REG_POWERPC_R23; - case UNW_PPC64_R24: - return PERF_REG_POWERPC_R24; - case UNW_PPC64_R25: - return PERF_REG_POWERPC_R25; - case UNW_PPC64_R26: - return PERF_REG_POWERPC_R26; - case UNW_PPC64_R27: - return PERF_REG_POWERPC_R27; - case UNW_PPC64_R28: - return PERF_REG_POWERPC_R28; - case UNW_PPC64_R29: - return PERF_REG_POWERPC_R29; - case UNW_PPC64_R30: - return PERF_REG_POWERPC_R30; - case UNW_PPC64_R31: - return PERF_REG_POWERPC_R31; - case UNW_PPC64_LR: - return PERF_REG_POWERPC_LINK; - case UNW_PPC64_CTR: - return PERF_REG_POWERPC_CTR; - case UNW_PPC64_XER: - return PERF_REG_POWERPC_XER; - case UNW_PPC64_NIP: - return PERF_REG_POWERPC_NIP; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } - return -EINVAL; -} diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build index b94c91984c66..7f89fffe4615 100644 --- a/tools/perf/arch/x86/util/Build +++ b/tools/perf/arch/x86/util/Build @@ -8,9 +8,6 @@ perf-util-y +=3D evlist.o perf-util-y +=3D mem-events.o perf-util-y +=3D evsel.o perf-util-y +=3D iostat.o - -perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind.o - perf-util-y +=3D auxtrace.o perf-util-y +=3D intel-pt.o perf-util-y +=3D intel-bts.o diff --git a/tools/perf/arch/x86/util/unwind-libunwind.c b/tools/perf/arch/= x86/util/unwind-libunwind.c deleted file mode 100644 index 47357973b55b..000000000000 --- a/tools/perf/arch/x86/util/unwind-libunwind.c +++ /dev/null @@ -1,115 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 - -#include -#include "../../util/debug.h" -#ifndef REMOTE_UNWIND_LIBUNWIND -#include -#include "perf_regs.h" -#include "../../util/unwind.h" -#endif - -#ifdef HAVE_ARCH_X86_64_SUPPORT -int LIBUNWIND__ARCH_REG_ID(int regnum) -{ - int id; - - switch (regnum) { - case UNW_X86_64_RAX: - id =3D PERF_REG_X86_AX; - break; - case UNW_X86_64_RDX: - id =3D PERF_REG_X86_DX; - break; - case UNW_X86_64_RCX: - id =3D PERF_REG_X86_CX; - break; - case UNW_X86_64_RBX: - id =3D PERF_REG_X86_BX; - break; - case UNW_X86_64_RSI: - id =3D PERF_REG_X86_SI; - break; - case UNW_X86_64_RDI: - id =3D PERF_REG_X86_DI; - break; - case UNW_X86_64_RBP: - id =3D PERF_REG_X86_BP; - break; - case UNW_X86_64_RSP: - id =3D PERF_REG_X86_SP; - break; - case UNW_X86_64_R8: - id =3D PERF_REG_X86_R8; - break; - case UNW_X86_64_R9: - id =3D PERF_REG_X86_R9; - break; - case UNW_X86_64_R10: - id =3D PERF_REG_X86_R10; - break; - case UNW_X86_64_R11: - id =3D PERF_REG_X86_R11; - break; - case UNW_X86_64_R12: - id =3D PERF_REG_X86_R12; - break; - case UNW_X86_64_R13: - id =3D PERF_REG_X86_R13; - break; - case UNW_X86_64_R14: - id =3D PERF_REG_X86_R14; - break; - case UNW_X86_64_R15: - id =3D PERF_REG_X86_R15; - break; - case UNW_X86_64_RIP: - id =3D PERF_REG_X86_IP; - break; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } - - return id; -} -#else -int LIBUNWIND__ARCH_REG_ID(int regnum) -{ - int id; - - switch (regnum) { - case UNW_X86_EAX: - id =3D PERF_REG_X86_AX; - break; - case UNW_X86_EDX: - id =3D PERF_REG_X86_DX; - break; - case UNW_X86_ECX: - id =3D PERF_REG_X86_CX; - break; - case UNW_X86_EBX: - id =3D PERF_REG_X86_BX; - break; - case UNW_X86_ESI: - id =3D PERF_REG_X86_SI; - break; - case UNW_X86_EDI: - id =3D PERF_REG_X86_DI; - break; - case UNW_X86_EBP: - id =3D PERF_REG_X86_BP; - break; - case UNW_X86_ESP: - id =3D PERF_REG_X86_SP; - break; - case UNW_X86_EIP: - id =3D PERF_REG_X86_IP; - break; - default: - pr_err("unwind: invalid reg id %d\n", regnum); - return -EINVAL; - } - - return id; -} -#endif /* HAVE_ARCH_X86_64_SUPPORT */ diff --git a/tools/perf/util/Build b/tools/perf/util/Build index bcccad7487a9..1964e13e3085 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -229,6 +229,7 @@ perf-util-$(CONFIG_LIBDW) +=3D unwind-libdw.o =20 perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind-local.o perf-util-$(CONFIG_LIBUNWIND) +=3D unwind-libunwind.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-arch/ perf-util-$(CONFIG_LIBUNWIND_X86) +=3D libunwind/x86_32.o perf-util-$(CONFIG_LIBUNWIND_AARCH64) +=3D libunwind/arm64.o =20 diff --git a/tools/perf/util/libunwind-arch/Build b/tools/perf/util/libunwi= nd-arch/Build new file mode 100644 index 000000000000..87fd657a3248 --- /dev/null +++ b/tools/perf/util/libunwind-arch/Build @@ -0,0 +1,10 @@ +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-arch.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-arm64.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-arm.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-loongarch.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-mips.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-ppc32.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-ppc64.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-s390.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-i386.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-x86_64.o diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.c b/tools/perf/u= til/libunwind-arch/libunwind-arch.c new file mode 100644 index 000000000000..5439bf90d161 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-arch.c @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include +#include + +int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum) +{ + switch (e_machine) { + case EM_ARM: + return __get_perf_regnum_for_unw_regnum_arm(unw_regnum); + case EM_AARCH64: + return __get_perf_regnum_for_unw_regnum_arm64(unw_regnum); + case EM_LOONGARCH: + return __get_perf_regnum_for_unw_regnum_loongarch(unw_regnum); + case EM_MIPS: + return __get_perf_regnum_for_unw_regnum_mips(unw_regnum); + case EM_PPC: + return __get_perf_regnum_for_unw_regnum_ppc32(unw_regnum); + case EM_PPC64: + return __get_perf_regnum_for_unw_regnum_ppc64(unw_regnum); + case EM_S390: + return __get_perf_regnum_for_unw_regnum_s390(unw_regnum); + case EM_386: + return __get_perf_regnum_for_unw_regnum_i386(unw_regnum); + case EM_X86_64: + return __get_perf_regnum_for_unw_regnum_x86_64(unw_regnum); + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + return -EINVAL; + } +} diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.h b/tools/perf/u= til/libunwind-arch/libunwind-arch.h new file mode 100644 index 000000000000..e1009c6cb965 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-arch.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LIBUNWIND_ARCH_H +#define __LIBUNWIND_ARCH_H + +int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_loongarch(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_mips(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_ppc32(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_ppc64(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_s390(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum); +int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum); + +#endif /* __LIBUNWIND_ARCH_H */ diff --git a/tools/perf/util/libunwind-arch/libunwind-arm.c b/tools/perf/ut= il/libunwind-arch/libunwind-arm.c new file mode 100644 index 000000000000..6740ee55b043 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-arm.c @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/arm/include/uapi/asm/perf_regs.h" +#include +#include + +int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum) +{ + if (unw_regnum < 0 || unw_regnum >=3D PERF_REG_ARM_MAX) { + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } + return unw_regnum; +} diff --git a/tools/perf/util/libunwind-arch/libunwind-arm64.c b/tools/perf/= util/libunwind-arch/libunwind-arm64.c new file mode 100644 index 000000000000..53b1877dfa04 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-arm64.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/arm64/include/uapi/asm/perf_regs.h" +#include + +int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum) +{ + if (unw_regnum < 0 || unw_regnum >=3D PERF_REG_ARM64_EXTENDED_MAX) { + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } + return unw_regnum; +} diff --git a/tools/perf/util/libunwind-arch/libunwind-i386.c b/tools/perf/u= til/libunwind-arch/libunwind-i386.c new file mode 100644 index 000000000000..83bef77bddfd --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-i386.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/x86/include/uapi/asm/perf_regs.h" +#include +#include +#include + +#ifdef HAVE_LIBUNWIND_X86_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_X86_SUPPORT + return -EINVAL; +#else + static const int perf_i386_regnums[] =3D { +#define REGNUM(reg) [UNW_X86_E ## reg] =3D PERF_REG_X86_ ## reg + REGNUM(AX), + REGNUM(DX), + REGNUM(CX), + REGNUM(BX), + REGNUM(SI), + REGNUM(DI), + REGNUM(BP), + REGNUM(SP), + REGNUM(IP), +#undef REGNUM + }; + + if (unw_regnum =3D=3D UNW_X86_64_EAX) + return PERF_REG_X86_AX; + + if (unw_regnum < 0 || unw_regnum > (int)ARRAY_SIZE(perf_i386_regnums) || + perf_i386_regnums[unw_regnum] =3D=3D 0) { + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } + + return perf_i386_regnums[unw_regnum]; +#endif // HAVE_LIBUNWIND_X86_SUPPORT +} diff --git a/tools/perf/util/libunwind-arch/libunwind-loongarch.c b/tools/p= erf/util/libunwind-arch/libunwind-loongarch.c new file mode 100644 index 000000000000..7009410989bc --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-loongarch.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/loongarch/include/uapi/asm/perf_regs.h" +#include +#include + +#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_loongarch(int unw_regnum __maybe_unus= ed) +{ +#ifndef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT + return -EINVAL; +#else + switch (unw_regnum) { + case UNW_LOONGARCH64_R1 ... UNW_LOONGARCH64_31: + return unw_regnum - UNW_LOONGARCH64_R1 + PERF_REG_LOONGARCH_R1; + case UNW_LOONGARCH64_PC: + return PERF_REG_LOONGARCH_PC; + default: + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } +#endif // HAVE_LIBUNWIND_LOONGARCH64_SUPPORT +} diff --git a/tools/perf/util/libunwind-arch/libunwind-mips.c b/tools/perf/u= til/libunwind-arch/libunwind-mips.c new file mode 100644 index 000000000000..01a506c8079c --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-mips.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/mips/include/uapi/asm/perf_regs.h" +#include +#include + +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_mips(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_MIPS_SUPPORT + return -EINVAL; +#else + switch (unw_regnum) { + case UNW_MIPS_R1 ... UNW_MIPS_R25: + return unw_regnum - UNW_MIPS_R1 + PERF_REG_MIPS_R1; + case UNW_MIPS_R28 ... UNW_MIPS_R31: + return unw_regnum - UNW_MIPS_R28 + PERF_REG_MIPS_R28; + case UNW_MIPS_PC: + return PERF_REG_MIPS_PC; + default: + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } +#endif // HAVE_LIBUNWIND_MIPS_SUPPORT +} diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc32.c b/tools/perf/= util/libunwind-arch/libunwind-ppc32.c new file mode 100644 index 000000000000..edcb0ec95dd7 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-ppc32.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h" +#include +#include + +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_ppc32(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_PPC32_SUPPORT + return -EINVAL; +#else + switch (unw_regnum) { + case UNW_PPC32_R0 ... UNW_PPC32_31: + return unw_regnum - UNW_PPC32_R0 + PERF_REG_POWERPC_R0; + case UNW_PPC32_LR: + return PERF_REG_POWERPC_LINK; + case UNW_PPC32_CTR: + return PERF_REG_POWERPC_CTR; + case UNW_PPC32_XER: + return PERF_REG_POWERPC_XER; + default: + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } +#endif // HAVE_LIBUNWIND_PPC32_SUPPORT +} diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc64.c b/tools/perf/= util/libunwind-arch/libunwind-ppc64.c new file mode 100644 index 000000000000..9f57a049600b --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-ppc64.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/powerpc/include/uapi/asm/perf_regs.h" +#include +#include + +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_ppc64(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_PPC64_SUPPORT + return -EINVAL; +#else + switch (unw_regnum) { + case UNW_PPC64_R0 ... UNW_PPC64_31: + return unw_regnum - UNW_PPC64_R0 + PERF_REG_POWERPC_R0; + case UNW_PPC64_LR: + return PERF_REG_POWERPC_LINK; + case UNW_PPC64_CTR: + return PERF_REG_POWERPC_CTR; + case UNW_PPC64_XER: + return PERF_REG_POWERPC_XER; + case UNW_PPC64_NIP: + return PERF_REG_POWERPC_NIP; + default: + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } +#endif // HAVE_LIBUNWIND_PPC64_SUPPORT +} diff --git a/tools/perf/util/libunwind-arch/libunwind-s390.c b/tools/perf/u= til/libunwind-arch/libunwind-s390.c new file mode 100644 index 000000000000..9fcc7885ca55 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-s390.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/s390/include/uapi/asm/perf_regs.h" +#include +#include + +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_s390(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_S390X_SUPPORT + return -EINVAL; +#else + switch (unw_regnum) { + case UNW_S390X_R0 ... UNW_S390_R15: + return unw_regnum - UNW_S390_R0 + PERF_REG_S390_R0; + case UNW_S390X_F0 ... UNW_S390_F15: + return unw_regnum - UNW_S390_F0 + PERF_REG_S390_FP0; + case UNW_S390X_IP: + return PERF_REG_S390_PC; + default: + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } +#endif // HAVE_LIBUNWIND_S390X_SUPPORT +} diff --git a/tools/perf/util/libunwind-arch/libunwind-x86_64.c b/tools/perf= /util/libunwind-arch/libunwind-x86_64.c new file mode 100644 index 000000000000..6072e3597e61 --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-x86_64.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../../../arch/x86/include/uapi/asm/perf_regs.h" +#include +#include +#include + +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_X86_64_SUPPORT + return -EINVAL; +#else + static const int perf_x86_64_regnums[] =3D { +#define REGNUM(reg) [UNW_X86_64_R ## reg] =3D PERF_REG_X86_ ## reg + REGNUM(AX), + REGNUM(DX), + REGNUM(CX), + REGNUM(BX), + REGNUM(SI), + REGNUM(DI), + REGNUM(BP), + REGNUM(SP), + REGNUM(IP), +#undef REGNUM +#define REGNUM(reg) [UNW_X86_64_ ## reg] =3D PERF_REG_X86_ ## reg + REGNUM(R8), + REGNUM(R9), + REGNUM(R10), + REGNUM(R11), + REGNUM(R12), + REGNUM(R13), + REGNUM(R14), + REGNUM(R15), +#undef REGNUM + }; + + if (unw_regnum =3D=3D UNW_X86_64_RAX) + return PERF_REG_X86_AX; + + if (unw_regnum < 0 || unw_regnum > (int)ARRAY_SIZE(perf_x86_64_regnums) = || + perf_x86_64_regnums[unw_regnum] =3D=3D 0) { + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } + return perf_x86_64_regnums[unw_regnum]; +#endif // HAVE_LIBUNWIND_X86_64_SUPPORT +} diff --git a/tools/perf/util/libunwind/arm64.c b/tools/perf/util/libunwind/= arm64.c index 37ecef0c53b9..15670a964495 100644 --- a/tools/perf/util/libunwind/arm64.c +++ b/tools/perf/util/libunwind/arm64.c @@ -14,11 +14,6 @@ =20 #define REMOTE_UNWIND_LIBUNWIND =20 -/* Define arch specific functions & regs for libunwind, should be - * defined before including "unwind.h" - */ -#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arm64_reg_id(regnum) - #include "unwind.h" #include "libunwind-aarch64.h" #define perf_event_arm_regs perf_event_arm64_regs diff --git a/tools/perf/util/libunwind/x86_32.c b/tools/perf/util/libunwind= /x86_32.c index 1697dece1b74..1e9fb8bfec44 100644 --- a/tools/perf/util/libunwind/x86_32.c +++ b/tools/perf/util/libunwind/x86_32.c @@ -14,20 +14,8 @@ =20 #define REMOTE_UNWIND_LIBUNWIND =20 -/* Define arch specific functions & regs for libunwind, should be - * defined before including "unwind.h" - */ -#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__x86_reg_id(regnum) - #include "unwind.h" #include "libunwind-x86.h" -#include <../../../../arch/x86/include/uapi/asm/perf_regs.h> - -/* HAVE_ARCH_X86_64_SUPPORT is used in'arch/x86/util/unwind-libunwind.c' - * for x86_32, we undef it to compile code for x86_32 only. - */ -#undef HAVE_ARCH_X86_64_SUPPORT -#include "../../arch/x86/util/unwind-libunwind.c" =20 /* Explicitly define NO_LIBUNWIND_DEBUG_FRAME, because non-ARM has no * dwarf_find_debug_frame() function. diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unw= ind-libunwind-local.c index 5b39ce21e333..3ecdb468b859 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -40,6 +40,7 @@ #include "debug.h" #include "asm/bug.h" #include "dso.h" +#include "libunwind-arch/libunwind-arch.h" =20 extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, @@ -96,6 +97,7 @@ struct unwind_info { struct perf_sample *sample; struct machine *machine; struct thread *thread; + uint16_t e_machine; bool best_effort; }; =20 @@ -584,9 +586,7 @@ static int access_mem(unw_addr_space_t __maybe_unused a= s, } =20 ret =3D perf_reg_value(&start, perf_sample__user_regs(ui->sample), - perf_arch_reg_sp(thread__e_machine(ui->thread, - ui->machine, - /*e_flags=3D*/NULL))); + perf_arch_reg_sp(ui->e_machine)); if (ret) return ret; =20 @@ -634,7 +634,7 @@ static int access_reg(unw_addr_space_t __maybe_unused a= s, return 0; } =20 - id =3D LIBUNWIND__ARCH_REG_ID(regnum); + id =3D get_perf_regnum_for_unw_regnum(ui->e_machine, regnum); if (id < 0) return -EINVAL; =20 @@ -735,7 +735,6 @@ static void _unwind__finish_access(struct maps *maps) static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, void *arg, int max_stack) { - uint16_t e_machine =3D thread__e_machine(ui->thread, ui->machine, /*e_fla= gs=3D*/NULL); u64 val; unw_word_t ips[max_stack]; unw_addr_space_t addr_space; @@ -743,7 +742,7 @@ static int get_entries(struct unwind_info *ui, unwind_e= ntry_cb_t cb, int ret, i =3D 0; =20 ret =3D perf_reg_value(&val, perf_sample__user_regs(ui->sample), - perf_arch_reg_ip(e_machine)); + perf_arch_reg_ip(ui->e_machine)); if (ret) return ret; =20 @@ -806,6 +805,7 @@ static int _unwind__get_entries(unwind_entry_cb_t cb, v= oid *arg, .sample =3D data, .thread =3D thread, .machine =3D maps__machine(thread__maps(thread)), + .e_machine =3D thread__e_machine(thread, /*machine=3D*/NULL, /*e_flag= s=3D*/NULL), .best_effort =3D best_effort }; =20 diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index 9f7164c6d9aa..f13cb6390088 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -38,11 +38,6 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, bool best_effort); /* libunwind specific */ #ifdef HAVE_LIBUNWIND_SUPPORT -#ifndef LIBUNWIND__ARCH_REG_ID -#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arch_reg_id(regnum) -#endif - -int LIBUNWIND__ARCH_REG_ID(int regnum); int unwind__prepare_access(struct maps *maps, struct map *map, bool *initi= alized); void unwind__flush_access(struct maps *maps); void unwind__finish_access(struct maps *maps); --=20 2.53.0.371.g1d285c8824-goog From nobody Fri Apr 17 01:39:38 2026 Received: from mail-dl1-f73.google.com (mail-dl1-f73.google.com [74.125.82.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 722EF39E6EE for ; Tue, 24 Feb 2026 14:30:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943404; cv=none; b=SYIMMB/u92AdI1DTVQs7liQj8dfsvDP84aXDhsePkUatvvh8WAqOSqLDvMt9f/aH+cYIH6m1OYhN34kXCytru3EKM76SaKNqabehluw+b/F8iaInLVG8hdKvLZxalQ1IYEGhxoAM5KyRDQICWnldOaYFXjlK0jiJZ2qjKhce7es= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943404; c=relaxed/simple; bh=erAozNjUqyYu6guhpSY5i3CDb+IP2E2Lp1khK7G1VV8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=eRw/QPr8/uVx3k7ImwfrIMCmOPHoLyF291bYbjTN23bdS6e2b4acYhbB+Eud52nzuTot+3A2ByEjRSENizDFur3FAc3SCrhqVkwlJ+tfi8uSOHmPotzcaJMqIlKD7nOeYFB8IBfrsuzuoVHzyV2A1By9PxJUY0s9ume65CT0sck= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ZCrcd+3U; arc=none smtp.client-ip=74.125.82.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ZCrcd+3U" Received: by mail-dl1-f73.google.com with SMTP id a92af1059eb24-1270dcd11c1so7400424c88.0 for ; Tue, 24 Feb 2026 06:30:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1771943402; x=1772548202; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=/lB3BAGQE2BMrrHbc0CnVsZb8STXY1ehvHUhdt6oNmg=; b=ZCrcd+3UvpNDVqZvsbizpRbXrgudUprVGMPiDNWfbmBu6hvM6kGphNbqOjXpGkT7k4 ENZL0czProTy7B6dnp1p+AoL3mXcPFPzI2lHwPZ4CPdU72T15wg4O/o1cqBbpsFi2cLS wiPIQbuBBZyR+/USd8+PfgquNYilUmFRdoX2TnnnWjnol/yWOruj56d48fhXx6VO9bMF s/AqbkZsSPDnjSMHtYswrUBPnrsH9hRm5GrY4gR7J9ZZ9PLPbYGB+kySUyMm7vGG0qOT 1kUuvm5A0fKMqHzk04PbbY1zwGFyrDue0OaL/oPiskQ0WamUL3Ogg3ZsYDrRz8nvE45S kYig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771943402; x=1772548202; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=/lB3BAGQE2BMrrHbc0CnVsZb8STXY1ehvHUhdt6oNmg=; b=s0mawz1LeWtTlCQj7m1EzxK3J7s2vVXGEDNzAh+DGSe+zkpRV2vzBqHb/vkUgfRwUw B19FSFc1v9vGU7d1mzZ9BxZ/l3pjk+GDQ5gAQrFSMEXH95B96poFYGqjbypE+anFlzFN qPnssxHEcZ2yKaWSjqo7DghhtRViOC0bncC37nKtUsxUt3erxHgZsZ8isEJwfWd2YJMF XK8aqyK61T2+NRDbmBJNoA2n0yIYBHakBQ/BRY/vzD4W22PSq1l7fC1Li+aodrTYKSAH pRNjSumcs+7VNcDztf8IeohyN2T1ZJp1LufFO/BmfuBhF3q5rv67WwwvQYgKepJw0t7j BMrg== X-Forwarded-Encrypted: i=1; AJvYcCVOPfLZHp8m9TvvfxlNlEN/N4Sefe+6thMaN2EobotW1PPST9tMgaMb3aJRpPaGm3DLwSMJn/kylR/9CcM=@vger.kernel.org X-Gm-Message-State: AOJu0YyPRXhXRYhwI546ReBVy/8iHTSmWC9jjTNiESl7/2N0b3SYMfBg N1+nl4i5bYQVOgU87UF/ijSVfpqwv7vwVqckQbA2M1N5lovM0KuYaRUVYPTowb6o/uvumYknv3e TJaGBXBnCDw== X-Received: from dlbsv6.prod.google.com ([2002:a05:7022:3a06:b0:127:177b:bd24]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:fa4:b0:124:9acd:328e with SMTP id a92af1059eb24-1276ad61b41mr4501553c88.27.1771943401387; Tue, 24 Feb 2026 06:30:01 -0800 (PST) Date: Tue, 24 Feb 2026 06:29:35 -0800 In-Reply-To: <20260224142938.26088-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260224142938.26088-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.371.g1d285c8824-goog Message-ID: <20260224142938.26088-6-irogers@google.com> Subject: [RFC PATCH v1 5/7] perf unwind-libunwind: Move flush/finish access out of local From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , John Garry , Will Deacon , Leo Yan , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Dmitrii Dolgov <9erthalion6@gmail.com>, Blake Jones , Tomas Glozar , Yuzhuo Jing , Dapeng Mi , Shimin Guo , Athira Rajeev , Chun-Tse Shao , Howard Chu , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-riscv@lists.infradead.org, Thomas Richter , libunwind-devel@nongnu.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Flush and finish access are relatively simple calls into libunwind, move them out struct unwind_libunwind_ops. So that the correct version can be called, add an e_machine variable to maps. This size regression will go away when the unwind_libunwind_ops no longer need stashing in the maps. To set the e_machine up pass it into unwind__prepare_access, which no longer needs to determine the unwind operations based on a map dso because of this. This also means the maps copying code can call unwind__prepare_access once for the e_machine rather than once per map. Signed-off-by: Ian Rogers --- .../perf/util/libunwind-arch/libunwind-arch.c | 82 +++++++++++++++++++ .../perf/util/libunwind-arch/libunwind-arch.h | 24 ++++++ .../perf/util/libunwind-arch/libunwind-arm.c | 19 +++++ .../util/libunwind-arch/libunwind-arm64.c | 20 +++++ .../perf/util/libunwind-arch/libunwind-i386.c | 15 ++++ .../util/libunwind-arch/libunwind-loongarch.c | 15 ++++ .../perf/util/libunwind-arch/libunwind-mips.c | 15 ++++ .../util/libunwind-arch/libunwind-ppc32.c | 15 ++++ .../util/libunwind-arch/libunwind-ppc64.c | 15 ++++ .../perf/util/libunwind-arch/libunwind-s390.c | 15 ++++ .../util/libunwind-arch/libunwind-x86_64.c | 15 ++++ tools/perf/util/maps.c | 31 ++++--- tools/perf/util/maps.h | 2 + tools/perf/util/thread.c | 29 +------ tools/perf/util/unwind-libunwind-local.c | 12 --- tools/perf/util/unwind-libunwind.c | 61 +++++--------- tools/perf/util/unwind.h | 8 +- 17 files changed, 299 insertions(+), 94 deletions(-) diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.c b/tools/perf/u= til/libunwind-arch/libunwind-arch.c index 5439bf90d161..9692e6c81492 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arch.c +++ b/tools/perf/util/libunwind-arch/libunwind-arch.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include #include =20 @@ -30,3 +31,84 @@ int get_perf_regnum_for_unw_regnum(unsigned int e_machin= e, int unw_regnum) return -EINVAL; } } + + +void libunwind_arch__flush_access(struct maps *maps) +{ + unsigned int e_machine =3D maps__e_machine(maps); + + switch (e_machine) { + case EM_NONE: + break; // No libunwind info on the maps. + case EM_ARM: + __libunwind_arch__flush_access_arm(maps); + break; + case EM_AARCH64: + __libunwind_arch__flush_access_arm64(maps); + break; + case EM_LOONGARCH: + __libunwind_arch__flush_access_loongarch(maps); + break; + case EM_MIPS: + __libunwind_arch__flush_access_mips(maps); + break; + case EM_PPC: + __libunwind_arch__flush_access_ppc32(maps); + break; + case EM_PPC64: + __libunwind_arch__flush_access_ppc64(maps); + break; + case EM_S390: + __libunwind_arch__flush_access_s390(maps); + break; + case EM_386: + __libunwind_arch__flush_access_i386(maps); + break; + case EM_X86_64: + __libunwind_arch__flush_access_x86_64(maps); + break; + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + break; + } +} + +void libunwind_arch__finish_access(struct maps *maps) +{ + unsigned int e_machine =3D maps__e_machine(maps); + + switch (e_machine) { + case EM_NONE: + break; // No libunwind info on the maps. + case EM_ARM: + __libunwind_arch__finish_access_arm(maps); + break; + case EM_AARCH64: + __libunwind_arch__finish_access_arm64(maps); + break; + case EM_LOONGARCH: + __libunwind_arch__finish_access_loongarch(maps); + break; + case EM_MIPS: + __libunwind_arch__finish_access_mips(maps); + break; + case EM_PPC: + __libunwind_arch__finish_access_ppc32(maps); + break; + case EM_PPC64: + __libunwind_arch__finish_access_ppc64(maps); + break; + case EM_S390: + __libunwind_arch__finish_access_s390(maps); + break; + case EM_386: + __libunwind_arch__finish_access_i386(maps); + break; + case EM_X86_64: + __libunwind_arch__finish_access_x86_64(maps); + break; + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + break; + } +} diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.h b/tools/perf/u= til/libunwind-arch/libunwind-arch.h index e1009c6cb965..c00277a5e914 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arch.h +++ b/tools/perf/util/libunwind-arch/libunwind-arch.h @@ -2,6 +2,8 @@ #ifndef __LIBUNWIND_ARCH_H #define __LIBUNWIND_ARCH_H =20 +struct maps; + int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum); int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum); int __get_perf_regnum_for_unw_regnum_loongarch(int unw_regnum); @@ -13,4 +15,26 @@ int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum= ); int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum); int get_perf_regnum_for_unw_regnum(unsigned int e_machine, int unw_regnum); =20 +void __libunwind_arch__flush_access_arm(struct maps *maps); +void __libunwind_arch__flush_access_arm64(struct maps *maps); +void __libunwind_arch__flush_access_loongarch(struct maps *maps); +void __libunwind_arch__flush_access_mips(struct maps *maps); +void __libunwind_arch__flush_access_ppc32(struct maps *maps); +void __libunwind_arch__flush_access_ppc64(struct maps *maps); +void __libunwind_arch__flush_access_s390(struct maps *maps); +void __libunwind_arch__flush_access_i386(struct maps *maps); +void __libunwind_arch__flush_access_x86_64(struct maps *maps); +void libunwind_arch__flush_access(struct maps *maps); + +void __libunwind_arch__finish_access_arm(struct maps *maps); +void __libunwind_arch__finish_access_arm64(struct maps *maps); +void __libunwind_arch__finish_access_loongarch(struct maps *maps); +void __libunwind_arch__finish_access_mips(struct maps *maps); +void __libunwind_arch__finish_access_ppc32(struct maps *maps); +void __libunwind_arch__finish_access_ppc64(struct maps *maps); +void __libunwind_arch__finish_access_s390(struct maps *maps); +void __libunwind_arch__finish_access_i386(struct maps *maps); +void __libunwind_arch__finish_access_x86_64(struct maps *maps); +void libunwind_arch__finish_access(struct maps *maps); + #endif /* __LIBUNWIND_ARCH_H */ diff --git a/tools/perf/util/libunwind-arch/libunwind-arm.c b/tools/perf/ut= il/libunwind-arch/libunwind-arm.c index 6740ee55b043..bbaf01406c52 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arm.c +++ b/tools/perf/util/libunwind-arch/libunwind-arm.c @@ -1,10 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/arm/include/uapi/asm/perf_regs.h" #include #include =20 +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT +#include +#endif + int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum) { if (unw_regnum < 0 || unw_regnum >=3D PERF_REG_ARM_MAX) { @@ -13,3 +18,17 @@ int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum) } return unw_regnum; } + +void __libunwind_arch__flush_access_arm(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_arm(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-arm64.c b/tools/perf/= util/libunwind-arch/libunwind-arm64.c index 53b1877dfa04..8ba510089736 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arm64.c +++ b/tools/perf/util/libunwind-arch/libunwind-arm64.c @@ -1,9 +1,15 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/arm64/include/uapi/asm/perf_regs.h" +#include #include =20 +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT +#include +#endif + int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum) { if (unw_regnum < 0 || unw_regnum >=3D PERF_REG_ARM64_EXTENDED_MAX) { @@ -12,3 +18,17 @@ int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnu= m) } return unw_regnum; } + +void __libunwind_arch__flush_access_arm64(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_arm64(struct maps *maps __maybe_unuse= d) +{ +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-i386.c b/tools/perf/u= til/libunwind-arch/libunwind-i386.c index 83bef77bddfd..a0dcaa10578e 100644 --- a/tools/perf/util/libunwind-arch/libunwind-i386.c +++ b/tools/perf/util/libunwind-arch/libunwind-i386.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/x86/include/uapi/asm/perf_regs.h" #include #include @@ -41,3 +42,17 @@ int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum= __maybe_unused) return perf_i386_regnums[unw_regnum]; #endif // HAVE_LIBUNWIND_X86_SUPPORT } + +void __libunwind_arch__flush_access_i386(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_i386(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-loongarch.c b/tools/p= erf/util/libunwind-arch/libunwind-loongarch.c index 7009410989bc..837aa11e2b9f 100644 --- a/tools/perf/util/libunwind-arch/libunwind-loongarch.c +++ b/tools/perf/util/libunwind-arch/libunwind-loongarch.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/loongarch/include/uapi/asm/perf_regs.h" #include #include @@ -25,3 +26,17 @@ int __get_perf_regnum_for_unw_regnum_loongarch(int unw_r= egnum __maybe_unused) } #endif // HAVE_LIBUNWIND_LOONGARCH64_SUPPORT } + +void __libunwind_arch__flush_access_loongarch(struct maps *maps __maybe_un= used) +{ +#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_loongarch(struct maps *maps __maybe_u= nused) +{ +#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-mips.c b/tools/perf/u= til/libunwind-arch/libunwind-mips.c index 01a506c8079c..1fa81742ff4a 100644 --- a/tools/perf/util/libunwind-arch/libunwind-mips.c +++ b/tools/perf/util/libunwind-arch/libunwind-mips.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/mips/include/uapi/asm/perf_regs.h" #include #include @@ -27,3 +28,17 @@ int __get_perf_regnum_for_unw_regnum_mips(int unw_regnum= __maybe_unused) } #endif // HAVE_LIBUNWIND_MIPS_SUPPORT } + +void __libunwind_arch__flush_access_mips(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_mips(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc32.c b/tools/perf/= util/libunwind-arch/libunwind-ppc32.c index edcb0ec95dd7..fa8471c74bf3 100644 --- a/tools/perf/util/libunwind-arch/libunwind-ppc32.c +++ b/tools/perf/util/libunwind-arch/libunwind-ppc32.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/powerpc/include/uapi/asm/perf_regs.h" #include #include @@ -29,3 +30,17 @@ int __get_perf_regnum_for_unw_regnum_ppc32(int unw_regnu= m __maybe_unused) } #endif // HAVE_LIBUNWIND_PPC32_SUPPORT } + +void __libunwind_arch__flush_access_ppc32(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_ppc32(struct maps *maps __maybe_unuse= d) +{ +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc64.c b/tools/perf/= util/libunwind-arch/libunwind-ppc64.c index 9f57a049600b..2f746e347336 100644 --- a/tools/perf/util/libunwind-arch/libunwind-ppc64.c +++ b/tools/perf/util/libunwind-arch/libunwind-ppc64.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/powerpc/include/uapi/asm/perf_regs.h" #include #include @@ -31,3 +32,17 @@ int __get_perf_regnum_for_unw_regnum_ppc64(int unw_regnu= m __maybe_unused) } #endif // HAVE_LIBUNWIND_PPC64_SUPPORT } + +void __libunwind_arch__flush_access_ppc64(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_ppc64(struct maps *maps __maybe_unuse= d) +{ +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-s390.c b/tools/perf/u= til/libunwind-arch/libunwind-s390.c index 9fcc7885ca55..9f68d15438b2 100644 --- a/tools/perf/util/libunwind-arch/libunwind-s390.c +++ b/tools/perf/util/libunwind-arch/libunwind-s390.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/s390/include/uapi/asm/perf_regs.h" #include #include @@ -27,3 +28,17 @@ int __get_perf_regnum_for_unw_regnum_s390(int unw_regnum= __maybe_unused) } #endif // HAVE_LIBUNWIND_S390X_SUPPORT } + +void __libunwind_arch__flush_access_s390(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_s390(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-x86_64.c b/tools/perf= /util/libunwind-arch/libunwind-x86_64.c index 6072e3597e61..25e326bd3e15 100644 --- a/tools/perf/util/libunwind-arch/libunwind-x86_64.c +++ b/tools/perf/util/libunwind-arch/libunwind-x86_64.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "libunwind-arch.h" #include "../debug.h" +#include "../maps.h" #include "../../../arch/x86/include/uapi/asm/perf_regs.h" #include #include @@ -50,3 +51,17 @@ int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regn= um __maybe_unused) return perf_x86_64_regnums[unw_regnum]; #endif // HAVE_LIBUNWIND_X86_64_SUPPORT } + +void __libunwind_arch__flush_access_x86_64(struct maps *maps __maybe_unuse= d) +{ +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_x86_64(struct maps *maps __maybe_unus= ed) +{ +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 4092211cff62..8c7b2a1e7642 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -40,6 +40,7 @@ DECLARE_RC_STRUCT(maps) { #ifdef HAVE_LIBUNWIND_SUPPORT void *addr_space; const struct unwind_libunwind_ops *unwind_libunwind_ops; + uint16_t e_machine; #endif #ifdef HAVE_LIBDW_SUPPORT void *libdw_addr_space_dwfl; @@ -206,6 +207,16 @@ void maps__set_unwind_libunwind_ops(struct maps *maps,= const struct unwind_libun { RC_CHK_ACCESS(maps)->unwind_libunwind_ops =3D ops; } + +uint16_t maps__e_machine(const struct maps *maps) +{ + return RC_CHK_ACCESS(maps)->e_machine; +} + +void maps__set_e_machine(struct maps *maps, uint16_t e_machine) +{ + RC_CHK_ACCESS(maps)->e_machine =3D e_machine; +} #endif #ifdef HAVE_LIBDW_SUPPORT void *maps__libdw_addr_space_dwfl(const struct maps *maps) @@ -1038,6 +1049,9 @@ int maps__copy_from(struct maps *dest, struct maps *p= arent) down_write(maps__lock(dest)); down_read(maps__lock(parent)); =20 +#ifdef HAVE_LIBUNWIND_SUPPORT + unwind__prepare_access(dest, maps__e_machine(parent)); +#endif parent_maps_by_address =3D maps__maps_by_address(parent); n =3D maps__nr_maps(parent); if (maps__nr_maps(dest) =3D=3D 0) { @@ -1067,14 +1081,11 @@ int maps__copy_from(struct maps *dest, struct maps = *parent) if (!new) err =3D -ENOMEM; else { - err =3D unwind__prepare_access(dest, new, NULL); - if (!err) { - dest_maps_by_address[i] =3D new; - map__set_kmap_maps(new, dest); - if (dest_maps_by_name) - dest_maps_by_name[i] =3D map__get(new); - RC_CHK_ACCESS(dest)->nr_maps =3D i + 1; - } + dest_maps_by_address[i] =3D new; + map__set_kmap_maps(new, dest); + if (dest_maps_by_name) + dest_maps_by_name[i] =3D map__get(new); + RC_CHK_ACCESS(dest)->nr_maps =3D i + 1; } if (err) map__put(new); @@ -1099,9 +1110,7 @@ int maps__copy_from(struct maps *dest, struct maps *p= arent) if (!new) err =3D -ENOMEM; else { - err =3D unwind__prepare_access(dest, new, NULL); - if (!err) - err =3D __maps__insert(dest, new); + err =3D __maps__insert(dest, new); } map__put(new); } diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h index 20c52084ba9e..6469f62c41a8 100644 --- a/tools/perf/util/maps.h +++ b/tools/perf/util/maps.h @@ -51,6 +51,8 @@ void *maps__addr_space(const struct maps *maps); void maps__set_addr_space(struct maps *maps, void *addr_space); const struct unwind_libunwind_ops *maps__unwind_libunwind_ops(const struct= maps *maps); void maps__set_unwind_libunwind_ops(struct maps *maps, const struct unwind= _libunwind_ops *ops); +uint16_t maps__e_machine(const struct maps *maps); +void maps__set_e_machine(struct maps *maps, uint16_t e_machine); #endif #ifdef HAVE_LIBDW_SUPPORT void *maps__libdw_addr_space_dwfl(const struct maps *maps); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 22be77225bb0..c5df11ad329c 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -358,41 +358,20 @@ size_t thread__fprintf(struct thread *thread, FILE *f= p) int thread__insert_map(struct thread *thread, struct map *map) { int ret; + uint16_t e_machine =3D thread__e_machine(thread, /*machine=3D*/NULL, /*e_= flags=3D*/NULL); =20 - ret =3D unwind__prepare_access(thread__maps(thread), map, NULL); + ret =3D unwind__prepare_access(thread__maps(thread), e_machine); if (ret) return ret; =20 return maps__fixup_overlap_and_insert(thread__maps(thread), map); } =20 -struct thread__prepare_access_maps_cb_args { - int err; - struct maps *maps; -}; - -static int thread__prepare_access_maps_cb(struct map *map, void *data) -{ - bool initialized =3D false; - struct thread__prepare_access_maps_cb_args *args =3D data; - - args->err =3D unwind__prepare_access(args->maps, map, &initialized); - - return (args->err || initialized) ? 1 : 0; -} - static int thread__prepare_access(struct thread *thread) { - struct thread__prepare_access_maps_cb_args args =3D { - .err =3D 0, - }; - - if (dwarf_callchain_users) { - args.maps =3D thread__maps(thread); - maps__for_each_map(thread__maps(thread), thread__prepare_access_maps_cb,= &args); - } + uint16_t e_machine =3D thread__e_machine(thread, /*machine=3D*/NULL, /*e_= flags=3D*/NULL); =20 - return args.err; + return unwind__prepare_access(thread__maps(thread), e_machine); } =20 static int thread__clone_maps(struct thread *thread, struct thread *parent= , bool do_maps_clone) diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unw= ind-libunwind-local.c index 3ecdb468b859..8f0128ba05a7 100644 --- a/tools/perf/util/unwind-libunwind-local.c +++ b/tools/perf/util/unwind-libunwind-local.c @@ -722,16 +722,6 @@ static int _unwind__prepare_access(struct maps *maps) return 0; } =20 -static void _unwind__flush_access(struct maps *maps) -{ - unw_flush_cache(maps__addr_space(maps), 0, 0); -} - -static void _unwind__finish_access(struct maps *maps) -{ - unw_destroy_addr_space(maps__addr_space(maps)); -} - static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, void *arg, int max_stack) { @@ -821,8 +811,6 @@ static int _unwind__get_entries(unwind_entry_cb_t cb, v= oid *arg, static struct unwind_libunwind_ops _unwind_libunwind_ops =3D { .prepare_access =3D _unwind__prepare_access, - .flush_access =3D _unwind__flush_access, - .finish_access =3D _unwind__finish_access, .get_entries =3D _unwind__get_entries, }; =20 diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-li= bunwind.c index cb8be6acfb6f..816891ecfa5e 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -7,76 +7,55 @@ #include "debug.h" #include "env.h" #include "callchain.h" +#include "libunwind-arch/libunwind-arch.h" +#include +#include =20 struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops; struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops; struct unwind_libunwind_ops __weak *arm64_unwind_libunwind_ops; =20 -int unwind__prepare_access(struct maps *maps, struct map *map, bool *initi= alized) +int unwind__prepare_access(struct maps *maps, uint16_t e_machine) { - const char *arch; - enum dso_type dso_type; struct unwind_libunwind_ops *ops =3D local_unwind_libunwind_ops; - struct dso *dso =3D map__dso(map); - struct machine *machine; - int err; =20 if (!dwarf_callchain_users) return 0; =20 if (maps__addr_space(maps)) { - pr_debug("unwind: thread map already set, dso=3D%s\n", dso__name(dso)); - if (initialized) - *initialized =3D true; + pr_debug3("unwind: thread map already set\n"); return 0; } =20 - machine =3D maps__machine(maps); - /* env->arch is NULL for live-mode (i.e. perf top) */ - if (!machine->env || !machine->env->arch) - goto out_register; - - dso_type =3D dso__type(dso, machine); - if (dso_type =3D=3D DSO__TYPE_UNKNOWN) - return 0; - - arch =3D perf_env__arch(machine->env); - - if (!strcmp(arch, "x86")) { - if (dso_type !=3D DSO__TYPE_64BIT) + if (e_machine !=3D EM_HOST) { + /* If not live/local mode. */ + switch (e_machine) { + case EM_386: ops =3D x86_32_unwind_libunwind_ops; - } else if (!strcmp(arch, "arm64") || !strcmp(arch, "arm")) { - if (dso_type =3D=3D DSO__TYPE_64BIT) + break; + case EM_AARCH64: ops =3D arm64_unwind_libunwind_ops; - } - - if (!ops) { - pr_warning_once("unwind: target platform=3D%s is not supported\n", arch); + break; + default: + pr_warning_once("unwind: ELF machine type %d is not supported\n", + e_machine); return 0; + } } -out_register: maps__set_unwind_libunwind_ops(maps, ops); + maps__set_e_machine(maps, e_machine); =20 - err =3D maps__unwind_libunwind_ops(maps)->prepare_access(maps); - if (initialized) - *initialized =3D err ? false : true; - return err; + return maps__unwind_libunwind_ops(maps)->prepare_access(maps); } =20 void unwind__flush_access(struct maps *maps) { - const struct unwind_libunwind_ops *ops =3D maps__unwind_libunwind_ops(map= s); - - if (ops) - ops->flush_access(maps); + libunwind_arch__flush_access(maps); } =20 void unwind__finish_access(struct maps *maps) { - const struct unwind_libunwind_ops *ops =3D maps__unwind_libunwind_ops(map= s); - - if (ops) - ops->finish_access(maps); + libunwind_arch__finish_access(maps); } =20 int unwind__get_entries(unwind_entry_cb_t cb, void *arg, diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h index f13cb6390088..d3d0f3650f83 100644 --- a/tools/perf/util/unwind.h +++ b/tools/perf/util/unwind.h @@ -2,6 +2,7 @@ #ifndef __UNWIND_H #define __UNWIND_H =20 +#include #include #include #include "util/map_symbol.h" @@ -19,8 +20,6 @@ typedef int (*unwind_entry_cb_t)(struct unwind_entry *ent= ry, void *arg); =20 struct unwind_libunwind_ops { int (*prepare_access)(struct maps *maps); - void (*flush_access)(struct maps *maps); - void (*finish_access)(struct maps *maps); int (*get_entries)(unwind_entry_cb_t cb, void *arg, struct thread *thread, struct perf_sample *data, int max_stack, bool best_effort); @@ -38,13 +37,12 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, bool best_effort); /* libunwind specific */ #ifdef HAVE_LIBUNWIND_SUPPORT -int unwind__prepare_access(struct maps *maps, struct map *map, bool *initi= alized); +int unwind__prepare_access(struct maps *maps, uint16_t e_machine); void unwind__flush_access(struct maps *maps); void unwind__finish_access(struct maps *maps); #else static inline int unwind__prepare_access(struct maps *maps __maybe_unused, - struct map *map __maybe_unused, - bool *initialized __maybe_unused) + uint16_t e_machine __maybe_unused) { return 0; } --=20 2.53.0.371.g1d285c8824-goog From nobody Fri Apr 17 01:39:38 2026 Received: from mail-dl1-f73.google.com (mail-dl1-f73.google.com [74.125.82.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D7A173A0E8B for ; Tue, 24 Feb 2026 14:30:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943411; cv=none; b=cAyOVEcCpiofQZkNm4VEb2UH+hdtnrEB6ae8/CKIRH4mI9SOa3tcfzSxwowt2C88sjDdjrdZaXW/7t1ilj2zCFj2m6p0IsvqdOWWPVDT6IbP7ollfZUxGIH0bJoDClzhTm6f+0j1ixg2nteJg8YA/Egz7Ow6RfJiq4P7NXWh+X4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943411; c=relaxed/simple; bh=TIt0dz6WonjzF3bp4jeJH8Bni81OHj7nOD/lBgqSh6E=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=IjEAyLZbcbCYNEvAEIKdc9YibEKeJPHTcAxcKfg2B0J8F+2HbsxoO4jrNbXdppkI9R9UVb+h/1e2DzXsccS6IgLIjwiYpw7Fj8JpQC/DHukh5ZkaFKQYukLwZsGabzxWVG/40j0wIc7AHX+iD8YMJUvbaG/knOb8NK7ZzEGG1yY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Bm4z5iH3; arc=none smtp.client-ip=74.125.82.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Bm4z5iH3" Received: by mail-dl1-f73.google.com with SMTP id a92af1059eb24-1277896014fso25587982c88.1 for ; Tue, 24 Feb 2026 06:30:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1771943404; x=1772548204; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=0xSLsIEVQq6LfeKnG5ahObFDsFE7ATbQnfrKYT0sabs=; b=Bm4z5iH3tDj6zvIXCiqn7PyJ9/btLjxiOLvzrw+ISjHJOd3LHp7nfcBzwwVoP3JyFl E7dxhc4y4IjKNgiWXmuBLxXBuQ78Iv4V6IOXpDcLsmH4viBhIRYk1AIxJRkBHW2zItB2 tOQqnH0LNMeGmjjvDjQKlbmlRbETjUkrDgdf8p+1O0d6NsqthNa2nJ3r26T++K8KGeH2 WtxjeiBbJ9yEFV6A39CxcopCYfve8/PwCJT1hdHlNBKPKyxXqtEjK0lf7VdXMr7RftBk VDR9S8lHvJrzfv2CoKdMrmAahTJyXoq3g60x1ThlA49EcuT0Crt9w1vVVYPYq2+Zo5mm l37g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771943404; x=1772548204; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=0xSLsIEVQq6LfeKnG5ahObFDsFE7ATbQnfrKYT0sabs=; b=FD4/LP4XzlgAG1aJYsxjssozqWezlMLG5ToSbnQtCfniH0lTEmvk2FN2R8OvQ7mPl3 ycnOHhc+ViC6iLWviuL/2hzcVKA3VSbnxz+X37tDj7AYL2Bxb6NjJkdrZnySaxZDPHUD ppTyOw80EMbDk4YUT+kACzsezgRgf+eDFA1ZHIX6mrb9o4/AeoMEmoptcUzCybilakPE We6shl5FgBam7s4qbjM4mhVWCQdm6aMwR4jQzzqBcOkOnZZG76+rzh3fERj/c7+Wq2Qo PVxbayMym31YS8Y1+rAvmW5FZiZX0V0IV9nDXvgAC5Dnca09L2koC5OBcyf80Hre3PyG wUaQ== X-Forwarded-Encrypted: i=1; AJvYcCVKMOv1endXYGw9s2OEJudZpzuLPEyJzzE5eRrE+HEpaFd8Ajk/HB89YBwqT1Up2xepOloIo7PqCsD81ho=@vger.kernel.org X-Gm-Message-State: AOJu0YxC/iEfrvhoaAskbiRjOYF/NX/YUG31mLYt/TyynKf7I0Q14nB+ cZG7DBOVYJmWdRuT1Iy3ofnZjS2vqEHve1cklltVe6AHjC571WolHmObtM4Degijf3F7Cyl5jwR lc7J4jUzvFw== X-Received: from dlkk14.prod.google.com ([2002:a05:7022:608e:b0:127:d50:fca6]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:2513:b0:11b:9386:a3cb with SMTP id a92af1059eb24-1276ad92a35mr6069559c88.44.1771943403787; Tue, 24 Feb 2026 06:30:03 -0800 (PST) Date: Tue, 24 Feb 2026 06:29:36 -0800 In-Reply-To: <20260224142938.26088-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260224142938.26088-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.371.g1d285c8824-goog Message-ID: <20260224142938.26088-7-irogers@google.com> Subject: [RFC PATCH v1 6/7] perf unwind-libunwind: Remove libunwind-local From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , John Garry , Will Deacon , Leo Yan , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Dmitrii Dolgov <9erthalion6@gmail.com>, Blake Jones , Tomas Glozar , Yuzhuo Jing , Dapeng Mi , Shimin Guo , Athira Rajeev , Chun-Tse Shao , Howard Chu , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-riscv@lists.infradead.org, Thomas Richter , libunwind-devel@nongnu.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Local unwinding only works on the machine libunwind is built for, rather than cross platform, the APIs for remote and local unwinding are similar but types like unw_word_t depend on the included header. Place the architecture specific code into the appropriate libunwind-.c file. Put generic code in unwind-libunwind.c and use libunwind-arch to choose the correct implementation based on the thread's e_machine. Structuring the code this way avoids including the unwind-libunwind-local.c for each architecture of remote unwinding. Data is moved into the struct unwind_info to simplify the architecture and generic code, trying to keep as much code as possible generic. Signed-off-by: Ian Rogers --- tools/perf/util/Build | 3 - .../perf/util/libunwind-arch/libunwind-arch.c | 184 ++++ .../perf/util/libunwind-arch/libunwind-arch.h | 234 +++++ .../perf/util/libunwind-arch/libunwind-arm.c | 256 ++++++ .../util/libunwind-arch/libunwind-arm64.c | 255 ++++++ .../perf/util/libunwind-arch/libunwind-i386.c | 254 ++++++ .../util/libunwind-arch/libunwind-loongarch.c | 255 ++++++ .../perf/util/libunwind-arch/libunwind-mips.c | 255 ++++++ .../util/libunwind-arch/libunwind-ppc32.c | 255 ++++++ .../util/libunwind-arch/libunwind-ppc64.c | 255 ++++++ .../perf/util/libunwind-arch/libunwind-s390.c | 255 ++++++ .../util/libunwind-arch/libunwind-x86_64.c | 253 ++++++ tools/perf/util/libunwind/arm64.c | 35 - tools/perf/util/libunwind/x86_32.c | 29 - tools/perf/util/maps.c | 10 - tools/perf/util/maps.h | 2 - tools/perf/util/unwind-libunwind-local.c | 820 ------------------ tools/perf/util/unwind-libunwind.c | 654 +++++++++++++- 18 files changed, 3334 insertions(+), 930 deletions(-) delete mode 100644 tools/perf/util/libunwind/arm64.c delete mode 100644 tools/perf/util/libunwind/x86_32.c delete mode 100644 tools/perf/util/unwind-libunwind-local.c diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 1964e13e3085..44685eec7615 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -227,11 +227,8 @@ perf-util-$(CONFIG_LIBDW) +=3D annotate-data.o perf-util-$(CONFIG_LIBDW) +=3D libdw.o perf-util-$(CONFIG_LIBDW) +=3D unwind-libdw.o =20 -perf-util-$(CONFIG_LOCAL_LIBUNWIND) +=3D unwind-libunwind-local.o perf-util-$(CONFIG_LIBUNWIND) +=3D unwind-libunwind.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-arch/ -perf-util-$(CONFIG_LIBUNWIND_X86) +=3D libunwind/x86_32.o -perf-util-$(CONFIG_LIBUNWIND_AARCH64) +=3D libunwind/arm64.o =20 ifeq ($(CONFIG_LIBTRACEEVENT),y) perf-util-$(CONFIG_LIBBABELTRACE) +=3D data-convert-bt.o diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.c b/tools/perf/u= til/libunwind-arch/libunwind-arch.c index 9692e6c81492..8539b4233df4 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arch.c +++ b/tools/perf/util/libunwind-arch/libunwind-arch.c @@ -112,3 +112,187 @@ void libunwind_arch__finish_access(struct maps *maps) break; } } + +void *libunwind_arch__create_addr_space(unsigned int e_machine) +{ + switch (e_machine) { + case EM_ARM: + return __libunwind_arch__create_addr_space_arm(); + case EM_AARCH64: + return __libunwind_arch__create_addr_space_arm64(); + case EM_LOONGARCH: + return __libunwind_arch__create_addr_space_loongarch(); + case EM_MIPS: + return __libunwind_arch__create_addr_space_mips(); + case EM_PPC: + return __libunwind_arch__create_addr_space_ppc32(); + case EM_PPC64: + return __libunwind_arch__create_addr_space_ppc64(); + case EM_S390: + return __libunwind_arch__create_addr_space_s390(); + case EM_386: + return __libunwind_arch__create_addr_space_i386(); + case EM_X86_64: + return __libunwind_arch__create_addr_space_x86_64(); + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + return NULL; + } +} + +int libunwind_arch__dwarf_search_unwind_table(unsigned int e_machine, + void *as, + uint64_t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg) +{ + switch (e_machine) { + case EM_ARM: + return __libunwind_arch__dwarf_search_unwind_table_arm(as, ip, di, pi, + need_unwind_info, arg); + case EM_AARCH64: + return __libunwind_arch__dwarf_search_unwind_table_arm64(as, ip, di, pi, + need_unwind_info, arg); + case EM_LOONGARCH: + return __libunwind_arch__dwarf_search_unwind_table_loongarch(as, ip, di,= pi, + need_unwind_info, arg); + case EM_MIPS: + return __libunwind_arch__dwarf_search_unwind_table_mips(as, ip, di, pi, + need_unwind_info, arg); + case EM_PPC: + return __libunwind_arch__dwarf_search_unwind_table_ppc32(as, ip, di, pi, + need_unwind_info, arg); + case EM_PPC64: + return __libunwind_arch__dwarf_search_unwind_table_ppc64(as, ip, di, pi, + need_unwind_info, arg); + case EM_S390: + return __libunwind_arch__dwarf_search_unwind_table_s390(as, ip, di, pi, + need_unwind_info, arg); + case EM_386: + return __libunwind_arch__dwarf_search_unwind_table_i386(as, ip, di, pi, + need_unwind_info, arg); + case EM_X86_64: + return __libunwind_arch__dwarf_search_unwind_table_x86_64(as, ip, di, pi, + need_unwind_info, arg); + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + return -EINVAL; + } +} + +int libunwind_arch__dwarf_find_debug_frame(unsigned int e_machine, + int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end) +{ + switch (e_machine) { + case EM_ARM: + return __libunwind_arch__dwarf_find_debug_frame_arm(found, di_debug, ip,= segbase, + obj_name, start, end); + case EM_AARCH64: + return __libunwind_arch__dwarf_find_debug_frame_arm64(found, di_debug, i= p, segbase, + obj_name, start, end); + case EM_LOONGARCH: + return __libunwind_arch__dwarf_find_debug_frame_loongarch(found, di_debu= g, ip, + segbase, obj_name, + start, end); + case EM_MIPS: + return __libunwind_arch__dwarf_find_debug_frame_mips(found, di_debug, ip= , segbase, + obj_name, start, end); + case EM_PPC: + return __libunwind_arch__dwarf_find_debug_frame_ppc32(found, di_debug, i= p, segbase, + obj_name, start, end); + case EM_PPC64: + return __libunwind_arch__dwarf_find_debug_frame_ppc64(found, di_debug, i= p, segbase, + obj_name, start, end); + case EM_S390: + return __libunwind_arch__dwarf_find_debug_frame_s390(found, di_debug, ip= , segbase, + obj_name, start, end); + case EM_386: + return __libunwind_arch__dwarf_find_debug_frame_i386(found, di_debug, ip= , segbase, + obj_name, start, end); + case EM_X86_64: + return __libunwind_arch__dwarf_find_debug_frame_x86_64(found, di_debug, = ip, segbase, + obj_name, start, end); + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + return -EINVAL; + } +} + +struct unwind_info *libunwind_arch_unwind_info__new(struct thread *thread, + struct perf_sample *sample, int max_stack, + bool best_effort, uint16_t e_machine, + uint64_t first_ip) +{ + switch (e_machine) { + case EM_ARM: + return __libunwind_arch_unwind_info__new_arm(thread, sample, max_stack, + best_effort, first_ip); + case EM_AARCH64: + return __libunwind_arch_unwind_info__new_arm64(thread, sample, max_stack, + best_effort, first_ip); + case EM_LOONGARCH: + return __libunwind_arch_unwind_info__new_loongarch(thread, sample, max_s= tack, + best_effort, first_ip); + case EM_MIPS: + return __libunwind_arch_unwind_info__new_mips(thread, sample, max_stack, + best_effort, first_ip); + case EM_PPC: + return __libunwind_arch_unwind_info__new_ppc32(thread, sample, max_stack, + best_effort, first_ip); + case EM_PPC64: + return __libunwind_arch_unwind_info__new_ppc64(thread, sample, max_stack, + best_effort, first_ip); + case EM_S390: + return __libunwind_arch_unwind_info__new_s390(thread, sample, max_stack, + best_effort, first_ip); + case EM_386: + return __libunwind_arch_unwind_info__new_i386(thread, sample, max_stack, + best_effort, first_ip); + case EM_X86_64: + return __libunwind_arch_unwind_info__new_x86_64(thread, sample, max_stac= k, + best_effort, first_ip); + default: + pr_err("ELF MACHINE %x is not supported.\n", e_machine); + return NULL; + } +} + +void libunwind_arch_unwind_info__delete(struct unwind_info *ui) +{ + free(ui); +} + +int libunwind_arch__unwind_step(struct unwind_info *ui) +{ + switch (ui->e_machine) { + case EM_ARM: + return __libunwind_arch__unwind_step_arm(ui); + case EM_AARCH64: + return __libunwind_arch__unwind_step_arm64(ui); + case EM_LOONGARCH: + return __libunwind_arch__unwind_step_loongarch(ui); + case EM_MIPS: + return __libunwind_arch__unwind_step_mips(ui); + case EM_PPC: + return __libunwind_arch__unwind_step_ppc32(ui); + case EM_PPC64: + return __libunwind_arch__unwind_step_ppc64(ui); + case EM_S390: + return __libunwind_arch__unwind_step_s390(ui); + case EM_386: + return __libunwind_arch__unwind_step_i386(ui); + case EM_X86_64: + return __libunwind_arch__unwind_step_x86_64(ui); + default: + pr_err("ELF MACHINE %x is not supported.\n", ui->e_machine); + return -EINVAL; + } +} diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.h b/tools/perf/u= til/libunwind-arch/libunwind-arch.h index c00277a5e914..2bf7fc33313b 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arch.h +++ b/tools/perf/util/libunwind-arch/libunwind-arch.h @@ -2,7 +2,36 @@ #ifndef __LIBUNWIND_ARCH_H #define __LIBUNWIND_ARCH_H =20 +#include +#include +#include + +struct machine; struct maps; +struct perf_sample; +struct thread; + +struct unwind_info { + struct machine *machine; + struct thread *thread; + struct perf_sample *sample; + void *cursor; + uint64_t *ips; + int cur_ip; + int max_ips; + unsigned int unw_word_t_size; + uint16_t e_machine; + bool best_effort; +}; + +struct libarch_unwind__dyn_info { + uint64_t start_ip; + uint64_t end_ip; + uint64_t segbase; + uint64_t table_data; + uint64_t table_len; +}; +struct libarch_unwind__proc_info; =20 int __get_perf_regnum_for_unw_regnum_arm(int unw_regnum); int __get_perf_regnum_for_unw_regnum_arm64(int unw_regnum); @@ -37,4 +66,209 @@ void __libunwind_arch__finish_access_i386(struct maps *= maps); void __libunwind_arch__finish_access_x86_64(struct maps *maps); void libunwind_arch__finish_access(struct maps *maps); =20 +void *__libunwind_arch__create_addr_space_arm(void); +void *__libunwind_arch__create_addr_space_arm64(void); +void *__libunwind_arch__create_addr_space_loongarch(void); +void *__libunwind_arch__create_addr_space_mips(void); +void *__libunwind_arch__create_addr_space_ppc32(void); +void *__libunwind_arch__create_addr_space_ppc64(void); +void *__libunwind_arch__create_addr_space_s390(void); +void *__libunwind_arch__create_addr_space_i386(void); +void *__libunwind_arch__create_addr_space_x86_64(void); +void *libunwind_arch__create_addr_space(unsigned int e_machine); + +int __libunwind__find_proc_info(void *as, uint64_t ip, void *pi, int need_= unwind_info, void *arg); +int __libunwind__access_mem(void *as, uint64_t addr, void *valp_word, int = __write, void *arg); +int __libunwind__access_reg(void *as, int regnum, void *valp_word, int __w= rite, void *arg); + +int __libunwind_arch__dwarf_search_unwind_table_arm(void *as, uint64_t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_arm64(void *as, uint64_t i= p, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_loongarch(void *as, uint64= _t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_mips(void *as, uint64_t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_ppc32(void *as, uint64_t i= p, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_ppc64(void *as, uint64_t i= p, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_s390(void *as, uint64_t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_i386(void *as, uint64_t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int __libunwind_arch__dwarf_search_unwind_table_x86_64(void *as, uint64_t = ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); +int libunwind_arch__dwarf_search_unwind_table(unsigned int e_machine, + void *as, + uint64_t ip, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); + +int __libunwind_arch__dwarf_find_debug_frame_arm(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_arm64(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_loongarch(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_mips(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_ppc32(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_ppc64(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_s390(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_i386(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_x86_64(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); +int libunwind_arch__dwarf_find_debug_frame(unsigned int e_machine, + int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); + +struct unwind_info *__libunwind_arch_unwind_info__new_arm(struct thread *t= hread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_arm64(struct thread = *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_loongarch(struct thr= ead *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_mips(struct thread *= thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_ppc32(struct thread = *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_ppc64(struct thread = *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_s390(struct thread *= thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_i386(struct thread *= thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_x86_64(struct thread= *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); +struct unwind_info *libunwind_arch_unwind_info__new(struct thread *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint16_t e_machine, + uint64_t first_ip); + +void libunwind_arch_unwind_info__delete(struct unwind_info *ui); + +int __libunwind_arch__unwind_step_arm(struct unwind_info *ui); +int __libunwind_arch__unwind_step_arm64(struct unwind_info *ui); +int __libunwind_arch__unwind_step_loongarch(struct unwind_info *ui); +int __libunwind_arch__unwind_step_mips(struct unwind_info *ui); +int __libunwind_arch__unwind_step_ppc32(struct unwind_info *ui); +int __libunwind_arch__unwind_step_ppc64(struct unwind_info *ui); +int __libunwind_arch__unwind_step_s390(struct unwind_info *ui); +int __libunwind_arch__unwind_step_i386(struct unwind_info *ui); +int __libunwind_arch__unwind_step_x86_64(struct unwind_info *ui); +int libunwind_arch__unwind_step(struct unwind_info *ui); + #endif /* __LIBUNWIND_ARCH_H */ diff --git a/tools/perf/util/libunwind-arch/libunwind-arm.c b/tools/perf/ut= il/libunwind-arch/libunwind-arm.c index bbaf01406c52..97a735488efe 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arm.c +++ b/tools/perf/util/libunwind-arch/libunwind-arm.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/arm/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_ARM_SUPPORT @@ -32,3 +36,255 @@ void __libunwind_arch__finish_access_arm(struct maps *m= aps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + + +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_arm(void) +{ +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_arm(void *as __maybe_unuse= d, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_ARM_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FRA= ME_ARM) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_arm(int found __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_ARM_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FRA= ME_ARM) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segvase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_arm(struct thread *t= hread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT + struct x86_64_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct x86_64_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_ARM; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_arm(struct unwind_info *ui __maybe_unuse= d) +{ +#ifdef HAVE_LIBUNWIND_ARM_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-arm64.c b/tools/perf/= util/libunwind-arch/libunwind-arm64.c index 8ba510089736..1f6e674b6565 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arm64.c +++ b/tools/perf/util/libunwind-arch/libunwind-arm64.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/arm64/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT @@ -32,3 +36,254 @@ void __libunwind_arch__finish_access_arm64(struct maps = *maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_arm64(void) +{ +#ifdef HAVE_LIBUNWIND_AARCH64_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_ARM64_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_arm64(void *as __maybe_unu= sed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_ARM64_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_ARM64_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_ARM64) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_arm64(int found __maybe_unuse= d, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_ARM64_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_ARM64) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segvase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_arm64(struct thread = *thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_ARM64_SUPPORT + struct x86_64_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct x86_64_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_AARCH64; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_arm64(struct unwind_info *ui __maybe_unu= sed) +{ +#ifdef HAVE_LIBUNWIND_ARM64_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-i386.c b/tools/perf/u= til/libunwind-arch/libunwind-i386.c index a0dcaa10578e..c52a41447ef0 100644 --- a/tools/perf/util/libunwind-arch/libunwind-i386.c +++ b/tools/perf/util/libunwind-arch/libunwind-i386.c @@ -2,9 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/x86/include/uapi/asm/perf_regs.h" #include #include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_X86_SUPPORT @@ -56,3 +59,254 @@ void __libunwind_arch__finish_access_i386(struct maps *= maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_X86_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_i386(void) +{ +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_X86_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_i386(void *as __maybe_unus= ed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_X86_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FRA= ME_X86) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_i386(int found __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_X86_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FRA= ME_X86) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segvase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_i386(struct thread *= thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + struct x86_64_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct x86_64_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_I386; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_i386(struct unwind_info *ui __maybe_unus= ed) +{ +#ifdef HAVE_LIBUNWIND_X86_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-loongarch.c b/tools/p= erf/util/libunwind-arch/libunwind-loongarch.c index 837aa11e2b9f..cccac749256d 100644 --- a/tools/perf/util/libunwind-arch/libunwind-loongarch.c +++ b/tools/perf/util/libunwind-arch/libunwind-loongarch.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/loongarch/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT @@ -40,3 +44,254 @@ void __libunwind_arch__finish_access_loongarch(struct m= aps *maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_loongarch(void) +{ +#ifdef HAVE_LIBUNWIND_LOONGARCH64_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_LOONGARCH_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_loongarch(void *as __maybe= _unused, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_LOONGARCH_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_LOONGARCH_SUPPORT) && !defined(NO_LIBUNWIND_DEB= UG_FRAME_LOONGARCH) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_loongarch(int found __maybe_u= nused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_LOONGARCH_SUPPORT) && !defined(NO_LIBUNWIND_DEB= UG_FRAME_LOONGARCH) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segvase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_loongarch(struct thr= ead *thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_LOONGARCH_SUPPORT + struct x86_64_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct x86_64_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_LOONGARCH; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_loongarch(struct unwind_info *ui __maybe= _unused) +{ +#ifdef HAVE_LIBUNWIND_LOONGARCH_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-mips.c b/tools/perf/u= til/libunwind-arch/libunwind-mips.c index 1fa81742ff4a..5136dcc81964 100644 --- a/tools/perf/util/libunwind-arch/libunwind-mips.c +++ b/tools/perf/util/libunwind-arch/libunwind-mips.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/mips/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_MIPS_SUPPORT @@ -42,3 +46,254 @@ void __libunwind_arch__finish_access_mips(struct maps *= maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_mips(void) +{ +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_mips(void *as __maybe_unus= ed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_MIPS_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FR= AME_MIPS) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_mips(int found __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_MIPS_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_FR= AME_MIPS) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segvase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_mips(struct thread *= thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT + struct x86_64_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct x86_64_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_MIPS; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_mips(struct unwind_info *ui __maybe_unus= ed) +{ +#ifdef HAVE_LIBUNWIND_MIPS_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc32.c b/tools/perf/= util/libunwind-arch/libunwind-ppc32.c index fa8471c74bf3..36e8036f7a3f 100644 --- a/tools/perf/util/libunwind-arch/libunwind-ppc32.c +++ b/tools/perf/util/libunwind-arch/libunwind-ppc32.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/powerpc/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_PPC32_SUPPORT @@ -44,3 +48,254 @@ void __libunwind_arch__finish_access_ppc32(struct maps = *maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_ppc32(void) +{ +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_ppc32(void *as __maybe_unu= sed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_PPC32_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_PPC32) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_ppc32(int found __maybe_unuse= d, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_PPC32_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_PPC32) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segvase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_ppc32(struct thread = *thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT + struct x86_64_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct x86_64_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_PPC32; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_ppc32(struct unwind_info *ui __maybe_unu= sed) +{ +#ifdef HAVE_LIBUNWIND_PPC32_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-ppc64.c b/tools/perf/= util/libunwind-arch/libunwind-ppc64.c index 2f746e347336..8e59956d105c 100644 --- a/tools/perf/util/libunwind-arch/libunwind-ppc64.c +++ b/tools/perf/util/libunwind-arch/libunwind-ppc64.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/powerpc/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_PPC64_SUPPORT @@ -46,3 +50,254 @@ void __libunwind_arch__finish_access_ppc64(struct maps = *maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_ppc64(void) +{ +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_ppc64(void *as __maybe_unu= sed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_PPC64_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_PPC64) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_ppc64(int found __maybe_unuse= d, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_PPC64_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_PPC64) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segvase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_ppc64(struct thread = *thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT + struct x86_64_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct x86_64_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_PPC64; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_ppc64(struct unwind_info *ui __maybe_unu= sed) +{ +#ifdef HAVE_LIBUNWIND_PPC64_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-s390.c b/tools/perf/u= til/libunwind-arch/libunwind-s390.c index 9f68d15438b2..320d1b8a11bc 100644 --- a/tools/perf/util/libunwind-arch/libunwind-s390.c +++ b/tools/perf/util/libunwind-arch/libunwind-s390.c @@ -2,8 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/s390/include/uapi/asm/perf_regs.h" #include +#include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_S390X_SUPPORT @@ -42,3 +46,254 @@ void __libunwind_arch__finish_access_s390(struct maps *= maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_s390(void) +{ +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_s390(void *as __maybe_unus= ed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_S390X_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_S390X) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_s390(int found __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_S390X_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_S390X) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segvase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_s390(struct thread *= thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT + struct x86_64_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct x86_64_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_S390; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_s390(struct unwind_info *ui __maybe_unus= ed) +{ +#ifdef HAVE_LIBUNWIND_S390X_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind-arch/libunwind-x86_64.c b/tools/perf= /util/libunwind-arch/libunwind-x86_64.c index 25e326bd3e15..4250001d021e 100644 --- a/tools/perf/util/libunwind-arch/libunwind-x86_64.c +++ b/tools/perf/util/libunwind-arch/libunwind-x86_64.c @@ -2,9 +2,12 @@ #include "libunwind-arch.h" #include "../debug.h" #include "../maps.h" +#include "../thread.h" #include "../../../arch/x86/include/uapi/asm/perf_regs.h" #include #include +#include +#include #include =20 #ifdef HAVE_LIBUNWIND_X86_64_SUPPORT @@ -65,3 +68,253 @@ void __libunwind_arch__finish_access_x86_64(struct maps= *maps __maybe_unused) unw_destroy_addr_space(maps__addr_space(maps)); #endif } + +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_x86_64(void) +{ +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_x86_64(void *as __maybe_un= used, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_X86_64_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_= FRAME_X86_64) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_x86_64(int found __maybe_unus= ed, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_X86_64_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_= FRAME_X86_64) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segvase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_x86_64(struct thread= *thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT + struct x86_64_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct x86_64_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_X86_64; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_x86_64(struct unwind_info *ui __maybe_un= used) +{ +#ifdef HAVE_LIBUNWIND_X86_64_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return 0; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} diff --git a/tools/perf/util/libunwind/arm64.c b/tools/perf/util/libunwind/= arm64.c deleted file mode 100644 index 15670a964495..000000000000 --- a/tools/perf/util/libunwind/arm64.c +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * This file setups defines to compile arch specific binary from the - * generic one. - * - * The function 'LIBUNWIND__ARCH_REG_ID' name is set according to arch - * name and the definition of this function is included directly from - * 'arch/arm64/util/unwind-libunwind.c', to make sure that this function - * is defined no matter what arch the host is. - * - * Finally, the arch specific unwind methods are exported which will - * be assigned to each arm64 thread. - */ - -#define REMOTE_UNWIND_LIBUNWIND - -#include "unwind.h" -#include "libunwind-aarch64.h" -#define perf_event_arm_regs perf_event_arm64_regs -#include <../../../arch/arm64/include/uapi/asm/perf_regs.h> -#undef perf_event_arm_regs -#include "../../arch/arm64/util/unwind-libunwind.c" - -/* NO_LIBUNWIND_DEBUG_FRAME is a feature flag for local libunwind, - * assign NO_LIBUNWIND_DEBUG_FRAME_AARCH64 to it for compiling arm64 - * unwind methods. - */ -#undef NO_LIBUNWIND_DEBUG_FRAME -#ifdef NO_LIBUNWIND_DEBUG_FRAME_AARCH64 -#define NO_LIBUNWIND_DEBUG_FRAME -#endif -#include "util/unwind-libunwind-local.c" - -struct unwind_libunwind_ops * -arm64_unwind_libunwind_ops =3D &_unwind_libunwind_ops; diff --git a/tools/perf/util/libunwind/x86_32.c b/tools/perf/util/libunwind= /x86_32.c deleted file mode 100644 index 1e9fb8bfec44..000000000000 --- a/tools/perf/util/libunwind/x86_32.c +++ /dev/null @@ -1,29 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * This file setups defines to compile arch specific binary from the - * generic one. - * - * The function 'LIBUNWIND__ARCH_REG_ID' name is set according to arch - * name and the definition of this function is included directly from - * 'arch/x86/util/unwind-libunwind.c', to make sure that this function - * is defined no matter what arch the host is. - * - * Finally, the arch specific unwind methods are exported which will - * be assigned to each x86 thread. - */ - -#define REMOTE_UNWIND_LIBUNWIND - -#include "unwind.h" -#include "libunwind-x86.h" - -/* Explicitly define NO_LIBUNWIND_DEBUG_FRAME, because non-ARM has no - * dwarf_find_debug_frame() function. - */ -#ifndef NO_LIBUNWIND_DEBUG_FRAME -#define NO_LIBUNWIND_DEBUG_FRAME -#endif -#include "util/unwind-libunwind-local.c" - -struct unwind_libunwind_ops * -x86_32_unwind_libunwind_ops =3D &_unwind_libunwind_ops; diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index 8c7b2a1e7642..7ba82024fb11 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -198,16 +198,6 @@ void maps__set_addr_space(struct maps *maps, void *add= r_space) RC_CHK_ACCESS(maps)->addr_space =3D addr_space; } =20 -const struct unwind_libunwind_ops *maps__unwind_libunwind_ops(const struct= maps *maps) -{ - return RC_CHK_ACCESS(maps)->unwind_libunwind_ops; -} - -void maps__set_unwind_libunwind_ops(struct maps *maps, const struct unwind= _libunwind_ops *ops) -{ - RC_CHK_ACCESS(maps)->unwind_libunwind_ops =3D ops; -} - uint16_t maps__e_machine(const struct maps *maps) { return RC_CHK_ACCESS(maps)->e_machine; diff --git a/tools/perf/util/maps.h b/tools/perf/util/maps.h index 6469f62c41a8..5b80b199685e 100644 --- a/tools/perf/util/maps.h +++ b/tools/perf/util/maps.h @@ -49,8 +49,6 @@ refcount_t *maps__refcnt(struct maps *maps); /* Test only= . */ #ifdef HAVE_LIBUNWIND_SUPPORT void *maps__addr_space(const struct maps *maps); void maps__set_addr_space(struct maps *maps, void *addr_space); -const struct unwind_libunwind_ops *maps__unwind_libunwind_ops(const struct= maps *maps); -void maps__set_unwind_libunwind_ops(struct maps *maps, const struct unwind= _libunwind_ops *ops); uint16_t maps__e_machine(const struct maps *maps); void maps__set_e_machine(struct maps *maps, uint16_t e_machine); #endif diff --git a/tools/perf/util/unwind-libunwind-local.c b/tools/perf/util/unw= ind-libunwind-local.c deleted file mode 100644 index 8f0128ba05a7..000000000000 --- a/tools/perf/util/unwind-libunwind-local.c +++ /dev/null @@ -1,820 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Post mortem Dwarf CFI based unwinding on top of regs and stack dumps. - * - * Lots of this code have been borrowed or heavily inspired from parts of - * the libunwind 0.99 code which are (amongst other contributors I may have - * forgotten): - * - * Copyright (C) 2002-2007 Hewlett-Packard Co - * Contributed by David Mosberger-Tang - * - * And the bugs have been added by: - * - * Copyright (C) 2010, Frederic Weisbecker - * Copyright (C) 2012, Jiri Olsa - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef REMOTE_UNWIND_LIBUNWIND -#include -#include -#endif -#include "callchain.h" -#include "thread.h" -#include "session.h" -#include "perf_regs.h" -#include "unwind.h" -#include "map.h" -#include "symbol.h" -#include "debug.h" -#include "asm/bug.h" -#include "dso.h" -#include "libunwind-arch/libunwind-arch.h" - -extern int -UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, - unw_word_t ip, - unw_dyn_info_t *di, - unw_proc_info_t *pi, - int need_unwind_info, void *arg); - -#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) - -extern int -UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, - unw_word_t ip, - unw_word_t segbase, - const char *obj_name, unw_word_t start, - unw_word_t end); - -#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) - -#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ -#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ - -/* Pointer-encoding formats: */ -#define DW_EH_PE_omit 0xff -#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ -#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ -#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ -#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ -#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ - -/* Pointer-encoding application: */ -#define DW_EH_PE_absptr 0x00 /* absolute value */ -#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ - -/* - * The following are not documented by LSB v1.3, yet they are used by - * GCC, presumably they aren't documented by LSB since they aren't - * used on Linux: - */ -#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ -#define DW_EH_PE_aligned 0x50 /* aligned pointer */ - -/* Flags intentionally not handled, since they're not needed: - * #define DW_EH_PE_indirect 0x80 - * #define DW_EH_PE_uleb128 0x01 - * #define DW_EH_PE_udata2 0x02 - * #define DW_EH_PE_sleb128 0x09 - * #define DW_EH_PE_sdata2 0x0a - * #define DW_EH_PE_textrel 0x20 - * #define DW_EH_PE_datarel 0x30 - */ - -struct unwind_info { - struct perf_sample *sample; - struct machine *machine; - struct thread *thread; - uint16_t e_machine; - bool best_effort; -}; - -#define dw_read(ptr, type, end) ({ \ - type *__p =3D (type *) ptr; \ - type __v; \ - if ((__p + 1) > (type *) end) \ - return -EINVAL; \ - __v =3D *__p++; \ - ptr =3D (typeof(ptr)) __p; \ - __v; \ - }) - -static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, - u8 encoding) -{ - u8 *cur =3D *p; - *val =3D 0; - - switch (encoding) { - case DW_EH_PE_omit: - *val =3D 0; - goto out; - case DW_EH_PE_ptr: - *val =3D dw_read(cur, unsigned long, end); - goto out; - default: - break; - } - - switch (encoding & DW_EH_PE_APPL_MASK) { - case DW_EH_PE_absptr: - break; - case DW_EH_PE_pcrel: - *val =3D (unsigned long) cur; - break; - default: - return -EINVAL; - } - - if ((encoding & 0x07) =3D=3D 0x00) - encoding |=3D DW_EH_PE_udata4; - - switch (encoding & DW_EH_PE_FORMAT_MASK) { - case DW_EH_PE_sdata4: - *val +=3D dw_read(cur, s32, end); - break; - case DW_EH_PE_udata4: - *val +=3D dw_read(cur, u32, end); - break; - case DW_EH_PE_sdata8: - *val +=3D dw_read(cur, s64, end); - break; - case DW_EH_PE_udata8: - *val +=3D dw_read(cur, u64, end); - break; - default: - return -EINVAL; - } - - out: - *p =3D cur; - return 0; -} - -#define dw_read_encoded_value(ptr, end, enc) ({ \ - u64 __v; \ - if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ - return -EINVAL; \ - } \ - __v; \ - }) - -static int elf_section_address_and_offset(int fd, const char *name, u64 *a= ddress, u64 *offset) -{ - Elf *elf; - GElf_Ehdr ehdr; - GElf_Shdr shdr; - int ret =3D -1; - - elf =3D elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); - if (elf =3D=3D NULL) - return -1; - - if (gelf_getehdr(elf, &ehdr) =3D=3D NULL) - goto out_err; - - if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) - goto out_err; - - *address =3D shdr.sh_addr; - *offset =3D shdr.sh_offset; - ret =3D 0; -out_err: - elf_end(elf); - return ret; -} - -#ifndef NO_LIBUNWIND_DEBUG_FRAME -static u64 elf_section_offset(int fd, const char *name) -{ - u64 address, offset =3D 0; - - if (elf_section_address_and_offset(fd, name, &address, &offset)) - return 0; - - return offset; -} -#endif - -static u64 elf_base_address(int fd) -{ - Elf *elf =3D elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); - GElf_Phdr phdr; - u64 retval =3D 0; - size_t i, phdrnum =3D 0; - - if (elf =3D=3D NULL) - return 0; - (void)elf_getphdrnum(elf, &phdrnum); - /* PT_LOAD segments are sorted by p_vaddr, so the first has the minimum p= _vaddr. */ - for (i =3D 0; i < phdrnum; i++) { - if (gelf_getphdr(elf, i, &phdr) && phdr.p_type =3D=3D PT_LOAD) { - retval =3D phdr.p_vaddr & -getpagesize(); - break; - } - } - - elf_end(elf); - return retval; -} - -#ifndef NO_LIBUNWIND_DEBUG_FRAME -static int elf_is_exec(int fd, const char *name) -{ - Elf *elf; - GElf_Ehdr ehdr; - int retval =3D 0; - - elf =3D elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); - if (elf =3D=3D NULL) - return 0; - if (gelf_getehdr(elf, &ehdr) =3D=3D NULL) - goto out; - - retval =3D (ehdr.e_type =3D=3D ET_EXEC); - -out: - elf_end(elf); - pr_debug("unwind: elf_is_exec(%s): %d\n", name, retval); - return retval; -} -#endif - -struct table_entry { - u32 start_ip_offset; - u32 fde_offset; -}; - -struct eh_frame_hdr { - unsigned char version; - unsigned char eh_frame_ptr_enc; - unsigned char fde_count_enc; - unsigned char table_enc; - - /* - * The rest of the header is variable-length and consists of the - * following members: - * - * encoded_t eh_frame_ptr; - * encoded_t fde_count; - */ - - /* A single encoded pointer should not be more than 8 bytes. */ - u64 enc[2]; - - /* - * struct { - * encoded_t start_ip; - * encoded_t fde_addr; - * } binary_search_table[fde_count]; - */ - char data[]; -} __packed; - -static int unwind_spec_ehframe(struct dso *dso, struct machine *machine, - u64 offset, u64 *table_data_offset, u64 *fde_count) -{ - struct eh_frame_hdr hdr; - u8 *enc =3D (u8 *) &hdr.enc; - u8 *end =3D (u8 *) &hdr.data; - ssize_t r; - - r =3D dso__data_read_offset(dso, machine, offset, - (u8 *) &hdr, sizeof(hdr)); - if (r !=3D sizeof(hdr)) - return -EINVAL; - - /* We dont need eh_frame_ptr, just skip it. */ - dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); - - *fde_count =3D dw_read_encoded_value(enc, end, hdr.fde_count_enc); - *table_data_offset =3D enc - (u8 *) &hdr; - return 0; -} - -struct read_unwind_spec_eh_frame_maps_cb_args { - struct dso *dso; - u64 base_addr; -}; - -static int read_unwind_spec_eh_frame_maps_cb(struct map *map, void *data) -{ - - struct read_unwind_spec_eh_frame_maps_cb_args *args =3D data; - - if (map__dso(map) =3D=3D args->dso && map__start(map) - map__pgoff(map) <= args->base_addr) - args->base_addr =3D map__start(map) - map__pgoff(map); - - return 0; -} - - -static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *= ui, - u64 *table_data, u64 *segbase, - u64 *fde_count) -{ - struct read_unwind_spec_eh_frame_maps_cb_args args =3D { - .dso =3D dso, - .base_addr =3D UINT64_MAX, - }; - int ret, fd; - - if (dso__data(dso)->eh_frame_hdr_offset =3D=3D 0) { - if (!dso__data_get_fd(dso, ui->machine, &fd)) - return -EINVAL; - - /* Check the .eh_frame section for unwinding info */ - ret =3D elf_section_address_and_offset(fd, ".eh_frame_hdr", - &dso__data(dso)->eh_frame_hdr_addr, - &dso__data(dso)->eh_frame_hdr_offset); - dso__data(dso)->elf_base_addr =3D elf_base_address(fd); - dso__data_put_fd(dso); - if (ret || dso__data(dso)->eh_frame_hdr_offset =3D=3D 0) - return -EINVAL; - } - - maps__for_each_map(thread__maps(ui->thread), read_unwind_spec_eh_frame_ma= ps_cb, &args); - - args.base_addr -=3D dso__data(dso)->elf_base_addr; - /* Address of .eh_frame_hdr */ - *segbase =3D args.base_addr + dso__data(dso)->eh_frame_hdr_addr; - ret =3D unwind_spec_ehframe(dso, ui->machine, dso__data(dso)->eh_frame_hd= r_offset, - table_data, fde_count); - if (ret) - return ret; - /* binary_search_table offset plus .eh_frame_hdr address */ - *table_data +=3D *segbase; - return 0; -} - -#ifndef NO_LIBUNWIND_DEBUG_FRAME -static int read_unwind_spec_debug_frame(struct dso *dso, - struct machine *machine, u64 *offset) -{ - int fd; - u64 ofs =3D dso__data(dso)->debug_frame_offset; - - /* debug_frame can reside in: - * - dso - * - debug pointed by symsrc_filename - * - gnu_debuglink, which doesn't necessary - * has to be pointed by symsrc_filename - */ - if (ofs =3D=3D 0) { - if (dso__data_get_fd(dso, machine, &fd)) { - ofs =3D elf_section_offset(fd, ".debug_frame"); - dso__data_put_fd(dso); - } - - if (ofs <=3D 0) { - fd =3D open(dso__symsrc_filename(dso), O_RDONLY); - if (fd >=3D 0) { - ofs =3D elf_section_offset(fd, ".debug_frame"); - close(fd); - } - } - - if (ofs <=3D 0) { - char *debuglink =3D malloc(PATH_MAX); - int ret =3D 0; - - if (debuglink =3D=3D NULL) { - pr_err("unwind: Can't read unwind spec debug frame.\n"); - return -ENOMEM; - } - - ret =3D dso__read_binary_type_filename( - dso, DSO_BINARY_TYPE__DEBUGLINK, - machine->root_dir, debuglink, PATH_MAX); - if (!ret) { - fd =3D open(debuglink, O_RDONLY); - if (fd >=3D 0) { - ofs =3D elf_section_offset(fd, - ".debug_frame"); - close(fd); - } - } - if (ofs > 0) { - if (dso__symsrc_filename(dso) !=3D NULL) { - pr_warning( - "%s: overwrite symsrc(%s,%s)\n", - __func__, - dso__symsrc_filename(dso), - debuglink); - dso__free_symsrc_filename(dso); - } - dso__set_symsrc_filename(dso, debuglink); - } else { - free(debuglink); - } - } - - dso__data(dso)->debug_frame_offset =3D ofs; - } - - *offset =3D ofs; - if (*offset) - return 0; - - return -EINVAL; -} -#endif - -static struct map *find_map(unw_word_t ip, struct unwind_info *ui) -{ - struct addr_location al; - struct map *ret; - - addr_location__init(&al); - thread__find_map(ui->thread, PERF_RECORD_MISC_USER, ip, &al); - ret =3D map__get(al.map); - addr_location__exit(&al); - return ret; -} - -static int -find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, - int need_unwind_info, void *arg) -{ - struct unwind_info *ui =3D arg; - struct map *map; - struct dso *dso; - unw_dyn_info_t di; - u64 table_data, segbase, fde_count; - int ret =3D -EINVAL; - - map =3D find_map(ip, ui); - if (!map) - return -EINVAL; - - dso =3D map__dso(map); - if (!dso) { - map__put(map); - return -EINVAL; - } - - pr_debug("unwind: find_proc_info dso %s\n", dso__name(dso)); - - /* Check the .eh_frame section for unwinding info */ - if (!read_unwind_spec_eh_frame(dso, ui, &table_data, &segbase, &fde_count= )) { - memset(&di, 0, sizeof(di)); - di.format =3D UNW_INFO_FORMAT_REMOTE_TABLE; - di.start_ip =3D map__start(map); - di.end_ip =3D map__end(map); - di.u.rti.segbase =3D segbase; - di.u.rti.table_data =3D table_data; - di.u.rti.table_len =3D fde_count * sizeof(struct table_entry) - / sizeof(unw_word_t); - ret =3D dwarf_search_unwind_table(as, ip, &di, pi, - need_unwind_info, arg); - } - -#ifndef NO_LIBUNWIND_DEBUG_FRAME - /* Check the .debug_frame section for unwinding info */ - if (ret < 0 && - !read_unwind_spec_debug_frame(dso, ui->machine, &segbase)) { - int fd; - u64 start =3D map__start(map); - unw_word_t base =3D start; - const char *symfile; - - if (dso__data_get_fd(dso, ui->machine, &fd)) { - if (elf_is_exec(fd, dso__name(dso))) - base =3D 0; - dso__data_put_fd(dso); - } - - symfile =3D dso__symsrc_filename(dso) ?: dso__name(dso); - - memset(&di, 0, sizeof(di)); - if (dwarf_find_debug_frame(0, &di, ip, base, symfile, start, map__end(ma= p))) - ret =3D dwarf_search_unwind_table(as, ip, &di, pi, - need_unwind_info, arg); - } -#endif - map__put(map); - return ret; -} - -static int access_fpreg(unw_addr_space_t __maybe_unused as, - unw_regnum_t __maybe_unused num, - unw_fpreg_t __maybe_unused *val, - int __maybe_unused __write, - void __maybe_unused *arg) -{ - pr_err("unwind: access_fpreg unsupported\n"); - return -UNW_EINVAL; -} - -static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, - unw_word_t __maybe_unused *dil_addr, - void __maybe_unused *arg) -{ - return -UNW_ENOINFO; -} - -static int resume(unw_addr_space_t __maybe_unused as, - unw_cursor_t __maybe_unused *cu, - void __maybe_unused *arg) -{ - pr_err("unwind: resume unsupported\n"); - return -UNW_EINVAL; -} - -static int -get_proc_name(unw_addr_space_t __maybe_unused as, - unw_word_t __maybe_unused addr, - char __maybe_unused *bufp, size_t __maybe_unused buf_len, - unw_word_t __maybe_unused *offp, void __maybe_unused *arg) -{ - pr_err("unwind: get_proc_name unsupported\n"); - return -UNW_EINVAL; -} - -static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, - unw_word_t *data) -{ - struct map *map; - struct dso *dso; - ssize_t size; - - map =3D find_map(addr, ui); - if (!map) { - pr_debug("unwind: no map for %lx\n", (unsigned long)addr); - return -1; - } - - dso =3D map__dso(map); - - if (!dso) { - map__put(map); - return -1; - } - - size =3D dso__data_read_addr(dso, map, ui->machine, - addr, (u8 *) data, sizeof(*data)); - map__put(map); - return !(size =3D=3D sizeof(*data)); -} - -static int access_mem(unw_addr_space_t __maybe_unused as, - unw_word_t addr, unw_word_t *valp, - int __write, void *arg) -{ - struct unwind_info *ui =3D arg; - struct stack_dump *stack =3D &ui->sample->user_stack; - u64 start, end; - int offset; - int ret; - - /* Don't support write, probably not needed. */ - if (__write || !stack || !ui->sample->user_regs || !ui->sample->user_regs= ->regs) { - *valp =3D 0; - return 0; - } - - ret =3D perf_reg_value(&start, perf_sample__user_regs(ui->sample), - perf_arch_reg_sp(ui->e_machine)); - if (ret) - return ret; - - end =3D start + stack->size; - - /* Check overflow. */ - if (addr + sizeof(unw_word_t) < addr) - return -EINVAL; - - if (addr < start || addr + sizeof(unw_word_t) >=3D end) { - ret =3D access_dso_mem(ui, addr, valp); - if (ret) { - pr_debug("unwind: access_mem %p not inside range" - " 0x%" PRIx64 "-0x%" PRIx64 "\n", - (void *) (uintptr_t) addr, start, end); - *valp =3D 0; - return ret; - } - return 0; - } - - offset =3D addr - start; - *valp =3D *(unw_word_t *)&stack->data[offset]; - pr_debug("unwind: access_mem addr %p val %lx, offset %d\n", - (void *) (uintptr_t) addr, (unsigned long)*valp, offset); - return 0; -} - -static int access_reg(unw_addr_space_t __maybe_unused as, - unw_regnum_t regnum, unw_word_t *valp, - int __write, void *arg) -{ - struct unwind_info *ui =3D arg; - int id, ret; - u64 val; - - /* Don't support write, I suspect we don't need it. */ - if (__write) { - pr_err("unwind: access_reg w %d\n", regnum); - return 0; - } - - if (!ui->sample->user_regs || !ui->sample->user_regs->regs) { - *valp =3D 0; - return 0; - } - - id =3D get_perf_regnum_for_unw_regnum(ui->e_machine, regnum); - if (id < 0) - return -EINVAL; - - ret =3D perf_reg_value(&val, perf_sample__user_regs(ui->sample), id); - if (ret) { - if (!ui->best_effort) - pr_err("unwind: can't read reg %d\n", regnum); - return ret; - } - - *valp =3D (unw_word_t) val; - pr_debug("unwind: reg %d, val %lx\n", regnum, (unsigned long)*valp); - return 0; -} - -static void put_unwind_info(unw_addr_space_t __maybe_unused as, - unw_proc_info_t *pi __maybe_unused, - void *arg __maybe_unused) -{ - pr_debug("unwind: put_unwind_info called\n"); -} - -static int entry(u64 ip, struct thread *thread, - unwind_entry_cb_t cb, void *arg) -{ - struct unwind_entry e; - struct addr_location al; - int ret; - - addr_location__init(&al); - e.ms.sym =3D thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al); - e.ip =3D ip; - e.ms.map =3D al.map; - e.ms.thread =3D thread__get(al.thread); - - pr_debug("unwind: %s:ip =3D 0x%" PRIx64 " (0x%" PRIx64 ")\n", - al.sym ? al.sym->name : "''", - ip, - al.map ? map__map_ip(al.map, ip) : (u64) 0); - - ret =3D cb(&e, arg); - addr_location__exit(&al); - return ret; -} - -static void display_error(int err) -{ - switch (err) { - case UNW_EINVAL: - pr_err("unwind: Only supports local.\n"); - break; - case UNW_EUNSPEC: - pr_err("unwind: Unspecified error.\n"); - break; - case UNW_EBADREG: - pr_err("unwind: Register unavailable.\n"); - break; - default: - break; - } -} - -static unw_accessors_t accessors =3D { - .find_proc_info =3D find_proc_info, - .put_unwind_info =3D put_unwind_info, - .get_dyn_info_list_addr =3D get_dyn_info_list_addr, - .access_mem =3D access_mem, - .access_reg =3D access_reg, - .access_fpreg =3D access_fpreg, - .resume =3D resume, - .get_proc_name =3D get_proc_name, -}; - -static int _unwind__prepare_access(struct maps *maps) -{ - void *addr_space =3D unw_create_addr_space(&accessors, 0); - - maps__set_addr_space(maps, addr_space); - if (!addr_space) { - pr_err("unwind: Can't create unwind address space.\n"); - return -ENOMEM; - } - - unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); - return 0; -} - -static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, - void *arg, int max_stack) -{ - u64 val; - unw_word_t ips[max_stack]; - unw_addr_space_t addr_space; - unw_cursor_t c; - int ret, i =3D 0; - - ret =3D perf_reg_value(&val, perf_sample__user_regs(ui->sample), - perf_arch_reg_ip(ui->e_machine)); - if (ret) - return ret; - - ips[i++] =3D (unw_word_t) val; - - /* - * If we need more than one entry, do the DWARF - * unwind itself. - */ - if (max_stack - 1 > 0) { - WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL"); - addr_space =3D maps__addr_space(thread__maps(ui->thread)); - - if (addr_space =3D=3D NULL) - return -1; - - ret =3D unw_init_remote(&c, addr_space, ui); - if (ret && !ui->best_effort) - display_error(ret); - - while (!ret && (unw_step(&c) > 0) && i < max_stack) { - unw_get_reg(&c, UNW_REG_IP, &ips[i]); - - /* - * Decrement the IP for any non-activation frames. - * this is required to properly find the srcline - * for caller frames. - * See also the documentation for dwfl_frame_pc(), - * which this code tries to replicate. - */ - if (unw_is_signal_frame(&c) <=3D 0) - --ips[i]; - - ++i; - } - - max_stack =3D i; - } - - /* - * Display what we got based on the order setup. - */ - for (i =3D 0; i < max_stack && !ret; i++) { - int j =3D i; - - if (callchain_param.order =3D=3D ORDER_CALLER) - j =3D max_stack - i - 1; - ret =3D ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0; - } - - return ret; -} - -static int _unwind__get_entries(unwind_entry_cb_t cb, void *arg, - struct thread *thread, - struct perf_sample *data, int max_stack, - bool best_effort) -{ - struct unwind_info ui =3D { - .sample =3D data, - .thread =3D thread, - .machine =3D maps__machine(thread__maps(thread)), - .e_machine =3D thread__e_machine(thread, /*machine=3D*/NULL, /*e_flag= s=3D*/NULL), - .best_effort =3D best_effort - }; - - if (!data->user_regs || !data->user_regs->regs) - return -EINVAL; - - if (max_stack <=3D 0) - return -EINVAL; - - return get_entries(&ui, cb, arg, max_stack); -} - -static struct unwind_libunwind_ops -_unwind_libunwind_ops =3D { - .prepare_access =3D _unwind__prepare_access, - .get_entries =3D _unwind__get_entries, -}; - -#ifndef REMOTE_UNWIND_LIBUNWIND -struct unwind_libunwind_ops * -local_unwind_libunwind_ops =3D &_unwind_libunwind_ops; -#endif diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-li= bunwind.c index 816891ecfa5e..a29ba14e7a30 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c @@ -1,23 +1,557 @@ // SPDX-License-Identifier: GPL-2.0 -#include "unwind.h" +#include "callchain.h" +#include "debug.h" #include "dso.h" +#include "env.h" #include "map.h" -#include "thread.h" +#include "perf_regs.h" #include "session.h" -#include "debug.h" -#include "env.h" -#include "callchain.h" +#include "symbol.h" +#include "thread.h" +#include "unwind.h" #include "libunwind-arch/libunwind-arch.h" #include #include +#include +#include +#include + +#define DW_EH_PE_FORMAT_MASK 0x0f /* format of the encoded value */ +#define DW_EH_PE_APPL_MASK 0x70 /* how the value is to be applied */ + +/* Pointer-encoding formats: */ +#define DW_EH_PE_omit 0xff +#define DW_EH_PE_ptr 0x00 /* pointer-sized unsigned value */ +#define DW_EH_PE_udata4 0x03 /* unsigned 32-bit value */ +#define DW_EH_PE_udata8 0x04 /* unsigned 64-bit value */ +#define DW_EH_PE_sdata4 0x0b /* signed 32-bit value */ +#define DW_EH_PE_sdata8 0x0c /* signed 64-bit value */ + +/* Pointer-encoding application: */ +#define DW_EH_PE_absptr 0x00 /* absolute value */ +#define DW_EH_PE_pcrel 0x10 /* rel. to addr. of encoded value */ + +/* + * The following are not documented by LSB v1.3, yet they are used by + * GCC, presumably they aren't documented by LSB since they aren't + * used on Linux: + */ +#define DW_EH_PE_funcrel 0x40 /* start-of-procedure-relative */ +#define DW_EH_PE_aligned 0x50 /* aligned pointer */ + +/* Flags intentionally not handled, since they're not needed: + * #define DW_EH_PE_indirect 0x80 + * #define DW_EH_PE_uleb128 0x01 + * #define DW_EH_PE_udata2 0x02 + * #define DW_EH_PE_sleb128 0x09 + * #define DW_EH_PE_sdata2 0x0a + * #define DW_EH_PE_textrel 0x20 + * #define DW_EH_PE_datarel 0x30 + */ + +#define dw_read(ptr, type, end) ({ \ + type *__p =3D (type *) ptr; \ + type __v; \ + if ((__p + 1) > (type *) end) \ + return -EINVAL; \ + __v =3D *__p++; \ + ptr =3D (typeof(ptr)) __p; \ + __v; \ + }) + +static int __dw_read_encoded_value(u8 **p, u8 *end, u64 *val, + u8 encoding) +{ + u8 *cur =3D *p; + *val =3D 0; + + switch (encoding) { + case DW_EH_PE_omit: + *val =3D 0; + goto out; + case DW_EH_PE_ptr: + *val =3D dw_read(cur, unsigned long, end); + goto out; + default: + break; + } + + switch (encoding & DW_EH_PE_APPL_MASK) { + case DW_EH_PE_absptr: + break; + case DW_EH_PE_pcrel: + *val =3D (unsigned long) cur; + break; + default: + return -EINVAL; + } + + if ((encoding & 0x07) =3D=3D 0x00) + encoding |=3D DW_EH_PE_udata4; + + switch (encoding & DW_EH_PE_FORMAT_MASK) { + case DW_EH_PE_sdata4: + *val +=3D dw_read(cur, s32, end); + break; + case DW_EH_PE_udata4: + *val +=3D dw_read(cur, u32, end); + break; + case DW_EH_PE_sdata8: + *val +=3D dw_read(cur, s64, end); + break; + case DW_EH_PE_udata8: + *val +=3D dw_read(cur, u64, end); + break; + default: + return -EINVAL; + } + + out: + *p =3D cur; + return 0; +} + +#define dw_read_encoded_value(ptr, end, enc) ({ \ + u64 __v; \ + if (__dw_read_encoded_value(&ptr, end, &__v, enc)) { \ + return -EINVAL; \ + } \ + __v; \ + }) + +static u64 elf_base_address(int fd) +{ + Elf *elf =3D elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + GElf_Phdr phdr; + u64 retval =3D 0; + size_t i, phdrnum =3D 0; + + if (elf =3D=3D NULL) + return 0; + (void)elf_getphdrnum(elf, &phdrnum); + /* PT_LOAD segments are sorted by p_vaddr, so the first has the minimum p= _vaddr. */ + for (i =3D 0; i < phdrnum; i++) { + if (gelf_getphdr(elf, i, &phdr) && phdr.p_type =3D=3D PT_LOAD) { + retval =3D phdr.p_vaddr & -getpagesize(); + break; + } + } + + elf_end(elf); + return retval; +} + +static int unwind_spec_ehframe(struct dso *dso, struct machine *machine, + u64 offset, u64 *table_data_offset, u64 *fde_count) +{ + struct eh_frame_hdr { + unsigned char version; + unsigned char eh_frame_ptr_enc; + unsigned char fde_count_enc; + unsigned char table_enc; + + /* + * The rest of the header is variable-length and consists of the + * following members: + * + * encoded_t eh_frame_ptr; + * encoded_t fde_count; + */ + + /* A single encoded pointer should not be more than 8 bytes. */ + u64 enc[2]; + + /* + * struct { + * encoded_t start_ip; + * encoded_t fde_addr; + * } binary_search_table[fde_count]; + */ + char data[]; + } __packed hdr; + u8 *enc =3D (u8 *) &hdr.enc; + u8 *end =3D (u8 *) &hdr.data; + ssize_t r; + + r =3D dso__data_read_offset(dso, machine, offset, (u8 *) &hdr, sizeof(hdr= )); + if (r !=3D sizeof(hdr)) + return -EINVAL; + + /* We dont need eh_frame_ptr, just skip it. */ + dw_read_encoded_value(enc, end, hdr.eh_frame_ptr_enc); + + *fde_count =3D dw_read_encoded_value(enc, end, hdr.fde_count_enc); + *table_data_offset =3D enc - (u8 *) &hdr; + return 0; +} + +struct read_unwind_spec_eh_frame_maps_cb_args { + struct dso *dso; + u64 base_addr; +}; + +static int read_unwind_spec_eh_frame_maps_cb(struct map *map, void *data) +{ + + struct read_unwind_spec_eh_frame_maps_cb_args *args =3D data; + + if (map__dso(map) =3D=3D args->dso && map__start(map) - map__pgoff(map) <= args->base_addr) + args->base_addr =3D map__start(map) - map__pgoff(map); + + return 0; +} + +static int elf_section_address_and_offset(int fd, const char *name, u64 *a= ddress, u64 *offset) +{ + Elf *elf; + GElf_Ehdr ehdr; + GElf_Shdr shdr; + int ret =3D -1; + + elf =3D elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf =3D=3D NULL) + return -1; =20 -struct unwind_libunwind_ops __weak *local_unwind_libunwind_ops; -struct unwind_libunwind_ops __weak *x86_32_unwind_libunwind_ops; -struct unwind_libunwind_ops __weak *arm64_unwind_libunwind_ops; + if (gelf_getehdr(elf, &ehdr) =3D=3D NULL) + goto out_err; + + if (!elf_section_by_name(elf, &ehdr, &shdr, name, NULL)) + goto out_err; + + *address =3D shdr.sh_addr; + *offset =3D shdr.sh_offset; + ret =3D 0; +out_err: + elf_end(elf); + return ret; +} + +static int read_unwind_spec_eh_frame(struct dso *dso, struct unwind_info *= ui, + u64 *table_data, u64 *segbase, + u64 *fde_count) +{ + struct read_unwind_spec_eh_frame_maps_cb_args args =3D { + .dso =3D dso, + .base_addr =3D UINT64_MAX, + }; + int ret, fd; + + if (dso__data(dso)->eh_frame_hdr_offset =3D=3D 0) { + if (!dso__data_get_fd(dso, ui->machine, &fd)) + return -EINVAL; + + /* Check the .eh_frame section for unwinding info */ + ret =3D elf_section_address_and_offset(fd, ".eh_frame_hdr", + &dso__data(dso)->eh_frame_hdr_addr, + &dso__data(dso)->eh_frame_hdr_offset); + dso__data(dso)->elf_base_addr =3D elf_base_address(fd); + dso__data_put_fd(dso); + if (ret || dso__data(dso)->eh_frame_hdr_offset =3D=3D 0) + return -EINVAL; + } + + maps__for_each_map(thread__maps(ui->thread), read_unwind_spec_eh_frame_ma= ps_cb, &args); + + args.base_addr -=3D dso__data(dso)->elf_base_addr; + /* Address of .eh_frame_hdr */ + *segbase =3D args.base_addr + dso__data(dso)->eh_frame_hdr_addr; + ret =3D unwind_spec_ehframe(dso, ui->machine, dso__data(dso)->eh_frame_hd= r_offset, + table_data, fde_count); + if (ret) + return ret; + /* binary_search_table offset plus .eh_frame_hdr address */ + *table_data +=3D *segbase; + return 0; +} + +static u64 elf_section_offset(int fd, const char *name) +{ + u64 address, offset =3D 0; + + if (elf_section_address_and_offset(fd, name, &address, &offset)) + return 0; + + return offset; +} + +static int read_unwind_spec_debug_frame(struct dso *dso, + struct machine *machine, u64 *offset) +{ + int fd; + u64 ofs =3D dso__data(dso)->debug_frame_offset; + + /* debug_frame can reside in: + * - dso + * - debug pointed by symsrc_filename + * - gnu_debuglink, which doesn't necessary + * has to be pointed by symsrc_filename + */ + if (ofs =3D=3D 0) { + if (dso__data_get_fd(dso, machine, &fd)) { + ofs =3D elf_section_offset(fd, ".debug_frame"); + dso__data_put_fd(dso); + } + + if (ofs <=3D 0) { + fd =3D open(dso__symsrc_filename(dso), O_RDONLY); + if (fd >=3D 0) { + ofs =3D elf_section_offset(fd, ".debug_frame"); + close(fd); + } + } + + if (ofs <=3D 0) { + char *debuglink =3D malloc(PATH_MAX); + int ret =3D 0; + + if (debuglink =3D=3D NULL) { + pr_err("unwind: Can't read unwind spec debug frame.\n"); + return -ENOMEM; + } + + ret =3D dso__read_binary_type_filename( + dso, DSO_BINARY_TYPE__DEBUGLINK, + machine->root_dir, debuglink, PATH_MAX); + if (!ret) { + fd =3D open(debuglink, O_RDONLY); + if (fd >=3D 0) { + ofs =3D elf_section_offset(fd, + ".debug_frame"); + close(fd); + } + } + if (ofs > 0) { + if (dso__symsrc_filename(dso) !=3D NULL) { + pr_warning( + "%s: overwrite symsrc(%s,%s)\n", + __func__, + dso__symsrc_filename(dso), + debuglink); + dso__free_symsrc_filename(dso); + } + dso__set_symsrc_filename(dso, debuglink); + } else { + free(debuglink); + } + } + + dso__data(dso)->debug_frame_offset =3D ofs; + } + + *offset =3D ofs; + if (*offset) + return 0; + + return -EINVAL; +} + +static struct map *find_map(uint64_t ip, struct unwind_info *ui) +{ + struct addr_location al; + struct map *ret; + + addr_location__init(&al); + thread__find_map(ui->thread, PERF_RECORD_MISC_USER, ip, &al); + ret =3D map__get(al.map); + addr_location__exit(&al); + return ret; +} + +static int elf_is_exec(int fd, const char *name) +{ + Elf *elf; + GElf_Ehdr ehdr; + int retval =3D 0; + + elf =3D elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); + if (elf =3D=3D NULL) + return 0; + if (gelf_getehdr(elf, &ehdr) =3D=3D NULL) + goto out; + + retval =3D (ehdr.e_type =3D=3D ET_EXEC); + +out: + elf_end(elf); + pr_debug3("unwind: elf_is_exec(%s): %d\n", name, retval); + return retval; +} + +int __libunwind__find_proc_info(void *as, uint64_t ip, void *pi, int need_= unwind_info, void *arg) +{ + struct unwind_info *ui =3D arg; + struct map *map; + struct dso *dso; + u64 table_data, segbase, fde_count; + int ret =3D -EINVAL; + + map =3D find_map(ip, ui); + if (!map) + return -EINVAL; + + dso =3D map__dso(map); + if (!dso) { + map__put(map); + return -EINVAL; + } + + pr_debug3("unwind: find_proc_info dso %s\n", dso__name(dso)); + + /* Check the .eh_frame section for unwinding info */ + if (!read_unwind_spec_eh_frame(dso, ui, &table_data, &segbase, &fde_count= )) { + struct table_entry { + u32 start_ip_offset; + u32 fde_offset; + }; + struct libarch_unwind__dyn_info di =3D { + .start_ip =3D map__start(map), + .end_ip =3D map__end(map), + .segbase =3D segbase, + .table_data =3D table_data, + .table_len =3D fde_count * sizeof(struct table_entry) / ui->unw_word_t= _size, + }; + + ret =3D libunwind_arch__dwarf_search_unwind_table(ui->e_machine, as, ip,= &di, pi, + need_unwind_info, arg); + } + + /* Check the .debug_frame section for unwinding info */ + if (ret < 0 && !read_unwind_spec_debug_frame(dso, ui->machine, &segbase))= { + int fd; + u64 start =3D map__start(map); + u64 base =3D start; + const char *symfile; + struct libarch_unwind__dyn_info di =3D {}; + + if (dso__data_get_fd(dso, ui->machine, &fd)) { + if (elf_is_exec(fd, dso__name(dso))) + base =3D 0; + dso__data_put_fd(dso); + } + + symfile =3D dso__symsrc_filename(dso) ?: dso__name(dso); + + if (libunwind_arch__dwarf_find_debug_frame(ui->e_machine, /*found=3D*/0,= &di, ip, + base, symfile, start, map__end(map))) { + ret =3D libunwind_arch__dwarf_search_unwind_table(ui->e_machine, as, ip= , &di, pi, + need_unwind_info, arg); + } + } + map__put(map); + return ret; +} + +static int access_dso_mem(struct unwind_info *ui, uint64_t addr, void *dat= a_word) +{ + struct map *map; + struct dso *dso; + ssize_t size; + + map =3D find_map(addr, ui); + if (!map) { + pr_debug("unwind: no map for %lx\n", (unsigned long)addr); + return -1; + } + + dso =3D map__dso(map); + + if (!dso) { + map__put(map); + return -1; + } + + size =3D dso__data_read_addr(dso, map, ui->machine, + addr, + (u8 *) data_word, + ui->unw_word_t_size); + map__put(map); + return !((size_t)size =3D=3D ui->unw_word_t_size); +} + +int __libunwind__access_mem(void *as __maybe_unused, uint64_t addr, void *= valp_word, + int __write, void *arg) +{ + struct unwind_info *ui =3D arg; + struct stack_dump *stack =3D &ui->sample->user_stack; + u64 start, end; + int offset; + int ret; + + /* Don't support write, probably not needed. */ + if (__write || !stack || !ui->sample->user_regs || !ui->sample->user_regs= ->regs) { + uint64_t zero =3D 0; + + memcpy(valp_word, &zero, ui->unw_word_t_size); + return 0; + } + + ret =3D perf_reg_value(&start, perf_sample__user_regs(ui->sample), + perf_arch_reg_sp(ui->e_machine)); + if (ret) + return ret; + + end =3D start + stack->size; + + /* Check overflow. */ + if (addr + ui->unw_word_t_size < addr) + return -EINVAL; + + if (addr < start || addr + ui->unw_word_t_size >=3D end) { + ret =3D access_dso_mem(ui, addr, valp_word); + if (ret) { + pr_debug3("unwind: access_mem %p not inside range" + " 0x%" PRIx64 "-0x%" PRIx64 "\n", + (void *) (uintptr_t) addr, start, end); + memset(valp_word, 0, ui->unw_word_t_size); + return ret; + } + return 0; + } + + offset =3D addr - start; + memcpy(valp_word, &stack->data[offset], ui->unw_word_t_size); + pr_debug3("unwind: access_mem addr %p val %lx, offset %d\n", + (void *) (uintptr_t) addr, *((unsigned long *)valp_word), offset); + return 0; +} + +int __libunwind__access_reg(void *as __maybe_unused, int regnum, void *val= p_word, int __write, + void *arg) +{ + struct unwind_info *ui =3D arg; + int id, ret; + u64 val; + + /* Don't support write, I suspect we don't need it. */ + if (__write) { + pr_err("unwind: access_reg w %d\n", regnum); + return 0; + } + + if (!ui->sample->user_regs || !ui->sample->user_regs->regs) { + memset(valp_word, 0, ui->unw_word_t_size); + return 0; + } + + id =3D get_perf_regnum_for_unw_regnum(ui->e_machine, regnum); + if (id < 0) + return -EINVAL; + + ret =3D perf_reg_value(&val, perf_sample__user_regs(ui->sample), id); + if (ret) { + if (!ui->best_effort) + pr_err("unwind: can't read reg %d\n", regnum); + return ret; + } + + memcpy(valp_word, &val, ui->unw_word_t_size); + pr_debug3("unwind: reg %d, val %lx\n", regnum, val); + return 0; +} =20 int unwind__prepare_access(struct maps *maps, uint16_t e_machine) { - struct unwind_libunwind_ops *ops =3D local_unwind_libunwind_ops; + void *addr_space; =20 if (!dwarf_callchain_users) return 0; @@ -27,25 +561,16 @@ int unwind__prepare_access(struct maps *maps, uint16_t= e_machine) return 0; } =20 - if (e_machine !=3D EM_HOST) { - /* If not live/local mode. */ - switch (e_machine) { - case EM_386: - ops =3D x86_32_unwind_libunwind_ops; - break; - case EM_AARCH64: - ops =3D arm64_unwind_libunwind_ops; - break; - default: - pr_warning_once("unwind: ELF machine type %d is not supported\n", - e_machine); - return 0; - } - } - maps__set_unwind_libunwind_ops(maps, ops); maps__set_e_machine(maps, e_machine); + addr_space =3D libunwind_arch__create_addr_space(e_machine); + + maps__set_addr_space(maps, addr_space); + if (!addr_space) { + pr_err("unwind: Can't create unwind address space.\n"); + return -ENOMEM; + } =20 - return maps__unwind_libunwind_ops(maps)->prepare_access(maps); + return 0; } =20 void unwind__flush_access(struct maps *maps) @@ -58,14 +583,81 @@ void unwind__finish_access(struct maps *maps) libunwind_arch__finish_access(maps); } =20 +static int entry(uint64_t ip, struct thread *thread, unwind_entry_cb_t cb,= void *arg) +{ + struct unwind_entry e; + struct addr_location al; + int ret; + + addr_location__init(&al); + e.ms.sym =3D thread__find_symbol(thread, PERF_RECORD_MISC_USER, ip, &al); + e.ip =3D ip; + e.ms.map =3D al.map; + e.ms.thread =3D thread__get(al.thread); + + pr_debug("unwind: %s:ip =3D 0x%" PRIx64 " (0x%" PRIx64 ")\n", + al.sym ? al.sym->name : "''", + ip, + al.map ? map__map_ip(al.map, ip) : (u64) 0); + + ret =3D cb(&e, arg); + addr_location__exit(&al); + return ret; +} + int unwind__get_entries(unwind_entry_cb_t cb, void *arg, struct thread *thread, - struct perf_sample *data, int max_stack, + struct perf_sample *sample, int max_stack, bool best_effort) { - const struct unwind_libunwind_ops *ops =3D maps__unwind_libunwind_ops(thr= ead__maps(thread)); + struct unwind_info *ui; + uint64_t first_ip; + int ret, i =3D 0; + uint16_t e_machine; =20 - if (ops) - return ops->get_entries(cb, arg, thread, data, max_stack, best_effort); - return 0; + if (!sample->user_regs || !sample->user_regs->regs) + return -EINVAL; + + if (max_stack <=3D 0) + return -EINVAL; + + if (!thread) { + pr_warning_once("WARNING: thread is NULL"); + return -EINVAL; + } + + e_machine =3D thread__e_machine(thread, /*machine=3D*/NULL, /*e_flags=3D*= /NULL); + ret =3D perf_reg_value(&first_ip, perf_sample__user_regs(sample), + perf_arch_reg_ip(e_machine)); + if (ret) + return ret; + + if (max_stack =3D=3D 1) { + /* Special case for a single entry. */ + return entry(first_ip, thread, cb, arg); + } + + ui =3D libunwind_arch_unwind_info__new(thread, sample, max_stack, best_ef= fort, e_machine, first_ip); + if (!ui) + return -1; + + do { + ret =3D libunwind_arch__unwind_step(ui); + if (ret < 0) + goto out; + + } while (ret); + + /* + * Display what we got based on the order setup. + */ + for (i =3D 0; i < ui->cur_ip; i++) { + int j =3D callchain_param.order =3D=3D ORDER_CALLEE ? i : ui->cur_ip - i= - 1; + + if (ui->ips[j]) + ret =3D entry(ui->ips[j], thread, cb, arg); + } +out: + libunwind_arch_unwind_info__delete(ui); + return ret; } --=20 2.53.0.371.g1d285c8824-goog From nobody Fri Apr 17 01:39:38 2026 Received: from mail-dl1-f74.google.com (mail-dl1-f74.google.com [74.125.82.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F36223A0B21 for ; Tue, 24 Feb 2026 14:30:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943409; cv=none; b=tIzyJ08j0JN5v17jWuHQkB0Xip1Hir4T20/C2mkSXTnGo8WXx+nE2Wspox3EGe+xgJdRCW/Chc1+YqKBd0DqKQqSep0TKaMSSdujXn0aqxMhY2jdW4Sv2/Q14y6y8E2sT/Wk2u9Cxl83N7wr7q4ndupf28PWo0OK4j+ezq4Jxko= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1771943409; c=relaxed/simple; bh=cIUVcIo/zi12/rUt2UUkbTmWlgvg7+zq59R5kvRXjeU=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Content-Type; b=mkKOMTUsTl8/98wNUYj4Xpi2gkUf1OEVsbQooLElm+tj3M2ROJW+PfoRcTRfuIwLO091c6NjGxhdp8sVmbiPBhijUXRj40TzsiT6uof/oWi2Gdsl3qfMGXwgZTgbXxCbylLdh6th+ZLi7jbacm+eKCbizH5CElBUppYfpnkflbg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=n8o04gsi; arc=none smtp.client-ip=74.125.82.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="n8o04gsi" Received: by mail-dl1-f74.google.com with SMTP id a92af1059eb24-1273665df8fso7464903c88.1 for ; Tue, 24 Feb 2026 06:30:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1771943406; x=1772548206; darn=vger.kernel.org; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :from:to:cc:subject:date:message-id:reply-to; bh=bW5OcwFpnai8hzp+Ggk0tIapBBTqER51SF6MQboFAUs=; b=n8o04gsiWMbMnpCaX496n1/F5csfjyjwF53tQIytFsWCdXwg5VNbIMXMwrai8lg66S 4o88Ge1/iQ22MbUHoj7DBFb7TQQITbLBFMMEmI8b+tbjyuVDGxtNbd8pXFHfcsKpmvcD /zp8i2vL0YgVctumYsMgVmijm5P4L97qWZghNkg16kXlw2mJPnqLhGHQIwi27gKAiuLx noopzhF64nOkSqBJxvx4fAl2IWqDfQ/q9YuIdgPE+u0kvW9p4rYfkmZNRuW2veaNCUXU 0M/jgFzf4/kr3BussIBQ61JkygxYe9tai6C9/peejBLmTa+FcJ5g/BWeKa+tZPsUQ9Vh 8faQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771943406; x=1772548206; h=to:from:subject:message-id:references:mime-version:in-reply-to:date :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=bW5OcwFpnai8hzp+Ggk0tIapBBTqER51SF6MQboFAUs=; b=uVIq3NV7COjAcGBnvUoPMPhaalmmE23WlB6mdbudwuIfbKLeUrBUWsT7WRC3QkrfpV s2mi+A9z/VFXuQ4u82BRpqf5Hn0YGpNCw6Rw+HlYFPikZD3xEA4lgqDMpN/8JldoD/6T +xJkuDWiNKFfs4IARKuosXyiBgZwy1RlSPtEmnc/IN2wM96rtmZO0tDxlfEtmVrgcpOQ 1ApRZw+KlMSRMsc7UdzQIqKFYlEsYW6s9RSR9zJgUk3XlMqmco8PQkdzh5kWVvNYkhK6 eaG4nBc2vWkXqqILkQZboCHHnodNEQSx7x25h25E20XNp9scWh0dSkBaJCVjOzQIroxH /0LQ== X-Forwarded-Encrypted: i=1; AJvYcCUA6K5UOQ57SfKbwijihEuVYFvixmaqOxP/npXrHiKb1TpxsiROBSpCQiTZQlYjU319wEr2t7QtQ4AeMPs=@vger.kernel.org X-Gm-Message-State: AOJu0YzxAs8GApQx+vVQU3XYAd9mfDHYmps20AVN5AMsB1N9N2eF5+JR IuS8t6Xa+n92tJBKrU8WtWr5uWrCBkRtVwKELgAQJNuviZuOnrni4y4dTPb8NA7wPflHGa8TYL+ sQznyxmd7BA== X-Received: from dlah19.prod.google.com ([2002:a05:701b:2613:b0:127:77a3:550]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:6b93:b0:122:33e:6d41 with SMTP id a92af1059eb24-1276ad11a3fmr3380035c88.23.1771943405757; Tue, 24 Feb 2026 06:30:05 -0800 (PST) Date: Tue, 24 Feb 2026 06:29:37 -0800 In-Reply-To: <20260224142938.26088-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260224142938.26088-1-irogers@google.com> X-Mailer: git-send-email 2.53.0.371.g1d285c8824-goog Message-ID: <20260224142938.26088-8-irogers@google.com> Subject: [RFC PATCH v1 7/7] perf unwind-libunwind: Add RISC-V libunwind support From: Ian Rogers To: Peter Zijlstra , Ingo Molnar , Arnaldo Carvalho de Melo , Namhyung Kim , Alexander Shishkin , Jiri Olsa , Ian Rogers , Adrian Hunter , James Clark , John Garry , Will Deacon , Leo Yan , Paul Walmsley , Palmer Dabbelt , Albert Ou , Alexandre Ghiti , Dmitrii Dolgov <9erthalion6@gmail.com>, Blake Jones , Tomas Glozar , Yuzhuo Jing , Dapeng Mi , Shimin Guo , Athira Rajeev , Chun-Tse Shao , Howard Chu , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-riscv@lists.infradead.org, Thomas Richter , libunwind-devel@nongnu.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a RISC-V implementation for unwinding. Signed-off-by: Ian Rogers --- tools/perf/util/libunwind-arch/Build | 1 + .../perf/util/libunwind-arch/libunwind-arch.c | 21 ++ .../perf/util/libunwind-arch/libunwind-arch.h | 22 ++ .../util/libunwind-arch/libunwind-riscv.c | 297 ++++++++++++++++++ 4 files changed, 341 insertions(+) create mode 100644 tools/perf/util/libunwind-arch/libunwind-riscv.c diff --git a/tools/perf/util/libunwind-arch/Build b/tools/perf/util/libunwi= nd-arch/Build index 87fd657a3248..80d3571918b1 100644 --- a/tools/perf/util/libunwind-arch/Build +++ b/tools/perf/util/libunwind-arch/Build @@ -5,6 +5,7 @@ perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-loongarch.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-mips.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-ppc32.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-ppc64.o +perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-riscv.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-s390.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-i386.o perf-util-$(CONFIG_LIBUNWIND) +=3D libunwind-x86_64.o diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.c b/tools/perf/u= til/libunwind-arch/libunwind-arch.c index 8539b4233df4..9a74cf3c8729 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arch.c +++ b/tools/perf/util/libunwind-arch/libunwind-arch.c @@ -20,6 +20,8 @@ int get_perf_regnum_for_unw_regnum(unsigned int e_machine= , int unw_regnum) return __get_perf_regnum_for_unw_regnum_ppc32(unw_regnum); case EM_PPC64: return __get_perf_regnum_for_unw_regnum_ppc64(unw_regnum); + case EM_RISCV: + return __get_perf_regnum_for_unw_regnum_riscv(unw_regnum); case EM_S390: return __get_perf_regnum_for_unw_regnum_s390(unw_regnum); case EM_386: @@ -58,6 +60,9 @@ void libunwind_arch__flush_access(struct maps *maps) case EM_PPC64: __libunwind_arch__flush_access_ppc64(maps); break; + case EM_RISCV: + __libunwind_arch__flush_access_riscv(maps); + break; case EM_S390: __libunwind_arch__flush_access_s390(maps); break; @@ -98,6 +103,9 @@ void libunwind_arch__finish_access(struct maps *maps) case EM_PPC64: __libunwind_arch__finish_access_ppc64(maps); break; + case EM_RISCV: + __libunwind_arch__finish_access_riscv(maps); + break; case EM_S390: __libunwind_arch__finish_access_s390(maps); break; @@ -128,6 +136,8 @@ void *libunwind_arch__create_addr_space(unsigned int e_= machine) return __libunwind_arch__create_addr_space_ppc32(); case EM_PPC64: return __libunwind_arch__create_addr_space_ppc64(); + case EM_RISCV: + return __libunwind_arch__create_addr_space_riscv(); case EM_S390: return __libunwind_arch__create_addr_space_s390(); case EM_386: @@ -167,6 +177,9 @@ int libunwind_arch__dwarf_search_unwind_table(unsigned = int e_machine, case EM_PPC64: return __libunwind_arch__dwarf_search_unwind_table_ppc64(as, ip, di, pi, need_unwind_info, arg); + case EM_RISCV: + return __libunwind_arch__dwarf_search_unwind_table_riscv(as, ip, di, pi, + need_unwind_info, arg); case EM_S390: return __libunwind_arch__dwarf_search_unwind_table_s390(as, ip, di, pi, need_unwind_info, arg); @@ -211,6 +224,9 @@ int libunwind_arch__dwarf_find_debug_frame(unsigned int= e_machine, case EM_PPC64: return __libunwind_arch__dwarf_find_debug_frame_ppc64(found, di_debug, i= p, segbase, obj_name, start, end); + case EM_RISCV: + return __libunwind_arch__dwarf_find_debug_frame_riscv(found, di_debug, i= p, segbase, + obj_name, start, end); case EM_S390: return __libunwind_arch__dwarf_find_debug_frame_s390(found, di_debug, ip= , segbase, obj_name, start, end); @@ -250,6 +266,9 @@ struct unwind_info *libunwind_arch_unwind_info__new(str= uct thread *thread, case EM_PPC64: return __libunwind_arch_unwind_info__new_ppc64(thread, sample, max_stack, best_effort, first_ip); + case EM_RISCV: + return __libunwind_arch_unwind_info__new_riscv(thread, sample, max_stack, + best_effort, first_ip); case EM_S390: return __libunwind_arch_unwind_info__new_s390(thread, sample, max_stack, best_effort, first_ip); @@ -285,6 +304,8 @@ int libunwind_arch__unwind_step(struct unwind_info *ui) return __libunwind_arch__unwind_step_ppc32(ui); case EM_PPC64: return __libunwind_arch__unwind_step_ppc64(ui); + case EM_RISCV: + return __libunwind_arch__unwind_step_riscv(ui); case EM_S390: return __libunwind_arch__unwind_step_s390(ui); case EM_386: diff --git a/tools/perf/util/libunwind-arch/libunwind-arch.h b/tools/perf/u= til/libunwind-arch/libunwind-arch.h index 2bf7fc33313b..74a09cd58f38 100644 --- a/tools/perf/util/libunwind-arch/libunwind-arch.h +++ b/tools/perf/util/libunwind-arch/libunwind-arch.h @@ -39,6 +39,7 @@ int __get_perf_regnum_for_unw_regnum_loongarch(int unw_re= gnum); int __get_perf_regnum_for_unw_regnum_mips(int unw_regnum); int __get_perf_regnum_for_unw_regnum_ppc32(int unw_regnum); int __get_perf_regnum_for_unw_regnum_ppc64(int unw_regnum); +int __get_perf_regnum_for_unw_regnum_riscv(int unw_regnum); int __get_perf_regnum_for_unw_regnum_s390(int unw_regnum); int __get_perf_regnum_for_unw_regnum_i386(int unw_regnum); int __get_perf_regnum_for_unw_regnum_x86_64(int unw_regnum); @@ -50,6 +51,7 @@ void __libunwind_arch__flush_access_loongarch(struct maps= *maps); void __libunwind_arch__flush_access_mips(struct maps *maps); void __libunwind_arch__flush_access_ppc32(struct maps *maps); void __libunwind_arch__flush_access_ppc64(struct maps *maps); +void __libunwind_arch__flush_access_riscv(struct maps *maps); void __libunwind_arch__flush_access_s390(struct maps *maps); void __libunwind_arch__flush_access_i386(struct maps *maps); void __libunwind_arch__flush_access_x86_64(struct maps *maps); @@ -61,6 +63,7 @@ void __libunwind_arch__finish_access_loongarch(struct map= s *maps); void __libunwind_arch__finish_access_mips(struct maps *maps); void __libunwind_arch__finish_access_ppc32(struct maps *maps); void __libunwind_arch__finish_access_ppc64(struct maps *maps); +void __libunwind_arch__finish_access_riscv(struct maps *maps); void __libunwind_arch__finish_access_s390(struct maps *maps); void __libunwind_arch__finish_access_i386(struct maps *maps); void __libunwind_arch__finish_access_x86_64(struct maps *maps); @@ -72,6 +75,7 @@ void *__libunwind_arch__create_addr_space_loongarch(void); void *__libunwind_arch__create_addr_space_mips(void); void *__libunwind_arch__create_addr_space_ppc32(void); void *__libunwind_arch__create_addr_space_ppc64(void); +void *__libunwind_arch__create_addr_space_riscv(void); void *__libunwind_arch__create_addr_space_s390(void); void *__libunwind_arch__create_addr_space_i386(void); void *__libunwind_arch__create_addr_space_x86_64(void); @@ -111,6 +115,11 @@ int __libunwind_arch__dwarf_search_unwind_table_ppc64(= void *as, uint64_t ip, void *pi, int need_unwind_info, void *arg); +int __libunwind_arch__dwarf_search_unwind_table_riscv(void *as, uint64_t i= p, + struct libarch_unwind__dyn_info *di, + void *pi, + int need_unwind_info, + void *arg); int __libunwind_arch__dwarf_search_unwind_table_s390(void *as, uint64_t ip, struct libarch_unwind__dyn_info *di, void *pi, @@ -176,6 +185,13 @@ int __libunwind_arch__dwarf_find_debug_frame_ppc64(int= found, const char *obj_name, uint64_t start, uint64_t end); +int __libunwind_arch__dwarf_find_debug_frame_riscv(int found, + struct libarch_unwind__dyn_info *di_debug, + uint64_t ip, + uint64_t segbase, + const char *obj_name, + uint64_t start, + uint64_t end); int __libunwind_arch__dwarf_find_debug_frame_s390(int found, struct libarch_unwind__dyn_info *di_debug, uint64_t ip, @@ -236,6 +252,11 @@ struct unwind_info *__libunwind_arch_unwind_info__new_= ppc64(struct thread *threa int max_stack, bool best_effort, uint64_t first_ip); +struct unwind_info *__libunwind_arch_unwind_info__new_riscv(struct thread = *thread, + struct perf_sample *sample, + int max_stack, + bool best_effort, + uint64_t first_ip); struct unwind_info *__libunwind_arch_unwind_info__new_s390(struct thread *= thread, struct perf_sample *sample, int max_stack, @@ -266,6 +287,7 @@ int __libunwind_arch__unwind_step_loongarch(struct unwi= nd_info *ui); int __libunwind_arch__unwind_step_mips(struct unwind_info *ui); int __libunwind_arch__unwind_step_ppc32(struct unwind_info *ui); int __libunwind_arch__unwind_step_ppc64(struct unwind_info *ui); +int __libunwind_arch__unwind_step_riscv(struct unwind_info *ui); int __libunwind_arch__unwind_step_s390(struct unwind_info *ui); int __libunwind_arch__unwind_step_i386(struct unwind_info *ui); int __libunwind_arch__unwind_step_x86_64(struct unwind_info *ui); diff --git a/tools/perf/util/libunwind-arch/libunwind-riscv.c b/tools/perf/= util/libunwind-arch/libunwind-riscv.c new file mode 100644 index 000000000000..dbca802b511c --- /dev/null +++ b/tools/perf/util/libunwind-arch/libunwind-riscv.c @@ -0,0 +1,297 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "libunwind-arch.h" +#include "../debug.h" +#include "../maps.h" +#include "../thread.h" +#include "../../../arch/riscv/include/uapi/asm/perf_regs.h" +#include +#include +#include +#include +#include + +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT +#include +#endif + +int __get_perf_regnum_for_unw_regnum_riscv(int unw_regnum __maybe_unused) +{ +#ifndef HAVE_LIBUNWIND_RISCV_SUPPORT + return -EINVAL; +#else + switch (unw_regnum) { + case UNW_RISCV_X1 ... UNW_RISCV_X31: + return unw_regnum - UNW_RISCV_X1 + PERF_REG_RISCV_RA; + case UNW_RISCV_PC: + return PERF_REG_RISCV_PC; + default: + pr_err("unwind: invalid reg id %d\n", unw_regnum); + return -EINVAL; + } +#endif // HAVE_LIBUNWIND_RISCV_SUPPORT +} + +void __libunwind_arch__flush_access_riscv(struct maps *maps __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT + unw_flush_cache(maps__addr_space(maps), 0, 0); +#endif +} + +void __libunwind_arch__finish_access_riscv(struct maps *maps __maybe_unuse= d) +{ +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT + unw_destroy_addr_space(maps__addr_space(maps)); +#endif +} + +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT +static int find_proc_info(unw_addr_space_t as, unw_word_t ip, unw_proc_inf= o_t *pi, + int need_unwind_info, void *arg) +{ + return __libunwind__find_proc_info(as, ip, pi, need_unwind_info, arg, siz= eof(unw_word_t)); +} + +static void put_unwind_info(unw_addr_space_t __maybe_unused as, + unw_proc_info_t *pi __maybe_unused, + void *arg __maybe_unused) +{ + pr_debug("unwind: put_unwind_info called\n"); +} + +static int get_dyn_info_list_addr(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused *dil_addr, + void __maybe_unused *arg) +{ + return -UNW_ENOINFO; +} + +static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *va= lp, + int __write, void *arg) +{ + return __libunwind__access_mem(as, addr, valp, __write, arg, sizeof(unw_w= ord_t)); +} + +static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t= *valp, + int __write, void *arg) +{ + return __libunwind__access_reg(as, regnum, valp, __write, arg, sizeof(unw= _word_t)); +} + +static int access_fpreg(unw_addr_space_t __maybe_unused as, + unw_regnum_t __maybe_unused num, + unw_fpreg_t __maybe_unused *val, + int __maybe_unused __write, + void __maybe_unused *arg) +{ + pr_err("unwind: access_fpreg unsupported\n"); + return -UNW_EINVAL; +} + +static int resume(unw_addr_space_t __maybe_unused as, + unw_cursor_t __maybe_unused *cu, + void __maybe_unused *arg) +{ + pr_err("unwind: resume unsupported\n"); + return -UNW_EINVAL; +} + +static int get_proc_name(unw_addr_space_t __maybe_unused as, + unw_word_t __maybe_unused addr, + char __maybe_unused *bufp, size_t __maybe_unused buf_len, + unw_word_t __maybe_unused *offp, void __maybe_unused *arg) +{ + pr_err("unwind: get_proc_name unsupported\n"); + return -UNW_EINVAL; +} +#endif + +void *__libunwind_arch__create_addr_space_riscv(void) +{ +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT + static unw_accessors_t accessors =3D { + .find_proc_info =3D find_proc_info, + .put_unwind_info =3D put_unwind_info, + .get_dyn_info_list_addr =3D get_dyn_info_list_addr, + .access_mem =3D access_mem, + .access_reg =3D access_reg, + .access_fpreg =3D access_fpreg, + .resume =3D resume, + .get_proc_name =3D get_proc_name, + }; + unw_addr_space_t addr_space; + + addr_space =3D unw_create_addr_space(&accessors, /*byte_order=3D*/0); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + return addr_space; +#else + return NULL; +#endif +} + +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT +extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, + unw_word_t ip, + unw_dyn_info_t *di, + unw_proc_info_t *pi, + int need_unwind_info, void *arg); +#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) +#endif + +int __libunwind_arch__dwarf_search_unwind_table_riscv(void *as __maybe_unu= sed, + uint64_t ip __maybe_unused, + struct libarch_unwind__dyn_info *_di __maybe_unused, + void *pi __maybe_unused, + int need_unwind_info __maybe_unused, + void *arg __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->table_len, + }, + }, + }; + int ret =3D dwarf_search_unwind_table(as, ip, &di, pi, need_unwind_info, = arg); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +#if defined(HAVE_LIBUNWIND_RISCV_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_RISCV) +extern int UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_= debug, + unw_word_t ip, + unw_word_t segbase, + const char *obj_name, unw_word_t start, + unw_word_t end); +#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) +#endif + +int __libunwind_arch__dwarf_find_debug_frame_riscv(int found __maybe_unuse= d, + struct libarch_unwind__dyn_info *_di __maybe_unused, + uint64_t ip __maybe_unused, + uint64_t segbase __maybe_unused, + const char *obj_name __maybe_unused, + uint64_t start __maybe_unused, + uint64_t end __maybe_unused) +{ +#if defined(HAVE_LIBUNWIND_RISCV_SUPPORT) && !defined(NO_LIBUNWIND_DEBUG_F= RAME_RISCV) + unw_dyn_info_t di =3D { + .format =3D UNW_INFO_FORMAT_REMOTE_TABLE, + .start_ip =3D _di->start_ip, + .end_ip =3D _di->end_ip, + .u =3D { + .rti =3D { + .segbase =3D _di->segbase, + .table_data =3D _di->table_data, + .table_len =3D _di->len, + }, + }, + }; + int ret =3D dwarf_find_debug_frame(found, &di, ip, segvase, obj_name, sta= rt, end); + + _di->start_ip =3D di.start_ip; + _di->end_ip =3D di.end_ip; + _di->segbase =3D di.u.rti.segbase; + _di->table_data =3D di.u.rti.table_data; + _di->table_len =3D di.u.rti.table_len; + return ret; +#else + return -EINVAL; +#endif +} + +struct unwind_info *__libunwind_arch_unwind_info__new_riscv(struct thread = *thread __maybe_unused, + struct perf_sample *sample __maybe_unused, + int max_stack __maybe_unused, + bool best_effort __maybe_unused, + uint64_t first_ip __maybe_unused) +{ +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT + struct x86_64_unwind_info { + struct unwind_info ui; + unw_cursor_t _cursor; + uint64_t _ips[]; + }; + + struct maps *maps =3D thread__maps(thread); + void *addr_space =3D maps__addr_space(maps); + struct x86_64_unwind_info *ui; + int ret; + + if (addr_space =3D=3D NULL) + return NULL; + + ui =3D zalloc(sizeof(*ui) + sizeof(ui->_ips[0]) * max_stack); + if (!ui) + return NULL; + + ui->ui.machine =3D maps__machine(maps); + ui->ui.thread =3D thread; + ui->ui.sample =3D sample; + ui->ui.cursor =3D &ui->_cursor; + ui->ui.ips =3D &ui->_ips[0]; + ui->ui.ips[0] =3D first_ip; + ui->ui.cur_ip =3D 1; + ui->ui.max_ips =3D max_stack; + ui->ui.unw_word_t_size =3D sizeof(unw_word_t); + ui->ui.e_machine =3D EM_RISCV; + ui->ui.best_effort =3D best_effort; + + ret =3D unw_init_remote(&ui->_cursor, addr_space, &ui->ui); + if (ret) { + if (!best_effort) + pr_err("libunwind: %s\n", unw_strerror(ret)); + free(ui); + return NULL; + } + + return &ui->ui; +#else + return NULL; +#endif +} + +int __libunwind_arch__unwind_step_riscv(struct unwind_info *ui __maybe_unu= sed) +{ +#ifdef HAVE_LIBUNWIND_RISCV_SUPPORT + int ret; + + if (ui->cur_ip >=3D ui->max_ips) + return -1; + + ret =3D unw_step(ui->cursor); + if (ret > 0) { + uint64_t ip; + + unw_get_reg(ui->cursor, UNW_REG_IP, &ip); + + if (unw_is_signal_frame(ui->cursor) <=3D 0) { + /* + * Decrement the IP for any non-activation frames. This + * is required to properly find the srcline for caller + * frames. See also the documentation for + * dwfl_frame_pc(), which this code tries to replicate. + */ + --ip; + } + ui->ips[ui->cur_ip++] =3D ip; + } + return ret; +#else + return -EINVAL; +#endif +} --=20 2.53.0.371.g1d285c8824-goog