[Crash-utility] [PATCH v1 3/5] x86_64: Add gdb multi-stack unwind support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Whenever extra stack is found, a user_regs structure is allocated and
regs value copied there. Later the values will be retrived by
get_current_task_reg() by given the thread's tid, aka the index of
stack.

Co-developed-by: Alexey Makhalov <alexey.makhalov@xxxxxxxxxxxx>
Co-developed-by: Tao Liu <ltao@xxxxxxxxxx>
Signed-off-by: Tao Liu <ltao@xxxxxxxxxx>
---
 x86_64.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 51 insertions(+), 10 deletions(-)

diff --git a/x86_64.c b/x86_64.c
index e544be8..ca745a6 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -3551,6 +3551,7 @@ x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in)
 	irq_eframe = 0;
 	last_process_stack_eframe = 0;
 	bt->call_target = NULL;
+	extra_stacks_idx = 0;
 	rsp = bt->stkptr;
 	ms = machdep->machspec;
 
@@ -4159,6 +4160,7 @@ x86_64_dwarf_back_trace_cmd(struct bt_info *bt_in)
 	last_process_stack_eframe = 0;
 	bt->call_target = NULL;
 	bt->bptr = 0;
+	extra_stacks_idx = 0;
 	rsp = bt->stkptr;
 	if (!rsp) {
 		error(INFO, "cannot determine starting stack pointer\n");
@@ -4546,6 +4548,9 @@ x86_64_back_trace(struct gnu_request *req, struct bt_info *bt)
  *
  */
 
+#define SET_REG_BITMAP(REGMAP, TYPE, MEMBER) \
+	SET_BIT(REGMAP, REG_SEQ(TYPE, MEMBER))
+
 long
 x86_64_exception_frame(ulong flags, ulong kvaddr, char *local,
 	struct bt_info *bt, FILE *ofp)
@@ -4799,6 +4804,22 @@ x86_64_exception_frame(ulong flags, ulong kvaddr, char *local,
 	} else if (machdep->flags & ORC)
 		bt->bptr = rbp;
 
+	/*
+	 * Preserve registers set for each additional in-kernel stack
+	 */
+	if (!(cs & 3) && verified && flags & EFRAME_PRINT &&
+	    extra_stacks_idx < MAX_EXCEPTION_STACKS) {
+		if (!extra_stacks_regs[extra_stacks_idx]) {
+			extra_stacks_regs[extra_stacks_idx] = (struct user_regs_bitmap_struct *)
+				GETBUF(sizeof(struct user_regs_bitmap_struct *));
+		}
+		memcpy(&extra_stacks_regs[extra_stacks_idx]->ur,
+			pt_regs_buf, SIZE(pt_regs));
+		for (int i = 0; i < SIZE(pt_regs)/sizeof(long); i++)
+			SET_BIT(extra_stacks_regs[extra_stacks_idx]->bitmap, i);
+		gdb_add_substack(extra_stacks_idx++);
+	}
+
 	if (kvaddr)
 		FREEBUF(pt_regs_buf);
 
@@ -5002,9 +5023,6 @@ get_reg_from_inactive_task_frame(struct bt_info *bt, char *reg_name,
 	return reg_value;
 }
 
-#define SET_REG_BITMAP(REGMAP, TYPE, MEMBER) \
-	SET_BIT(REGMAP, REG_SEQ(TYPE, MEMBER))
-
 /*
  *  Get a stack frame combination of pc and ra from the most relevent spot.
  */
@@ -5092,11 +5110,22 @@ x86_64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
 			* ip and sp in the end of the function.
 			*/
 			if (bt->flags & BT_DUMPFILE_SEARCH) {
-				FREEBUF(ur_bitmap);
-				bt->need_free = FALSE;
 				*pcp = pcp_save;
 				*spp = spp_save;
-				return x86_64_get_dumpfile_stack_frame(bt, pcp, spp);
+				/*
+				* pcp/spp_save is read from elf notes, for panic
+				* task, we'll continue to use the original elf
+				* notes to get regs; for other active tasks,
+				* we'll update the sp/ip into our own ur_bitmap.
+				*/
+				x86_64_get_dumpfile_stack_frame(bt, pcp, spp);
+				if (tt->panic_task == bt->task) {
+					FREEBUF(ur_bitmap);
+					bt->need_free = FALSE;
+					return;
+				} else {
+					sp = *spp;
+				}
 			}
 		}
 	} else {
@@ -5106,11 +5135,16 @@ x86_64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
 			SET_REG_BITMAP(ur_bitmap->bitmap, x86_64_user_regs_struct, bp);
 		} else {
 			if (bt->flags & BT_DUMPFILE_SEARCH) {
-				FREEBUF(ur_bitmap);
-				bt->need_free = FALSE;
 				*pcp = pcp_save;
 				*spp = spp_save;
-				return x86_64_get_dumpfile_stack_frame(bt, pcp, spp);
+				x86_64_get_dumpfile_stack_frame(bt, pcp, spp);
+				if (tt->panic_task == bt->task) {
+					FREEBUF(ur_bitmap);
+					bt->need_free = FALSE;
+					return;
+				} else {
+					sp = *spp;
+				}
 			}
 		}
 	}
@@ -9256,6 +9290,12 @@ x86_64_get_current_task_reg(int regno, const char *name,
 	if (!tc)
 		return FALSE;
 
+	/* Non zero stack ID, use extra stacks regs */
+	if (sid && sid <= extra_stacks_idx) {
+		ur_bitmap = extra_stacks_regs[sid - 1];
+		goto get_sub;
+	}
+
 	/*
 	* Task is active, grab CPU's registers
 	*/
@@ -9280,6 +9320,7 @@ x86_64_get_current_task_reg(int regno, const char *name,
 	}
 
 	/* Get subset registers from stack frame*/
+get_sub:
 	switch (regno) {
 		CHECK_REG_CASE(RAX,   ax);
 		CHECK_REG_CASE(RBX,   bx);
@@ -9341,7 +9382,7 @@ get_all:
 		COPY_REG_CASE(ORIG_RAX, orig_ax);
 	}
 
-	if (bt_info.need_free) {
+	if (!sid && bt_info.need_free) {
 		FREEBUF(ur_bitmap);
 		bt_info.need_free = FALSE;
 	}
-- 
2.47.0
--
Crash-utility mailing list -- devel@xxxxxxxxxxxxxxxxxxxxxxxxxxx
To unsubscribe send an email to devel-leave@xxxxxxxxxxxxxxxxxxxxxxxxxxx
https://${domain_name}/admin/lists/devel.lists.crash-utility.osci.io/
Contribution Guidelines: https://github.com/crash-utility/crash/wiki




[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux