From 2e3d3f20d3b5ec6c17ceaeaa9c868f9d8794db4a Mon Sep 17 00:00:00 2001
From: Dave Anderson <anderson@redhat.com>
Date: Fri, 14 Aug 2015 10:19:56 -0400
Subject: [PATCH] Fix for the "dis" command on architectures with
 variable-length instructions.  Without the patch, "dis [-f] <function>" may
 continue beyond the end of a function, disassembling the memory that is in
 between the target function and the next function. (anderson@redhat.com)

---
 defs.h          |    2 ++
 gdb-7.6.patch   |   15 +++++++++++++++
 gdb_interface.c |    7 +++++--
 kernel.c        |    7 ++++++-
 symbols.c       |   31 +++++++++++++++++++++++++++++++
 5 files changed, 59 insertions(+), 3 deletions(-)

Index: crash-7.0.5/defs.h
===================================================================
--- crash-7.0.5.orig/defs.h
+++ crash-7.0.5/defs.h
@@ -3948,6 +3948,7 @@ struct gnu_request {
 #define GNU_GET_SYMBOL_TYPE      (15)
 #define GNU_USER_PRINT_OPTION 	 (16)
 #define GNU_SET_CRASH_BLOCK      (17)
+#define GNU_GET_FUNCTION_RANGE   (18)
 #define GNU_DEBUG_COMMAND       (100)
 /*
  *  GNU flags
@@ -4369,6 +4370,7 @@ int is_kernel_data(ulong);
 int is_init_data(ulong value); 
 int is_kernel_text_offset(ulong);
 int is_rodata(ulong, struct syment **);
+int get_text_function_range(ulong, ulong *, ulong *);
 void datatype_init(void);
 struct syment *symbol_search(char *);
 struct syment *value_search(ulong, ulong *);
Index: crash-7.0.5/gdb-7.6.patch
===================================================================
--- crash-7.0.5.orig/gdb-7.6.patch
+++ crash-7.0.5/gdb-7.6.patch
@@ -1571,3 +1571,18 @@
    if (build_address_symbolic (gdbarch, addr, do_demangle, &name, &offset,
  			      &filename, &line, &unmapped))
      {
+--- gdb-7.6/gdb/symtab.c.orig
++++ gdb-7.6/gdb/symtab.c
+@@ -5236,6 +5236,12 @@ gdb_command_funnel(struct gnu_request *r
+ 		gdb_set_crash_block(req);
+ 		break;
+ 
++	case GNU_GET_FUNCTION_RANGE:
++		sym = lookup_symbol(req->name, 0, VAR_DOMAIN, 0);
++		if (!find_pc_partial_function(req->pc, NULL, &req->addr, &req->addr2))
++			req->flags |= GNU_COMMAND_FAILED;
++		break;
++
+ 	default:
+ 		req->flags |= GNU_COMMAND_FAILED;
+ 		break;
Index: crash-7.0.5/gdb_interface.c
===================================================================
--- crash-7.0.5.orig/gdb_interface.c
+++ crash-7.0.5/gdb_interface.c
@@ -1,8 +1,8 @@
 /* gdb_interface.c - core analysis suite
  *
  * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
- * Copyright (C) 2002-2013 David Anderson
- * Copyright (C) 2002-2013 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2002-2015 David Anderson
+ * Copyright (C) 2002-2015 Red Hat, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -592,6 +592,9 @@ gdb_command_string(int cmd, char *buf, i
         case GNU_SET_CRASH_BLOCK:
                 sprintf(buf, "GNU_SET_CRASH_BLOCK");
 		break;
+	case GNU_GET_FUNCTION_RANGE:
+                sprintf(buf, "GNU_GET_FUNCTION_RANGE");
+                break;
 	case 0:
 		buf[0] = NULLCHAR;
 		break;
Index: crash-7.0.5/kernel.c
===================================================================
--- crash-7.0.5.orig/kernel.c
+++ crash-7.0.5/kernel.c
@@ -1339,6 +1339,7 @@ cmd_dis(void)
 	ulong target;
 	ulong count;
 	ulong offset;
+	ulong low, high;
 	struct syment *sp;
 	struct gnu_request *req;
 	char *savename; 
@@ -1495,8 +1496,12 @@ cmd_dis(void)
 		req->command = GNU_RESOLVE_TEXT_ADDR;
 		gdb_interface(req);
 		req->flags &= ~GNU_COMMAND_FAILED;
+
 		if (reverse || forward || req->flags & GNU_FUNCTION_ONLY) {
-			if (sp) {
+			if (get_text_function_range(sp ? sp->value : req->addr,
+			    &low, &high))
+				req->addr2 = high;
+			else if (sp) {
 				savename = sp->name;
 				if ((sp = next_symbol(NULL, sp)))
 					req->addr2 = sp->value;
Index: crash-7.0.5/symbols.c
===================================================================
--- crash-7.0.5.orig/symbols.c
+++ crash-7.0.5/symbols.c
@@ -2653,6 +2653,37 @@ is_rodata(ulong value, struct syment **s
 }
 
 /*
+ *  For a given kernel virtual address, request that gdb return 
+ *  the address range of the containing function.  For module 
+ *  text addresses, its debuginfo data must be loaded.
+ */
+int
+get_text_function_range(ulong vaddr, ulong *low, ulong *high)
+{
+	struct syment *sp;
+	struct gnu_request gnu_request, *req = &gnu_request;
+
+	if (!(sp = value_search(vaddr, NULL)))
+		return FALSE;
+
+	BZERO(req, sizeof(struct gnu_request));
+	req->command = GNU_GET_FUNCTION_RANGE;
+	req->pc = sp->value;
+	req->name = sp->name;
+	gdb_interface(req);
+	if (req->flags & GNU_COMMAND_FAILED)
+		return FALSE;
+
+	if ((vaddr < req->addr) || (vaddr >= req->addr2))
+		return FALSE;
+
+	*low = req->addr;
+	*high = req->addr2;
+
+	return TRUE;
+}
+
+/*
  *  "help -s" output
  */
 void
