[PATCH v2 09/14] Estimate phys_base based on linux_banner position

HATAYAMA Daisuke
2011-10-28T09:48:57Z

sadump doesn't save phys_base, so we must estimate it in any way. Here
we borrow the method in crash utility that we search a certain range
of addresses for linux_banner symbol value.

Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
---

makedumpfile.c | 12 ++++++++++++
sadump_info.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
sadump_info.h | 13 +++++++++++++
3 files changed, 72 insertions(+), 0 deletions(-)

diff --git a/makedumpfile.c b/makedumpfile.c
index 205d3de..6e9dd83 100644
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -2504,6 +2504,15 @@ initial(void)

(void) sadump_set_timestamp(&info->timestamp);

+ /*
+ * NOTE: phys_base is never saved by sadump and so
+ * must be computed in some way. We here choose the
+ * way of looking at linux_banner. See
+ * sadump_virt_phys_base(). The processing is
+ * postponed until debug information becomes
+ * available.
+ */
+
} else if (!get_phys_base())
return FALSE;

@@ -2579,6 +2588,9 @@ out:
return FALSE;

if (debug_info) {
+ if (info->flag_sadump)
+ (void) sadump_virt_phys_base();
+
if (!get_machdep_info())
return FALSE;

diff --git a/sadump_info.c b/sadump_info.c
index abc81d9..adca47b 100644
--- a/sadump_info.c
+++ b/sadump_info.c
@@ -22,6 +22,12 @@
#include "print_info.h"
#include "sadump_mod.h"

+#ifdef __x86_64__
+
+#define MEGABYTES(x) ((x) * (1048576))
+
+#endif
+
struct sadump_diskset_info {
char *name_memory;
int fd_memory;
@@ -666,6 +672,47 @@ sadump_get_max_mapnr(void)
return si->sh_memory->max_mapnr;
}

+#ifdef __x86_64__
+
+int
+sadump_virt_phys_base(void)
+{
+ char buf[BUFSIZE];
+ unsigned long phys, linux_banner_phys;
+
+ if (SYMBOL(linux_banner) == NOT_FOUND_SYMBOL) {
+ DEBUG_MSG("sadump: symbol linux_banner is not found\n");
+ goto failed;
+ }
+
+ linux_banner_phys = SYMBOL(linux_banner) - __START_KERNEL_map;
+
+ if (readmem(PADDR, linux_banner_phys + info->phys_base, buf,
+ strlen("Linux version")) && STRNEQ(buf, "Linux version"))
+ return TRUE;
+
+ for (phys = (-MEGABYTES(16)); phys != MEGABYTES(16+1);
+ phys += MEGABYTES(1)) {
+ if (readmem(PADDR, linux_banner_phys + phys, buf,
+ strlen("Linux version")) &&
+ STRNEQ(buf, "Linux version")) {
+ DEBUG_MSG("sadump: phys_base: %lx %s\n", phys,
+ info->phys_base != phys ? "override" : "");
+ info->phys_base = phys;
+ return TRUE;
+ }
+ }
+
+failed:
+ info->phys_base = 0;
+
+ DEBUG_MSG("sadump: failed to calculate phys_base; default to 0\n");
+
+ return FALSE;
+}
+
+#endif /* __x86_64__ */
+
int
readpmem_sadump(unsigned long long paddr, void *bufptr, size_t size)
{
diff --git a/sadump_info.h b/sadump_info.h
index b6b9cdd..401b769 100644
--- a/sadump_info.h
+++ b/sadump_info.h
@@ -22,6 +22,19 @@

#include "makedumpfile.h"

+#ifdef __x86_64__
+
+int sadump_virt_phys_base(void);
+
+#else
+
+static inline int sadump_virt_phys_base(void)
+{
+ return TRUE;
+}
+
+#endif
+
#if defined(__x86__) || defined(__x86_64__)

int check_and_get_sadump_header_info(char *filename);