All of lore.kernel.org
 help / color / mirror / Atom feed
From: madvenka@linux.microsoft.com
To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com,
	ardb@kernel.org, nobuta.keiya@fujitsu.com,
	sjitindarsingh@gmail.com, catalin.marinas@arm.com,
	will@kernel.org, jmorris@namei.org,
	linux-arm-kernel@lists.infradead.org,
	live-patching@vger.kernel.org, linux-kernel@vger.kernel.org,
	madvenka@linux.microsoft.com
Subject: [RFC PATCH v1 4/9] dwarf: Implement DWARF rule processing in the kernel
Date: Thu,  7 Apr 2022 15:25:13 -0500	[thread overview]
Message-ID: <20220407202518.19780-5-madvenka@linux.microsoft.com> (raw)
In-Reply-To: <20220407202518.19780-1-madvenka@linux.microsoft.com>

From: "Madhavan T. Venkataraman" <madvenka@linux.microsoft.com>

Define a struct dwarf_info to store all of the DWARF information needed to
lookup the DWARF rules for an instruction address. There is one dwarf_info
for vmlinux and one for every module.

Implement a lookup function dwarf_lookup(). Given an instruction address,
the function looks up the corresponding DWARF rules. The unwinder will use
the lookup function in the future.

Sort the rules based on instruction address. This allows a binary search.

Divide the text range into fixed sized blocks and map the rules to their
respective blocks. Given an instruction address, first locate the block
for the address. Then, perform a binary search within the rules in the
block. This minimizes the number of rules to consider in the binary search.

dwarf_info contains an array of PCs to search. In order to save space, store
the PCs array as an array of offsets from the base PC of the text range.
This way, we only need 32 bits to store the PC.

Signed-off-by: Madhavan T. Venkataraman <madvenka@linux.microsoft.com>
---
 arch/arm64/include/asm/sections.h |   4 +
 include/linux/dwarf.h             |  21 +++
 kernel/Makefile                   |   1 +
 kernel/dwarf_fp.c                 | 244 ++++++++++++++++++++++++++++++
 tools/include/linux/dwarf.h       |  21 +++
 5 files changed, 291 insertions(+)
 create mode 100644 kernel/dwarf_fp.c

diff --git a/arch/arm64/include/asm/sections.h b/arch/arm64/include/asm/sections.h
index 152cb35bf9df..d9095a9094b7 100644
--- a/arch/arm64/include/asm/sections.h
+++ b/arch/arm64/include/asm/sections.h
@@ -22,5 +22,9 @@ extern char __irqentry_text_start[], __irqentry_text_end[];
 extern char __mmuoff_data_start[], __mmuoff_data_end[];
 extern char __entry_tramp_text_start[], __entry_tramp_text_end[];
 extern char __relocate_new_kernel_start[], __relocate_new_kernel_end[];
+#ifdef CONFIG_DWARF_FP
+extern char __dwarf_rules_start[], __dwarf_rules_end[];
+extern char __dwarf_pcs_start[], __dwarf_pcs_end[];
+#endif
 
 #endif /* __ASM_SECTIONS_H */
diff --git a/include/linux/dwarf.h b/include/linux/dwarf.h
index 16e9dd8c60c8..3df15e79003c 100644
--- a/include/linux/dwarf.h
+++ b/include/linux/dwarf.h
@@ -40,4 +40,25 @@ struct dwarf_rule {
 	short		fp_offset;
 };
 
+/*
+ * The whole text area is divided into fixed sized blocks. Rules are mapped
+ * to their respective blocks. To find a block for an instruction address,
+ * the block of the address is located. Then, a binary search is performed
+ * on just the rules in the block. This minimizes the number of rules to
+ * be considered for the search.
+ */
+struct dwarf_block {
+	int		first_rule;
+	int		last_rule;
+};
+
+#ifdef CONFIG_DWARF_FP
+extern struct dwarf_rule	*dwarf_lookup(unsigned long pc);
+#else
+static inline struct dwarf_rule *dwarf_lookup(unsigned long pc)
+{
+	return NULL;
+}
+#endif
+
 #endif /* _LINUX_DWARF_H */
diff --git a/kernel/Makefile b/kernel/Makefile
index 186c49582f45..7582a6323446 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -130,6 +130,7 @@ obj-$(CONFIG_WATCH_QUEUE) += watch_queue.o
 
 obj-$(CONFIG_RESOURCE_KUNIT_TEST) += resource_kunit.o
 obj-$(CONFIG_SYSCTL_KUNIT_TEST) += sysctl-test.o
+obj-$(CONFIG_DWARF_FP) += dwarf_fp.o
 
 CFLAGS_stackleak.o += $(DISABLE_STACKLEAK_PLUGIN)
 obj-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak.o
