[PATCH] Read in .debug_frame section of vmlinux

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

 



Hi Dave and all,

The attached patch read the .debug_frame section of vmlinux into
crash. By doing this, we could backtrace kernel stack frame using
dwarf unwind information contained in that section.

ChangeLog:
- Modified section_header_info() function to initialize the offset
  and size of .debug_frame section.
- Modified init_unwind_table() function to read in .debug_frame.
- Modified the prototype of unwind(), adding a int argument to
  indicate whether .eh_frame or .debug_frame is used. Also there're
  a few changes due to the difference between these two sections.

Well, it's the first time I came to crash utility, and I hope that
I didn't do anything wrong.

Thanks,
Wang Chao
The following patch read the .debug_frame section of vmlinux into
crash. By doing this, we could backtrace kernel stack frame using
dwarf unwind information contained in that section.

ChangeLog:
- Modified section_header_info() function to initialize the offset
  and size of .debug_frame section.
- Modified init_unwind_table() function to read in .debug_frame.
- Modified the prototype of unwind(), adding a int argument to
  indicate whether .eh_frame or .debug_frame is used. Also there're
  a few changes due to the difference between these two sections.

Signed-off-by: Wang Chao <wang.chao@xxxxxxxxxxxxxx>
---
 defs.h             |    2 ++
 symbols.c          |    8 ++++++++
 unwind_x86_32_64.c |   43 ++++++++++++++++++++++++++++---------------
 unwind_x86_64.h    |    2 +-
 4 files changed, 39 insertions(+), 16 deletions(-)

diff --git a/defs.h b/defs.h
index dcece4a..ec85279 100755
--- a/defs.h
+++ b/defs.h
@@ -1977,6 +1977,8 @@ struct symbol_table_data {
 	struct load_module *load_modules;
 	off_t dwarf_eh_frame_file_offset;
 	ulong dwarf_eh_frame_size;
+	off_t dwarf_debug_frame_file_offset;
+	ulong dwarf_debug_frame_size;
 	ulong first_ksymbol;
 	ulong __per_cpu_start;
 	ulong __per_cpu_end;
diff --git a/symbols.c b/symbols.c
index ec9c893..78fca5a 100755
--- a/symbols.c
+++ b/symbols.c
@@ -8271,6 +8271,10 @@ section_header_info(bfd *bfd, asection *section, void *reqptr)
 			st->dwarf_eh_frame_file_offset = (off_t)section->filepos;
 			st->dwarf_eh_frame_size = (ulong)bfd_section_size(bfd, section);
 		}
+                if (STREQ(bfd_get_section_name(bfd, section), ".debug_frame")) {
+			st->dwarf_debug_frame_file_offset = (off_t)section->filepos;
+			st->dwarf_debug_frame_size = (ulong)bfd_section_size(bfd, section);
+		}
 		break;
 
 	case (ulong)MODULE_SECTIONS:
@@ -8291,6 +8295,10 @@ section_header_info(bfd *bfd, asection *section, void *reqptr)
 			st->dwarf_eh_frame_file_offset = (off_t)section->filepos;
 			st->dwarf_eh_frame_size = (ulong)bfd_section_size(bfd, section);
 		}
+                if (STREQ(bfd_get_section_name(bfd, section), ".debug_frame")) {
+			st->dwarf_debug_frame_file_offset = (off_t)section->filepos;
+			st->dwarf_debug_frame_size = (ulong)bfd_section_size(bfd, section);
+		}
 		break;
 
 	default:
