From 4935c333a6cd1e7a8949eda53319b8550640cfc0 Mon Sep 17 00:00:00 2001
From: Dave Anderson <anderson@redhat.com>
Date: Wed, 12 Aug 2015 13:49:15 -0400
Subject: [PATCH] Introduction of the "dis -f <address>" option, which
 disassembles from the target address until the end of the function.
 (atomlin@redhat.com)

---
 help.c   |   39 ++++++--
 kernel.c |  301 ++++++++++++++++++++++++---------------------------------------
 2 files changed, 145 insertions(+), 195 deletions(-)

Index: crash-7.0.5/help.c
===================================================================
--- crash-7.0.5.orig/help.c
+++ crash-7.0.5/help.c
@@ -5869,11 +5869,13 @@ NULL
 char *help_dis[] = {
 "dis",
 "disassemble",
-"[-rludx][-b [num]] [address | symbol | (expression)] [count]",
+"[-rfludx][-b [num]] [address | symbol | (expression)] [count]",
 "  This command disassembles source code instructions starting (or ending) at",
 "  a text address that may be expressed by value, symbol or expression:\n",
 "            -r  (reverse) displays all instructions from the start of the ",
 "                routine up to and including the designated address.",
+"            -f  (forward) displays all instructions from the given address ",
+"                to the end of the routine.",
 "            -l  displays source code line number data in addition to the ",
 "                disassembly output.", 
 "            -u  address is a user virtual address in the current context;",
@@ -5986,15 +5988,32 @@ char *help_dis[] = {
 "  Override the current decimal output radix format:\n",
 "    %s> dis sys_read 10 -x",
 "    0xffffffff8001178f <sys_read>:  push   %r13",
-"    0xffffffff80011791 <sys_read+0x2>:      mov    %rsi,%r13",
-"    0xffffffff80011794 <sys_read+0x5>:      push   %r12",
-"    0xffffffff80011796 <sys_read+0x7>:      mov    $0xfffffffffffffff7,%r12",
-"    0xffffffff8001179d <sys_read+0xe>:      push   %rbp",
-"    0xffffffff8001179e <sys_read+0xf>:      mov    %rdx,%rbp",
-"    0xffffffff800117a1 <sys_read+0x12>:     push   %rbx",
-"    0xffffffff800117a2 <sys_read+0x13>:     sub    $0x18,%rsp",
-"    0xffffffff800117a6 <sys_read+0x17>:     lea    0x14(%rsp),%rsi",
-"    0xffffffff800117ab <sys_read+0x1c>:     callq  0xffffffff8000b5b4 <fget_light>",
+"    0xffffffff80011791 <sys_read+0x2>:    mov    %rsi,%r13",
+"    0xffffffff80011794 <sys_read+0x5>:    push   %r12",
+"    0xffffffff80011796 <sys_read+0x7>:    mov    $0xfffffffffffffff7,%r12",
+"    0xffffffff8001179d <sys_read+0xe>:    push   %rbp",
+"    0xffffffff8001179e <sys_read+0xf>:    mov    %rdx,%rbp",
+"    0xffffffff800117a1 <sys_read+0x12>:   push   %rbx",
+"    0xffffffff800117a2 <sys_read+0x13>:   sub    $0x18,%rsp",
+"    0xffffffff800117a6 <sys_read+0x17>:   lea    0x14(%rsp),%rsi",
+"    0xffffffff800117ab <sys_read+0x1c>:   callq  0xffffffff8000b5b4 <fget_light>",
+" ",
+"  Disassemble from vfs_read+320 until the end of the function:\n",
+"    %s> dis -f vfs_read+320",
+"    0xffffffff8119d4e0 <vfs_read+320>:  cmpq   $0x0,0x20(%rax)",
+"    0xffffffff8119d4e5 <vfs_read+325>:  jne    0xffffffff8119d3e8 <vfs_read+72>",
+"    0xffffffff8119d4eb <vfs_read+331>:  mov    $0xffffffffffffffea,%r12",
+"    0xffffffff8119d4f2 <vfs_read+338>:  jmp    0xffffffff8119d4c3 <vfs_read+291>",
+"    0xffffffff8119d4f4 <vfs_read+340>:  nopl   0x0(%rax)",
+"    0xffffffff8119d4f8 <vfs_read+344>:  callq  0xffffffff8119cc40 <do_sync_read>",
+"    0xffffffff8119d4fd <vfs_read+349>:  mov    %rax,%r12",
+"    0xffffffff8119d500 <vfs_read+352>:  jmpq   0xffffffff8119d44c <vfs_read+172>",
+"    0xffffffff8119d505 <vfs_read+357>:  nopl   (%rax)",
+"    0xffffffff8119d508 <vfs_read+360>:  mov    $0xfffffffffffffff7,%r12",
+"    0xffffffff8119d50f <vfs_read+367>:  jmp    0xffffffff8119d4c3 <vfs_read+291>",
+"    0xffffffff8119d511 <vfs_read+369>:  mov    $0xfffffffffffffff2,%r12",
+"    0xffffffff8119d518 <vfs_read+376>:  jmp    0xffffffff8119d4c3 <vfs_read+291>",
+"    0xffffffff8119d51a <vfs_read+378>:  nopw   0x0(%rax,%rax,1)",
 NULL               
 };
 
Index: crash-7.0.5/kernel.c
===================================================================
--- crash-7.0.5.orig/kernel.c
+++ crash-7.0.5/kernel.c
@@ -1332,11 +1332,11 @@ void
 cmd_dis(void)
 {
 	int c;
-	int do_load_module_filter, do_machdep_filter, reverse; 
+	int do_load_module_filter, do_machdep_filter, reverse, forward;
 	int unfiltered, user_mode, count_entered, bug_bytes_entered;
 	unsigned int radix;
 	ulong curaddr;
-	ulong revtarget;
+	ulong target;
 	ulong count;
 	ulong offset;
 	struct syment *sp;
@@ -1358,17 +1358,18 @@ cmd_dis(void)
 		return;
 	}
 
-	reverse = count_entered = bug_bytes_entered = FALSE;
+	reverse = forward = count_entered = bug_bytes_entered = FALSE;
 	sp = NULL;
 	unfiltered = user_mode = do_machdep_filter = do_load_module_filter = 0;
 	radix = 0;
+	target = 0;
 
 	req = (struct gnu_request *)getbuf(sizeof(struct gnu_request));
 	req->buf = GETBUF(BUFSIZE);
 	req->flags |= GNU_FROM_TTY_OFF|GNU_RETURN_ON_ERROR;
 	req->count = 1;
 
-        while ((c = getopt(argcnt, args, "dxhulrUb:B:")) != EOF) {
+        while ((c = getopt(argcnt, args, "dxhulrfUb:B:")) != EOF) {
                 switch(c)
 		{
 		case 'd':
@@ -1395,9 +1396,19 @@ cmd_dis(void)
 			break;
 
 		case 'r':
+			if (forward)
+				error(FATAL, 
+					"-r and -f are mutually exclusive\n");
 			reverse = TRUE;
 			break;
 
+		case 'f':
+			if (reverse)
+				error(FATAL, 
+					"-r and -f are mutually exclusive\n");
+			forward = TRUE;
+			break;
+
 		case 'l':
 			if (GDB_PATCHED())
 				error(INFO, "line numbers are not available\n");
@@ -1450,9 +1461,10 @@ cmd_dis(void)
                 }
 
                 if (args[++optind]) {
-			if (reverse) {
+			if (reverse || forward) {
 				error(INFO, 
-			            "count argument ignored with -r option\n");
+			            "count argument ignored with -%s option\n",
+				    	reverse ? "r" : "f");
 			} else {
                         	req->count = stol(args[optind], 
 					FAULT_ON_ERROR, NULL);
@@ -1480,212 +1492,131 @@ cmd_dis(void)
 			return;
 		}
 
+		req->command = GNU_RESOLVE_TEXT_ADDR;
+		gdb_interface(req);
+		req->flags &= ~GNU_COMMAND_FAILED;
+		if (reverse || forward || req->flags & GNU_FUNCTION_ONLY) {
+			if (sp) {
+				savename = sp->name;
+				if ((sp = next_symbol(NULL, sp)))
+					req->addr2 = sp->value;
+				else
+					error(FATAL, 
+				"unable to determine symbol after %s\n",
+						savename);
+			} else {
+				if ((sp = value_search(req->addr, NULL))
+				     && (sp = next_symbol(NULL, sp)))
+					req->addr2 = sp->value;	
+				else 
+					error(FATAL, dis_err, req->addr);
+			}
+		}
+
+		if (reverse || forward) {
+			target = req->addr;
+			if ((sp = value_search(target, NULL)) == NULL)
+				error(FATAL, "cannot resolve address: %lx\n", target);
+
+			req->addr = sp->value;
+		} else
+			count = 0;
 		do_load_module_filter = module_symbol(req->addr, NULL, NULL, 
 			NULL, *gdb_output_radix);
 
-		if (!reverse) {
-			req->command = GNU_RESOLVE_TEXT_ADDR;
-			gdb_interface(req);
-                        if ((req->flags & GNU_COMMAND_FAILED) ||
-			    do_load_module_filter ||
-			    (req->flags & GNU_FUNCTION_ONLY)) {
-				req->flags &= ~GNU_COMMAND_FAILED;
-				if (sp) {
-					savename = sp->name;
-                                        if ((sp = next_symbol(NULL, sp)))
-                                                req->addr2 = sp->value;
-					else
-                                		error(FATAL, 
-				        "unable to determine symbol after %s\n",
-                                        		savename);
-				} else {
-					if ((sp = value_search(req->addr, NULL))
-                                             && (sp = next_symbol(NULL, sp)))
-						req->addr2 = sp->value;	
-					else 
-						error(FATAL, dis_err, req->addr);
-				}
-                        }
+		do_machdep_filter = machdep->dis_filter(req->addr, NULL, radix);
+		open_tmpfile();
 
-			do_machdep_filter = machdep->dis_filter(req->addr, NULL, radix);
-			count = 0;
-			open_tmpfile();
-#ifdef OLDWAY
-			req->command = GNU_DISASSEMBLE;
-			req->fp = pc->tmpfile;
-			gdb_interface(req);
-#else
-			sprintf(buf1, "x/%ldi 0x%lx",
-                                count_entered && req->count ? req->count : 
-				req->flags & GNU_FUNCTION_ONLY ? 
+		if (reverse)
+			sprintf(buf5, "x/%ldi 0x%lx",
+				(target - req->addr) ? target - req->addr : 1, 
+				req->addr);
+		else
+			sprintf(buf5, "x/%ldi 0x%lx",
+				count_entered && req->count ? req->count : 
+				forward || req->flags & GNU_FUNCTION_ONLY ? 
 				req->addr2 - req->addr : 1, 
 				req->addr);
-        		gdb_pass_through(buf1, NULL, GNU_RETURN_ON_ERROR);
-#endif
-			if (req->flags & GNU_COMMAND_FAILED) {
-				close_tmpfile();
-				error(FATAL, dis_err, req->addr);
-			}
+		gdb_pass_through(buf5, NULL, GNU_RETURN_ON_ERROR);
 
-        		rewind(pc->tmpfile);
-        		while (fgets(buf2, BUFSIZE, pc->tmpfile)) {
-				if (STRNEQ(buf2, "Dump of") ||
-				    STRNEQ(buf2, "End of"))
-					continue;
+		if (req->flags & GNU_COMMAND_FAILED) {
+			close_tmpfile();
+			error(FATAL, dis_err, req->addr);
+		}
+
+		rewind(pc->tmpfile);
+		while (fgets(buf2, BUFSIZE, pc->tmpfile)) {
+			if (STRNEQ(buf2, "Dump of") ||
+			    STRNEQ(buf2, "End of"))
+				continue;
+
+			strip_beginning_whitespace(buf2);
 
-				strip_beginning_whitespace(buf2);
+			if (do_load_module_filter)
+				load_module_filter(buf2, LM_DIS_FILTER);
 
-				if (do_load_module_filter)
-					load_module_filter(buf2, LM_DIS_FILTER);
+			if (STRNEQ(buf2, "0x"))
+				extract_hex(buf2, &curaddr, ':', TRUE);
 
-				if (STRNEQ(buf2, "0x")) 
-					extract_hex(buf2, &curaddr, ':', TRUE);
+			if (forward) {
+				if (curaddr != target)
+					continue;
+				else
+					forward = FALSE;
+			}
 
-				if ((req->flags & GNU_FUNCTION_ONLY) &&
+			if (!reverse)
+				if (!count_entered && req->addr2 &&
 				    (curaddr >= req->addr2))
 					break;
 
-				if (do_machdep_filter)
-					machdep->dis_filter(curaddr, buf2, radix);
-
-				if (req->flags & GNU_FUNCTION_ONLY) {
-                                        if (req->flags & 
-                                            GNU_PRINT_LINE_NUMBERS) {
-                                                get_line_number(curaddr, buf3,
-                                                        FALSE);
-                                                if (!STREQ(buf3, buf4)) {
-                                                        print_verbatim(
-                                                            pc->saved_fp, buf3);
-                                                        print_verbatim(
-                                                            pc->saved_fp, "\n");
-                                                        strcpy(buf4, buf3);
-                                                }
-                                        }
+			if (do_machdep_filter)
+				machdep->dis_filter(curaddr, buf2, radix);
 
-                			print_verbatim(pc->saved_fp, buf2); 
-					continue;
-				} else {
-					if (curaddr < req->addr) 
-						continue;
-
-                			if (req->flags & 
-					    GNU_PRINT_LINE_NUMBERS) {
-                        			get_line_number(curaddr, buf3, 
-							FALSE);
-                        			if (!STREQ(buf3, buf4)) {
-                                			print_verbatim(
-							    pc->saved_fp, buf3);
-                                			print_verbatim(
-						            pc->saved_fp, "\n");
-                                			strcpy(buf4, buf3);
-                        			}
-                			} 
-
-                			print_verbatim(pc->saved_fp, buf2);
-
-					if (LASTCHAR(clean_line(buf2)) 
-						!= ':') {
-						if (++count == req->count)
-							break;
-					}
+			if (req->flags & GNU_PRINT_LINE_NUMBERS) {
+				get_line_number(curaddr, buf3,
+					FALSE);
+				if (!STREQ(buf3, buf4)) {
+					print_verbatim(
+					    pc->saved_fp, buf3);
+					print_verbatim(
+					    pc->saved_fp, "\n");
+					strcpy(buf4, buf3);
 				}
-        		}
-			close_tmpfile();
-		}
-        }
-        else if (bug_bytes_entered)
-		return;
-	else cmd_usage(pc->curcmd, SYNOPSIS);
-
-	if (!reverse) {
-		FREEBUF(req->buf);
-		FREEBUF(req);
-		return;
-	}
-
-        revtarget = req->addr;
-        if ((sp = value_search(revtarget, NULL)) == NULL)
-                error(FATAL, "cannot resolve address: %lx\n", revtarget);
-
-        sprintf(buf1, "0x%lx", revtarget);
-
-        open_tmpfile();
-
-        req->addr = sp->value;
-        req->flags |= GNU_FUNCTION_ONLY;
-        req->command = GNU_RESOLVE_TEXT_ADDR;
-        gdb_interface(req);
-        req->flags &= ~GNU_COMMAND_FAILED;
-	savename = sp->name;
-        if ((sp = next_symbol(NULL, sp)))
-                req->addr2 = sp->value;
-        else {
-		close_tmpfile();
-                error(FATAL, "unable to determine symbol after %s\n", savename);
-	}
-
-	do_machdep_filter = machdep->dis_filter(req->addr, NULL, radix);
-#ifdef OLDWAY
-	req->command = GNU_DISASSEMBLE;
-	req->fp = pc->tmpfile;
-	gdb_interface(req);
-#else
-        sprintf(buf5, "x/%ldi 0x%lx",
-        	(revtarget - req->addr) ? revtarget - req->addr : 1, 
-		req->addr);
-        gdb_pass_through(buf5, NULL, GNU_RETURN_ON_ERROR);
-#endif
-        if (req->flags & GNU_COMMAND_FAILED) {
-		close_tmpfile();
-        	error(FATAL, dis_err, req->addr);
-	}
-
-        rewind(pc->tmpfile);
-        while (fgets(buf2, BUFSIZE, pc->tmpfile)) {
-                if (STRNEQ(buf2, "Dump of") || STRNEQ(buf2, "End of"))
-                	continue;
-
-		strip_beginning_whitespace(buf2);
-
-                if (do_load_module_filter)
-                        load_module_filter(buf2, LM_DIS_FILTER);
-
-                if (STRNEQ(buf2, "0x"))
-                	extract_hex(buf2, &curaddr, ':', TRUE);
-
-		if (do_machdep_filter)
-			machdep->dis_filter(curaddr, buf2, radix);
-
-		if (req->flags & GNU_PRINT_LINE_NUMBERS) {
-			get_line_number(curaddr, buf3, FALSE);
-			if (!STREQ(buf3, buf4)) {
-				print_verbatim(pc->saved_fp, buf3);
-				print_verbatim(pc->saved_fp, "\n");
-				strcpy(buf4, buf3);
 			}
-		}
 
-                print_verbatim(pc->saved_fp, buf2);
-                if (STRNEQ(buf2, buf1)) {
-                	if (LASTCHAR(clean_line(buf2)) != ':') 
-                        	break;
+			print_verbatim(pc->saved_fp, buf2); 
+			if (reverse) {
+				if (curaddr == target) {
+					if (LASTCHAR(clean_line(buf2)) != ':') 
+						break;
 
-        		ret = fgets(buf2, BUFSIZE, pc->tmpfile);
+					ret = fgets(buf2, BUFSIZE, pc->tmpfile);
 
-                	if (do_load_module_filter)
-                        	load_module_filter(buf2, LM_DIS_FILTER);
+					if (do_load_module_filter)
+						load_module_filter(buf2, LM_DIS_FILTER);
 
-			if (do_machdep_filter) 
-				machdep->dis_filter(curaddr, buf2, radix);
+					if (do_machdep_filter) 
+						machdep->dis_filter(curaddr, buf2, radix);
 
-                	print_verbatim(pc->saved_fp, buf2);
-			break;
+					print_verbatim(pc->saved_fp, buf2);
+					break;
+				}
+			}
+
+			if (count_entered && LASTCHAR(clean_line(buf2)) != ':')
+				if (++count == req->count)
+					break;
 		}
+		close_tmpfile();
         }
+        else if (bug_bytes_entered)
+		return;
+	else cmd_usage(pc->curcmd, SYNOPSIS);
 
-        close_tmpfile();
 	FREEBUF(req->buf);
 	FREEBUF(req);
+	return;
 }
 
 /*