diff --git a/kernel/dwarf_fp.c b/kernel/dwarf_fp.c
new file mode 100644
index 000000000000..bb14fbe3f3e1
--- /dev/null
+++ b/kernel/dwarf_fp.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * dwarf_fp.c - Allocate DWARF info. There will be one info for vmlinux
+ *		and one for every module. Implement a lookup function that
+ *		can locate the rule for a given instruction address.
+ *
+ * Copyright (C) 2021 Microsoft, Inc.
+ * Author: Madhavan T. Venkataraman <madvenka@microsoft.com>
+ */
+#include <linux/dwarf.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/types.h>
+#include <asm/sections.h>
+#include <asm/memory.h>
+
+#define OFFSET_BLOCK_SHIFT		12
+#define OFFSET_BLOCK(pc)		((pc) >> OFFSET_BLOCK_SHIFT)
+
+/*
+ * There is one struct dwarf_info for vmlinux and one for each module.
+ */
+struct dwarf_info {
+	struct dwarf_rule	*rules;
+	int			nrules;
+	unsigned int		*offsets;
+
+	struct dwarf_block	*blocks;
+	int			nblocks;
+
+	unsigned long		*pcs;
+	unsigned long		base_pc;
+	unsigned long		end_pc;
+};
+
+static DEFINE_MUTEX(dwarf_mutex);
+
+static struct dwarf_info	*vmlinux_dwarf_info;
+static struct dwarf_info	*cur_info;
+
+static int dwarf_compare(const void *arg1, const void *arg2)
+{
+	const unsigned long		*pc1 = arg1;
+	const unsigned long		*pc2 = arg2;
+
+	if (*pc1 > *pc2)
+		return 1;
+	if (*pc1 < *pc2)
+		return -1;
+	return 0;
+}
+
+static void dwarf_swap(void *arg1, void *arg2, int size)
+{
+	struct dwarf_rule	*rules = cur_info->rules;
+	unsigned long		*pc1 = arg1;
+	unsigned long		*pc2 = arg2;
+	int			i = (int) (pc1 - cur_info->pcs);
+	int			j = (int) (pc2 - cur_info->pcs);
+	unsigned long		tmp_pc;
+	struct dwarf_rule	tmp_rule;
+
+	tmp_pc = *pc1;
+	*pc1 = *pc2;
+	*pc2 = tmp_pc;
+
+	tmp_rule = rules[i];
+	rules[i] = rules[j];
+	rules[j] = tmp_rule;
+}
+
+/*
+ * Sort DWARF Records based on instruction addresses.
+ */
+static void dwarf_sort(struct dwarf_info *info)
+{
+	mutex_lock(&dwarf_mutex);
+
+	/*
+	 * cur_info is a global that allows us to sort both arrays in one go.
+	 */
+	cur_info = info;
+	sort(info->pcs, info->nrules, sizeof(*info->pcs),
+	     dwarf_compare, dwarf_swap);
+
+	mutex_unlock(&dwarf_mutex);
+}
+
+#define INVALID_RULE		-1
+
+static struct dwarf_info *dwarf_alloc(struct dwarf_rule *rules, int nrules,
+				      unsigned long *pcs)
+{
+	struct dwarf_info	*info;
+	unsigned int		*offsets, last_offset;
+	struct dwarf_block	*blocks;
+	int			r, b, nblocks;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return NULL;
+
+	info->rules = rules;
+	info->nrules = nrules;
+	info->pcs = pcs;
+
+	/* Sort pcs[] and rules[] in the increasing order of PC. */
+	dwarf_sort(info);
+
+	/* Compute the boundaries for the rules. */
+	info->base_pc = pcs[0];
+	info->end_pc = pcs[nrules - 1] + rules[nrules - 1].size;
+
+	offsets = kmalloc_array(nrules, sizeof(*offsets), GFP_KERNEL);
+	if (!offsets)
+		goto free_info;
+
+	/* Store the PCs as offsets from the base PC. This is to save memory. */
+	for (r = 0; r < nrules; r++)
+		offsets[r] = pcs[r] - info->base_pc;
+
+	/* Compute the number of blocks. */
+	last_offset = offsets[nrules - 1];
+	nblocks = OFFSET_BLOCK(last_offset) + 1;
+
+	blocks = kmalloc_array(nblocks, sizeof(*blocks), GFP_KERNEL);
+	if (!blocks)
+		goto free_offsets;
+
+	/* Initialize blocks. */
+	for (b = 0; b < nblocks; b++) {
+		blocks[b].first_rule = INVALID_RULE;
+		blocks[b].last_rule = INVALID_RULE;
+	}
+
+	/* Map rules to blocks. */
+	for (r = 0; r < nrules; r++) {
+		b = OFFSET_BLOCK(offsets[r]);
+		if (blocks[b].first_rule == INVALID_RULE)
+			blocks[b].first_rule = r;
+		blocks[b].last_rule = r;
+	}
+
+	/* Initialize empty blocks. */
+	for (b = 0; b < nblocks; b++) {
+		if (blocks[b].first_rule == INVALID_RULE) {
+			blocks[b].first_rule = blocks[b - 1].last_rule;
+			blocks[b].last_rule = blocks[b - 1].last_rule;
+		}
+	}
+
+	info->blocks = blocks;
+	info->nblocks = nblocks;
+	info->offsets = offsets;
+
+	/* PCs for vmlinux is in init data. It will discarded. */
+	info->pcs = NULL;
+
+	return info;
+free_offsets:
+	kfree(offsets);
+free_info:
+	kfree(info);
+	return NULL;
+}
+
+static struct dwarf_rule *dwarf_lookup_rule(struct dwarf_info *info,
+					    unsigned long pc)
+{
+	struct dwarf_block	*blocks = info->blocks;
+	unsigned int		*offsets = info->offsets, off;
+	struct dwarf_rule	*rule;
+	int			start, mid, end, n, b;
+
+	if (pc < info->base_pc || pc >= info->end_pc)
+		return NULL;
+
+	/* Make PC relative to the base for binary search. */
+	off = pc - info->base_pc;
+
+	/*
+	 * Locate the block for the offset. Do a binary search between the
+	 * start and end rules in the block.
+	 */
+	b = OFFSET_BLOCK(off);
+	start = blocks[b].first_rule;
+	end = blocks[b].last_rule + 1;
+
+	if (off < offsets[start])
+		start--;
+
+	/*
+	 * Binary search. For cache performance, we search in offsets[]
+	 * first and locate a candidate rule. Then, we perform a range check
+	 * for the candidate rule at the end. This is so that rules[]
+	 * is only accessed at the end of the search.
+	 */
+	for (n = end - start; n > 1; n = end - start) {
+		mid = start + (n >> 1);
+
+		if (off >= offsets[mid])
+			start = mid;
+		else
+			end = mid;
+	}
+
+	/* Do a final range check. */
+	rule = &info->rules[start];
+	if (off >= offsets[start] && off < (offsets[start] + rule->size))
+		return rule;
+
+	return NULL;
+}
+
+struct dwarf_rule *dwarf_lookup(unsigned long pc)
+{
+	/*
+	 * Currently, only looks up vmlinux. Support for modules will be
+	 * added later.
+	 */
+	return dwarf_lookup_rule(vmlinux_dwarf_info, pc);
+}
+
+static int __init dwarf_init_feature(void)
+{
+	struct dwarf_rule	*rules;
+	unsigned long		*pcs;
+	int			nrules, npcs;
+
+	rules = (struct dwarf_rule *) __dwarf_rules_start;
+	nrules = (__dwarf_rules_end - __dwarf_rules_start) / sizeof(*rules);
+	if (!nrules)
+		return -EINVAL;
+
+	pcs = (unsigned long *) __dwarf_pcs_start;
+	npcs = (__dwarf_pcs_end - __dwarf_pcs_start) / sizeof(*pcs);
+	if (npcs != nrules)
+		return -EINVAL;
+
+	vmlinux_dwarf_info = dwarf_alloc(rules, nrules, pcs);
+
+	return vmlinux_dwarf_info ? 0 : -EINVAL;
+}
+early_initcall(dwarf_init_feature);
diff --git a/tools/include/linux/dwarf.h b/tools/include/linux/dwarf.h
index 16e9dd8c60c8..3df15e79003c 100644
--- a/tools/include/linux/dwarf.h
+++ b/tools/include/linux/dwarf.h
@@ -40,4 +40,25 @@ struct dwarf_rule {
 	short		fp_offset;
 };
 