diff --git a/unwind_x86_32_64.c b/unwind_x86_32_64.c
index 13d86a9..754890e 100644
--- a/unwind_x86_32_64.c
+++ b/unwind_x86_32_64.c
@@ -496,7 +496,7 @@ static int processCFI(const u8 *start,
 /* Unwind to previous to frame.  Returns 0 if successful, negative
  * number in case of an error. */
 int 
-unwind(struct unwind_frame_info *frame)
+unwind(struct unwind_frame_info *frame, int is_ehframe)
 {
 #define FRAME_REG(r, t) (((t *)frame)[reg_info[r].offs])
 	const u32 *fde = NULL, *cie = NULL;
@@ -527,17 +527,22 @@ unwind(struct unwind_frame_info *frame)
 		     fde += 1 + *fde / sizeof(*fde)) {
 			if (!*fde || (*fde & (sizeof(*fde) - 1)))
 				break;
-			if (!fde[1])
+			if (is_ehframe && !fde[1])
+				continue; /* this is a CIE */
+			else if (fde[1] == 0xffffffff)
 				continue; /* this is a CIE */
 			if ((fde[1] & (sizeof(*fde) - 1))
 			    || fde[1] > (unsigned long)(fde + 1)
 			                - (unsigned long)unwind_table)
 				continue; /* this is not a valid FDE */
-			cie = fde + 1 - fde[1] / sizeof(*fde);
+			if (is_ehframe)
+				cie = fde + 1 - fde[1] / sizeof(*fde);
+			else
+				cie = unwind_table + fde[1];
 			if (*cie <= sizeof(*cie) + 4
 			    || *cie >= fde[1] - sizeof(*fde)
 			    || (*cie & (sizeof(*cie) - 1))
-			    || cie[1]
+			    || (cie[1] != 0xffffffff && cie[1])
 			    || (ptrType = fde_pointer_type(cie)) < 0) {
 				cie = NULL; /* this is not a (valid) CIE */
 				continue;
@@ -783,10 +788,13 @@ init_unwind_table(void)
 
 try_eh_frame:
 
-	if (st->dwarf_eh_frame_size) {
+	if (st->dwarf_eh_frame_size || st->dwarf_debug_frame_size) {
 		int fd;
+		int is_ehframe = (!st->dwarf_debug_frame_size &&
+				   st->dwarf_eh_frame_size);
 
-		unwind_table_size = st->dwarf_eh_frame_size;
+		unwind_table_size = is_ehframe ? st->dwarf_eh_frame_size :
+						 st->dwarf_debug_frame_size;
 
 		if (!(unwind_table = malloc(unwind_table_size))) {
 			error(WARNING, "cannot malloc unwind table space\n");
@@ -794,18 +802,21 @@ try_eh_frame:
 		}
 
 		if ((fd = open(pc->namelist, O_RDONLY)) < 0) {
-			error(WARNING, "cannot open %s for .eh_frame data\n",
-				pc->namelist);
+			error(WARNING, "cannot open %s for %s data\n",
+				pc->namelist, is_ehframe ? ".eh_frame" : ".debug_frame");
 			free(unwind_table);
 			return;
 		}
 
-		lseek(fd, st->dwarf_eh_frame_file_offset, SEEK_SET);
+		if (is_ehframe)
+			lseek(fd, st->dwarf_eh_frame_file_offset, SEEK_SET);
+		else
+			lseek(fd, st->dwarf_debug_frame_file_offset, SEEK_SET);
 
-		if (read(fd, unwind_table, st->dwarf_eh_frame_size) !=
-		    st->dwarf_eh_frame_size) {
-			error(WARNING, "cannot read .eh_frame data from %s\n",
-				pc->namelist);
+		if (read(fd, unwind_table, unwind_table_size) !=
+		    unwind_table_size) {
+			error(WARNING, "cannot read %s data from %s\n",
+			      is_ehframe ? ".eh_frame" : ".debug_frame", pc->namelist);
 			free(unwind_table);
 			return;
 		}
@@ -1054,6 +1065,7 @@ dwarf_backtrace(struct bt_info *bt, int level, ulong stacktop)
 	struct syment *sp;
 	char *name;
 	struct unwind_frame_info *frame;
+	int is_ehframe = (!st->dwarf_debug_frame_size && st->dwarf_eh_frame_size);
 
 	frame = (struct unwind_frame_info *)GETBUF(sizeof(struct unwind_frame_info));
 //	frame->regs.rsp = bt->stkptr;
@@ -1102,7 +1114,7 @@ dwarf_backtrace(struct bt_info *bt, int level, ulong stacktop)
 			UNW_PC(frame), frame->regs.rbp);
 
        	while ((UNW_SP(frame) < stacktop)
-				&& !unwind(frame) && UNW_PC(frame)) {
+				&& !unwind(frame, is_ehframe) && UNW_PC(frame)) {
 		/* To prevent rip pushed on IRQ stack being reported both
 		 * both on the IRQ and process stacks
 		 */
@@ -1193,6 +1205,7 @@ dwarf_debug(struct bt_info *bt)
 {
 	struct unwind_frame_info *frame;
 	ulong bp;
+	int is_ehframe = (!st->dwarf_debug_frame_size && st->dwarf_eh_frame_size);
 
 	if (!bt->hp->eip) {
 		dump_local_unwind_tables();
@@ -1220,7 +1233,7 @@ dwarf_debug(struct bt_info *bt)
  		sizeof(unsigned long), "reading bp", FAULT_ON_ERROR);
         frame->regs.rbp = bp;  /* fixme for x86 */
 
-	unwind(frame);
+	unwind(frame, is_ehframe);
 
 	fprintf(fp, "frame size: %lx (%lx)\n", 
 		(ulong)UNW_SP(frame), (ulong)UNW_SP(frame) - bt->hp->esp);
diff --git a/unwind_x86_64.h b/unwind_x86_64.h
index 52fcf7a..d3fae15 100644
--- a/unwind_x86_64.h
+++ b/unwind_x86_64.h
@@ -54,7 +54,7 @@ struct unwind_frame_info
         struct pt_regs regs;
 };
 
-extern int unwind(struct unwind_frame_info *);
+extern int unwind(struct unwind_frame_info *, int);
 extern void init_unwind_table(void);
 extern void free_unwind_table(void);

--
Crash-utility mailing list
Crash-utility@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/crash-utility

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

 

Powered by Linux