+/*
+ * The whole text area is divided into fixed sized blocks. Rules are mapped
+ * to their respective blocks. To find a block for an instruction address,
+ * the block of the address is located. Then, a binary search is performed
+ * on just the rules in the block. This minimizes the number of rules to
+ * be considered for the search.
+ */
+struct dwarf_block {
+	int		first_rule;
+	int		last_rule;
+};
+
+#ifdef CONFIG_DWARF_FP
+extern struct dwarf_rule	*dwarf_lookup(unsigned long pc);
+#else
+static inline struct dwarf_rule *dwarf_lookup(unsigned long pc)
+{
+	return NULL;
+}
+#endif
+
 #endif /* _LINUX_DWARF_H */
-- 
2.25.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

WARNING: multiple messages have this Message-ID (diff)
From: madvenka@linux.microsoft.com
To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com,
	ardb@kernel.org, nobuta.keiya@fujitsu.com,
	sjitindarsingh@gmail.com, catalin.marinas@arm.com,
	will@kernel.org, jmorris@namei.org,
	linux-arm-kernel@lists.infradead.org,
	live-patching@vger.kernel.org, linux-kernel@vger.kernel.org,
	madvenka@linux.microsoft.com
Subject: [RFC PATCH v1 4/9] dwarf: Implement DWARF rule processing in the kernel
Date: Thu,  7 Apr 2022 15:25:13 -0500	[thread overview]
Message-ID: <20220407202518.19780-5-madvenka@linux.microsoft.com> (raw)
In-Reply-To: <20220407202518.19780-1-madvenka@linux.microsoft.com>

From: "Madhavan T. Venkataraman" <madvenka@linux.microsoft.com>

Define a struct dwarf_info to store all of the DWARF information needed to
lookup the DWARF rules for an instruction address. There is one dwarf_info
for vmlinux and one for every module.

Implement a lookup function dwarf_lookup(). Given an instruction address,
the function looks up the corresponding DWARF rules. The unwinder will use
the lookup function in the future.

Sort the rules based on instruction address. This allows a binary search.

Divide the text range into fixed sized blocks and map the rules to their
respective blocks. Given an instruction address, first locate the block
for the address. Then, perform a binary search within the rules in the
block. This minimizes the number of rules to consider in the binary search.

dwarf_info contains an array of PCs to search. In order to save space, store
the PCs array as an array of offsets from the base PC of the text range.
This way, we only need 32 bits to store the PC.

Signed-off-by: Madhavan T. Venkataraman <madvenka@linux.microsoft.com>
---
 arch/arm64/include/asm/sections.h |   4 +
 include/linux/dwarf.h             |  21 +++
 kernel/Makefile                   |   1 +
 kernel/dwarf_fp.c                 | 244 ++++++++++++++++++++++++++++++
 tools/include/linux/dwarf.h       |  21 +++
 5 files changed, 291 insertions(+)
 create mode 100644 kernel/dwarf_fp.c

diff --git a/arch/arm64/include/asm/sections.h b/arch/arm64/include/asm/sections.h
index 152cb35bf9df..d9095a9094b7 100644
--- a/arch/arm64/include/asm/sections.h
+++ b/arch/arm64/include/asm/sections.h
@@ -22,5 +22,9 @@ extern char __irqentry_text_start[], __irqentry_text_end[];
 extern char __mmuoff_data_start[], __mmuoff_data_end[];
 extern char __entry_tramp_text_start[], __entry_tramp_text_end[];
 extern char __relocate_new_kernel_start[], __relocate_new_kernel_end[];
+#ifdef CONFIG_DWARF_FP
+extern char __dwarf_rules_start[], __dwarf_rules_end[];
+extern char __dwarf_pcs_start[], __dwarf_pcs_end[];
+#endif
 
 #endif /* __ASM_SECTIONS_H */
diff --git a/include/linux/dwarf.h b/include/linux/dwarf.h
index 16e9dd8c60c8..3df15e79003c 100644
--- a/include/linux/dwarf.h
+++ b/include/linux/dwarf.h
@@ -40,4 +40,25 @@ struct dwarf_rule {
 	short		fp_offset;
 };
 
+/*
+ * The whole text area is divided into fixed sized blocks. Rules are mapped
+ * to their respective blocks. To find a block for an instruction address,
+ * the block of the address is located. Then, a binary search is performed
+ * on just the rules in the block. This minimizes the number of rules to
+ * be considered for the search.
+ */
+struct dwarf_block {
+	int		first_rule;
+	int		last_rule;
+};
+
+#ifdef CONFIG_DWARF_FP
+extern struct dwarf_rule	*dwarf_lookup(unsigned long pc);
+#else
+static inline struct dwarf_rule *dwarf_lookup(unsigned long pc)
+{
+	return NULL;
+}
+#endif
+
 #endif /* _LINUX_DWARF_H */
diff --git a/kernel/Makefile b/kernel/Makefile
index 186c49582f45..7582a6323446 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -130,6 +130,7 @@ obj-$(CONFIG_WATCH_QUEUE) += watch_queue.o
 
 obj-$(CONFIG_RESOURCE_KUNIT_TEST) += resource_kunit.o
 obj-$(CONFIG_SYSCTL_KUNIT_TEST) += sysctl-test.o
+obj-$(CONFIG_DWARF_FP) += dwarf_fp.o
 
 CFLAGS_stackleak.o += $(DISABLE_STACKLEAK_PLUGIN)
 obj-$(CONFIG_GCC_PLUGIN_STACKLEAK) += stackleak.o
diff --git a/kernel/dwarf_fp.c b/kernel/dwarf_fp.c
new file mode 100644
index 000000000000..bb14fbe3f3e1
--- /dev/null
+++ b/kernel/dwarf_fp.c
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * dwarf_fp.c - Allocate DWARF info. There will be one info for vmlinux
+ *		and one for every module. Implement a lookup function that
+ *		can locate the rule for a given instruction address.
+ *
+ * Copyright (C) 2021 Microsoft, Inc.
+ * Author: Madhavan T. Venkataraman <madvenka@microsoft.com>
+ */
+#include <linux/dwarf.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/types.h>
+#include <asm/sections.h>
+#include <asm/memory.h>
+
+#define OFFSET_BLOCK_SHIFT		12
+#define OFFSET_BLOCK(pc)		((pc) >> OFFSET_BLOCK_SHIFT)
+
+/*
+ * There is one struct dwarf_info for vmlinux and one for each module.
+ */
+struct dwarf_info {
+	struct dwarf_rule	*rules;
+	int			nrules;
+	unsigned int		*offsets;
+
+	struct dwarf_block	*blocks;
+	int			nblocks;
+
+	unsigned long		*pcs;
+	unsigned long		base_pc;
+	unsigned long		end_pc;
+};
+
+static DEFINE_MUTEX(dwarf_mutex);
+
+static struct dwarf_info	*vmlinux_dwarf_info;
+static struct dwarf_info	*cur_info;
+
+static int dwarf_compare(const void *arg1, const void *arg2)
+{
+	const unsigned long		*pc1 = arg1;
+	const unsigned long		*pc2 = arg2;
+
+	if (*pc1 > *pc2)
+		return 1;
+	if (*pc1 < *pc2)
+		return -1;
+	return 0;
+}
+
+static void dwarf_swap(void *arg1, void *arg2, int size)
+{
+	struct dwarf_rule	*rules = cur_info->rules;
+	unsigned long		*pc1 = arg1;
+	unsigned long		*pc2 = arg2;
+	int			i = (int) (pc1 - cur_info->pcs);
+	int			j = (int) (pc2 - cur_info->pcs);
+	unsigned long		tmp_pc;
+	struct dwarf_rule	tmp_rule;
+
+	tmp_pc = *pc1;
+	*pc1 = *pc2;
+	*pc2 = tmp_pc;
+
+	tmp_rule = rules[i];
+	rules[i] = rules[j];
+	rules[j] = tmp_rule;
+}
+
+/*
+ * Sort DWARF Records based on instruction addresses.
+ */
+static void dwarf_sort(struct dwarf_info *info)
+{
+	mutex_lock(&dwarf_mutex);
+
+	/*
+	 * cur_info is a global that allows us to sort both arrays in one go.
+	 */
+	cur_info = info;
+	sort(info->pcs, info->nrules, sizeof(*info->pcs),
+	     dwarf_compare, dwarf_swap);
+
+	mutex_unlock(&dwarf_mutex);
+}
+
+#define INVALID_RULE		-1
+
+static struct dwarf_info *dwarf_alloc(struct dwarf_rule *rules, int nrules,
+				      unsigned long *pcs)
+{
+	struct dwarf_info	*info;
+	unsigned int		*offsets, last_offset;
+	struct dwarf_block	*blocks;
+	int			r, b, nblocks;
+
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return NULL;
+
+	info->rules = rules;
+	info->nrules = nrules;
+	info->pcs = pcs;
+
+	/* Sort pcs[] and rules[] in the increasing order of PC. */
+	dwarf_sort(info);
+
+	/* Compute the boundaries for the rules. */
+	info->base_pc = pcs[0];
+	info->end_pc = pcs[nrules - 1] + rules[nrules - 1].size;
+
+	offsets = kmalloc_array(nrules, sizeof(*offsets), GFP_KERNEL);
+	if (!offsets)
+		goto free_info;
+
+	/* Store the PCs as offsets from the base PC. This is to save memory. */
+	for (r = 0; r < nrules; r++)
+		offsets[r] = pcs[r] - info->base_pc;
+
+	/* Compute the number of blocks. */
+	last_offset = offsets[nrules - 1];
+	nblocks = OFFSET_BLOCK(last_offset) + 1;
+
+	blocks = kmalloc_array(nblocks, sizeof(*blocks), GFP_KERNEL);
+	if (!blocks)
+		goto free_offsets;
+
+	/* Initialize blocks. */
+	for (b = 0; b < nblocks; b++) {
+		blocks[b].first_rule = INVALID_RULE;
+		blocks[b].last_rule = INVALID_RULE;
+	}
+
+	/* Map rules to blocks. */
+	for (r = 0; r < nrules; r++) {
+		b = OFFSET_BLOCK(offsets[r]);
+		if (blocks[b].first_rule == INVALID_RULE)
+			blocks[b].first_rule = r;
+		blocks[b].last_rule = r;
+	}
+
+	/* Initialize empty blocks. */
+	for (b = 0; b < nblocks; b++) {
+		if (blocks[b].first_rule == INVALID_RULE) {
+			blocks[b].first_rule = blocks[b - 1].last_rule;
+			blocks[b].last_rule = blocks[b - 1].last_rule;
+		}
+	}
+
+	info->blocks = blocks;
+	info->nblocks = nblocks;
+	info->offsets = offsets;
+
+	/* PCs for vmlinux is in init data. It will discarded. */
+	info->pcs = NULL;
+
+	return info;
+free_offsets:
+	kfree(offsets);
+free_info:
+	kfree(info);
+	return NULL;
+}
+
+static struct dwarf_rule *dwarf_lookup_rule(struct dwarf_info *info,
+					    unsigned long pc)
+{
+	struct dwarf_block	*blocks = info->blocks;
+	unsigned int		*offsets = info->offsets, off;
+	struct dwarf_rule	*rule;
+	int			start, mid, end, n, b;
+
+	if (pc < info->base_pc || pc >= info->end_pc)
+		return NULL;
+
+	/* Make PC relative to the base for binary search. */
+	off = pc - info->base_pc;
+
+	/*
+	 * Locate the block for the offset. Do a binary search between the
+	 * start and end rules in the block.
+	 */
+	b = OFFSET_BLOCK(off);
+	start = blocks[b].first_rule;
+	end = blocks[b].last_rule + 1;
+
+	if (off < offsets[start])
+		start--;
+
+	/*
+	 * Binary search. For cache performance, we search in offsets[]
+	 * first and locate a candidate rule. Then, we perform a range check
+	 * for the candidate rule at the end. This is so that rules[]
+	 * is only accessed at the end of the search.
+	 */
+	for (n = end - start; n > 1; n = end - start) {
+		mid = start + (n >> 1);
+
+		if (off >= offsets[mid])
+			start = mid;
+		else
+			end = mid;
+	}
+
+	/* Do a final range check. */
+	rule = &info->rules[start];
+	if (off >= offsets[start] && off < (offsets[start] + rule->size))
+		return rule;
+
+	return NULL;
+}
+
+struct dwarf_rule *dwarf_lookup(unsigned long pc)
+{
+	/*
+	 * Currently, only looks up vmlinux. Support for modules will be
+	 * added later.
+	 */
+	return dwarf_lookup_rule(vmlinux_dwarf_info, pc);
+}
+
+static int __init dwarf_init_feature(void)
+{
+	struct dwarf_rule	*rules;
+	unsigned long		*pcs;
+	int			nrules, npcs;
+
+	rules = (struct dwarf_rule *) __dwarf_rules_start;
+	nrules = (__dwarf_rules_end - __dwarf_rules_start) / sizeof(*rules);
+	if (!nrules)
+		return -EINVAL;
+
+	pcs = (unsigned long *) __dwarf_pcs_start;
+	npcs = (__dwarf_pcs_end - __dwarf_pcs_start) / sizeof(*pcs);
+	if (npcs != nrules)
+		return -EINVAL;
+
+	vmlinux_dwarf_info = dwarf_alloc(rules, nrules, pcs);
+
+	return vmlinux_dwarf_info ? 0 : -EINVAL;
+}
+early_initcall(dwarf_init_feature);
diff --git a/tools/include/linux/dwarf.h b/tools/include/linux/dwarf.h
index 16e9dd8c60c8..3df15e79003c 100644
--- a/tools/include/linux/dwarf.h
+++ b/tools/include/linux/dwarf.h
@@ -40,4 +40,25 @@ struct dwarf_rule {
 	short		fp_offset;
 };
 
+/*
+ * The whole text area is divided into fixed sized blocks. Rules are mapped
+ * to their respective blocks. To find a block for an instruction address,
+ * the block of the address is located. Then, a binary search is performed
+ * on just the rules in the block. This minimizes the number of rules to
+ * be considered for the search.
+ */
+struct dwarf_block {
+	int		first_rule;
+	int		last_rule;
+};
+
+#ifdef CONFIG_DWARF_FP
+extern struct dwarf_rule	*dwarf_lookup(unsigned long pc);
+#else
+static inline struct dwarf_rule *dwarf_lookup(unsigned long pc)
+{
+	return NULL;
+}
+#endif
+
 #endif /* _LINUX_DWARF_H */
-- 
2.25.1


  parent reply	other threads:[~2022-04-07 20:28 UTC|newest]

Thread overview: 150+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <95691cae4f4504f33d0fc9075541b1e7deefe96f>
2022-01-17 14:55 ` [PATCH v13 00/11] arm64: Reorganize the unwinder and implement stack trace reliability checks madvenka
2022-01-17 14:55   ` madvenka
2022-01-17 14:55   ` [PATCH v13 01/11] arm64: Remove NULL task check from unwind_frame() madvenka
2022-01-17 14:55     ` madvenka
2022-01-17 14:55   ` [PATCH v13 02/11] arm64: Rename unwinder functions madvenka
2022-01-17 14:55     ` madvenka
2022-01-17 14:56   ` [PATCH v13 03/11] arm64: Rename stackframe to unwind_state madvenka
2022-01-17 14:56     ` madvenka
2022-01-17 14:56   ` [PATCH v13 04/11] arm64: Split unwind_init() madvenka
2022-01-17 14:56     ` madvenka
2022-02-02 18:44     ` Mark Brown
2022-02-02 18:44       ` Mark Brown
2022-02-03  0:26       ` Madhavan T. Venkataraman
2022-02-03  0:26         ` Madhavan T. Venkataraman
2022-02-03  0:39         ` Madhavan T. Venkataraman
2022-02-03  0:39           ` Madhavan T. Venkataraman
2022-02-03 11:29           ` Mark Brown
2022-02-03 11:29             ` Mark Brown
2022-02-15 13:07     ` Mark Rutland
2022-02-15 13:07       ` Mark Rutland
2022-02-15 18:04       ` Madhavan T. Venkataraman
2022-02-15 18:04         ` Madhavan T. Venkataraman
2022-01-17 14:56   ` [PATCH v13 05/11] arm64: Copy the task argument to unwind_state madvenka
2022-01-17 14:56     ` madvenka
2022-02-02 18:45     ` Mark Brown
2022-02-02 18:45       ` Mark Brown
2022-02-15 13:22     ` Mark Rutland
2022-02-15 13:22       ` Mark Rutland
2022-02-22 16:53       ` Madhavan T. Venkataraman
2022-02-22 16:53         ` Madhavan T. Venkataraman
2022-01-17 14:56   ` [PATCH v13 06/11] arm64: Use stack_trace_consume_fn and rename args to unwind() madvenka
2022-01-17 14:56     ` madvenka
2022-02-02 18:46     ` Mark Brown
2022-02-02 18:46       ` Mark Brown
2022-02-03  0:34       ` Madhavan T. Venkataraman
2022-02-03  0:34         ` Madhavan T. Venkataraman
2022-02-03 11:30         ` Mark Brown
2022-02-03 11:30           ` Mark Brown
2022-02-03 14:45           ` Madhavan T. Venkataraman
2022-02-03 14:45             ` Madhavan T. Venkataraman
2022-02-15 13:39     ` Mark Rutland
2022-02-15 13:39       ` Mark Rutland
2022-02-15 18:12       ` Madhavan T. Venkataraman
2022-02-15 18:12         ` Madhavan T. Venkataraman
2022-03-07 16:51       ` Madhavan T. Venkataraman
2022-03-07 16:51         ` Madhavan T. Venkataraman
2022-03-07 17:01         ` Mark Brown
2022-03-07 17:01           ` Mark Brown
2022-03-08 22:00           ` Madhavan T. Venkataraman
2022-03-08 22:00             ` Madhavan T. Venkataraman
2022-03-09 11:47             ` Mark Brown
2022-03-09 11:47               ` Mark Brown
2022-03-09 15:34               ` Madhavan T. Venkataraman
2022-03-09 15:34                 ` Madhavan T. Venkataraman
2022-03-10  8:33               ` Miroslav Benes
2022-03-10  8:33                 ` Miroslav Benes
2022-03-10 12:36                 ` Madhavan T. Venkataraman
2022-03-10 12:36                   ` Madhavan T. Venkataraman
2022-03-16  3:43               ` Josh Poimboeuf
2022-03-16  3:43                 ` Josh Poimboeuf
2022-04-08 14:44         ` Mark Rutland
2022-04-08 14:44           ` Mark Rutland
2022-04-08 17:58           ` Mark Rutland
2022-04-08 17:58             ` Mark Rutland
2022-04-10 17:42             ` Madhavan T. Venkataraman
2022-04-10 17:42               ` Madhavan T. Venkataraman
2022-04-10 17:33           ` Madhavan T. Venkataraman
2022-04-10 17:33             ` Madhavan T. Venkataraman
2022-04-10 17:45           ` Madhavan T. Venkataraman
2022-04-10 17:45             ` Madhavan T. Venkataraman
2022-01-17 14:56   ` [PATCH v13 07/11] arm64: Make the unwind loop in unwind() similar to other architectures madvenka
2022-01-17 14:56     ` madvenka
2022-01-17 14:56   ` [PATCH v13 08/11] arm64: Introduce stack trace reliability checks in the unwinder madvenka
2022-01-17 14:56     ` madvenka
2022-01-17 14:56   ` [PATCH v13 09/11] arm64: Create a list of SYM_CODE functions, check return PC against list madvenka
2022-01-17 14:56     ` madvenka
2022-01-17 14:56   ` [PATCH v13 10/11] arm64: Introduce arch_stack_walk_reliable() madvenka
2022-01-17 14:56     ` madvenka
2022-01-17 14:56   ` [PATCH v13 11/11] arm64: Select HAVE_RELIABLE_STACKTRACE madvenka
2022-01-17 14:56     ` madvenka
2022-01-25  5:21     ` nobuta.keiya
2022-01-25  5:21       ` nobuta.keiya
2022-01-25 13:43       ` Madhavan T. Venkataraman
2022-01-25 13:43         ` Madhavan T. Venkataraman
2022-01-26 10:20         ` nobuta.keiya
2022-01-26 10:20           ` nobuta.keiya
2022-01-26 17:14           ` Madhavan T. Venkataraman
2022-01-26 17:14             ` Madhavan T. Venkataraman
2022-01-27  1:13             ` nobuta.keiya
2022-01-27  1:13               ` nobuta.keiya
2022-01-26 17:16       ` Mark Brown
2022-01-26 17:16         ` Mark Brown
2022-04-07 20:25 ` [RFC PATCH v1 0/9] arm64: livepatch: Use DWARF Call Frame Information for frame pointer validation madvenka
2022-04-07 20:25   ` madvenka
2022-04-07 20:25   ` [RFC PATCH v1 1/9] objtool: Parse DWARF Call Frame Information in object files madvenka
2022-04-07 20:25     ` madvenka
2022-04-07 20:25   ` [RFC PATCH v1 2/9] objtool: Generate DWARF rules and place them in a special section madvenka
2022-04-07 20:25     ` madvenka
2022-04-07 20:25   ` [RFC PATCH v1 3/9] dwarf: Build the kernel with DWARF information madvenka
2022-04-07 20:25     ` madvenka
2022-04-07 20:25   ` madvenka [this message]
2022-04-07 20:25     ` [RFC PATCH v1 4/9] dwarf: Implement DWARF rule processing in the kernel madvenka
2022-04-07 20:25   ` [RFC PATCH v1 5/9] dwarf: Implement DWARF support for modules madvenka
2022-04-07 20:25     ` madvenka
2022-04-07 20:25   ` [RFC PATCH v1 6/9] arm64: unwinder: Add a reliability check in the unwinder based on DWARF CFI madvenka
2022-04-07 20:25     ` madvenka
2022-04-07 20:25   ` [RFC PATCH v1 7/9] arm64: dwarf: Implement unwind hints madvenka
2022-04-07 20:25     ` madvenka
2022-04-07 20:25   ` [RFC PATCH v1 8/9] dwarf: Miscellaneous changes required for enabling livepatch madvenka
2022-04-07 20:25     ` madvenka
2022-04-07 20:25   ` [RFC PATCH v1 9/9] dwarf: Enable livepatch for ARM64 madvenka
2022-04-07 20:25     ` madvenka
2022-04-08  0:21   ` [RFC PATCH v1 0/9] arm64: livepatch: Use DWARF Call Frame Information for frame pointer validation Josh Poimboeuf
2022-04-08  0:21     ` Josh Poimboeuf
2022-04-08 11:41     ` Peter Zijlstra
2022-04-08 11:41       ` Peter Zijlstra
2022-04-11 17:26       ` Madhavan T. Venkataraman
2022-04-11 17:26         ` Madhavan T. Venkataraman
2022-04-11 17:18     ` Madhavan T. Venkataraman
2022-04-11 17:18       ` Madhavan T. Venkataraman
2022-04-12  8:32       ` Chen Zhongjin
2022-04-12  8:32         ` Chen Zhongjin
2022-04-16  0:56         ` Josh Poimboeuf
2022-04-16  0:56           ` Josh Poimboeuf
2022-04-18 12:28           ` Chen Zhongjin
2022-04-18 12:28             ` Chen Zhongjin
2022-04-18 16:11             ` Josh Poimboeuf
2022-04-18 16:11               ` Josh Poimboeuf
2022-04-18 18:38               ` Madhavan T. Venkataraman
2022-04-18 18:38                 ` Madhavan T. Venkataraman
     [not found]       ` <844b3ede-eddb-cbe6-80e0-3529e2da2eb6@huawei.com>
2022-04-12 17:27         ` Madhavan T. Venkataraman
2022-04-12 17:27           ` Madhavan T. Venkataraman
2022-04-16  1:07       ` Josh Poimboeuf
2022-04-16  1:07         ` Josh Poimboeuf
2022-04-14 14:11     ` Madhavan T. Venkataraman
2022-04-14 14:11       ` Madhavan T. Venkataraman
2022-04-08 10:55   ` Peter Zijlstra
2022-04-08 10:55     ` Peter Zijlstra
2022-04-08 11:54     ` Peter Zijlstra
2022-04-08 11:54       ` Peter Zijlstra
2022-04-08 14:34       ` Josh Poimboeuf
2022-04-08 14:34         ` Josh Poimboeuf
2022-04-10 17:47     ` Madhavan T. Venkataraman
2022-04-10 17:47       ` Madhavan T. Venkataraman
2022-04-11 16:34       ` Josh Poimboeuf
2022-04-11 16:34         ` Josh Poimboeuf
2022-04-08 12:06   ` Peter Zijlstra
2022-04-08 12:06     ` Peter Zijlstra
2022-04-11 17:35     ` Madhavan T. Venkataraman
2022-04-11 17:35       ` Madhavan T. Venkataraman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220407202518.19780-5-madvenka@linux.microsoft.com \
    --to=madvenka@linux.microsoft.com \
    --cc=ardb@kernel.org \
    --cc=broonie@kernel.org \
    --cc=catalin.marinas@arm.com \
    --cc=jmorris@namei.org \
    --cc=jpoimboe@redhat.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=live-patching@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=nobuta.keiya@fujitsu.com \
    --cc=sjitindarsingh@gmail.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.