lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Wed, 20 Jan 2016 11:15:50 +0000
From:	Kieran Bingham <kieran.bingham@...aro.org>
To:	jan.kiszka@...mens.com
Cc:	Kieran Bingham <kieran.bingham@...aro.org>,
	linux-kernel@...r.kernel.org, maxime.coquelin@...com,
	peter.griffin@...aro.org, lee.jones@...aro.org
Subject: [PATCH 5/5] scripts/gdb: Add meminfo command

Provide an equivalent of /proc/meminfo which should be available from
core dumps, or crashed kernels. This should allow a debugger to identify
if memory pressures were applicable in the instance of their issue

Signed-off-by: Kieran Bingham <kieran.bingham@...aro.org>
---

This command has proved to be much more difficult that I first thought it
would be!

It also poses a couple of interesting issues, which is why I submit this
patch in a much more unfinished form.

The meminfo implementation at fs/proc/meminfo.c makes several function calls
to collate information, which makes duplicating here more difficult.

I suspect the best option here is to not present lines of which we can not
obtain accurate data for, (much better than presenting inaccurate information)

Would this go in agreement with you?

Finally, do you have any ideas on the best way to manage code which
is #ifdef'd on kernel config options? (#ifdef CONFIG_HIGHMEM for example).

In a similar vein to the constants.py, I considered that we could iterate all
of the kernel configuration options and store them in a dictionary some how.

That may be awkward, however, and I wondered what ideas anyone had!


 scripts/gdb/linux/constants.py.in |  22 +++++
 scripts/gdb/linux/proc.py         | 173 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 195 insertions(+)

diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
index 739a15d2e984..306bd601ae4e 100644
--- a/scripts/gdb/linux/constants.py.in
+++ b/scripts/gdb/linux/constants.py.in
@@ -12,8 +12,15 @@
  *
  */
 
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/thread_info.h>
+
 #include <linux/fs.h>
+#include <linux/swap.h>
 #include <linux/mount.h>
+#include <linux/vmalloc.h>
+
 
 /* We need to stringify expanded macros so that they can be parsed */
 
@@ -41,3 +48,18 @@ LX_MNT_NOATIME = MNT_NOATIME
 LX_MNT_NODIRATIME = MNT_NODIRATIME
 LX_MNT_RELATIME = MNT_RELATIME
 
+/* asm/page.h */
+LX_PAGE_SHIFT = XSTRING(PAGE_SHIFT)
+lx_page_shift = gdb.parse_and_eval(LX_PAGE_SHIFT)
+
+/* asm/thread_info.h */
+LX_THREAD_SIZE = XSTRING(THREAD_SIZE)
+lx_thread_size = gdb.parse_and_eval(LX_THREAD_SIZE)
+
+/* linux/vmalloc.h */
+LX_VMALLOC_TOTAL = XSTRING(VMALLOC_TOTAL)
+lx_vmalloc_total = gdb.parse_and_eval(LX_VMALLOC_TOTAL)
+
+/* linux/swap.h */
+LX_MAX_SWAPFILES = XSTRING(MAX_SWAPFILES)
+lx_max_swapfiles = gdb.parse_and_eval(LX_MAX_SWAPFILES)
diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py
index b79ce2a33a3d..ac9e1aac2403 100644
--- a/scripts/gdb/linux/proc.py
+++ b/scripts/gdb/linux/proc.py
@@ -206,3 +206,176 @@ values of that process namespace"""
                         info_opts(MNT_INFO, m_flags)))
 
 LxMounts()
+
+
+bdev_type = utils.CachedType("struct block_device")
+
+
+class LxMeminfo(gdb.Command):
+    """ Identify the memory usage, statistics, and availability
+
+Equivalent to cat /proc/meminfo on a running target """
+
+    def __init__(self):
+        super(LxMeminfo, self).__init__("lx-meminfo", gdb.COMMAND_DATA)
+
+    def K(self, val):
+        # Convert from PAGES to KB
+        return int(val << (constants.lx_page_shift - 10))
+
+    def page_K(self, remote_value):
+        # Obtain page value, and Convert from PAGES to KB
+        val = int(gdb.parse_and_eval(remote_value))
+        return self.K(val)
+
+    def gps(self, enum_zone_stat_item):
+        # Access the Global Page State structure
+        # I would prefer to read this structure in one go and then index
+        # from the enum. But we can't determine the enum values with out
+        # a call to GDB anyway so we may as well take the easy route and
+        # get the value.
+        remote_value = "vm_stat[" + enum_zone_stat_item + "].counter"
+        return int(gdb.parse_and_eval(remote_value))
+
+    def gps_K(self, enum_zone_stat_item):
+        return self.K(self.gps(enum_zone_stat_item))
+
+    def nr_blockdev_pages(self):
+        bdevs_head = gdb.parse_and_eval("all_bdevs")
+        pages = 0
+        for bdev in lists.items(bdev_type, "bd_list", bdevs_head):
+            pages += bdev['bd_inode']['i_mapping']['nrpages']
+        return pages
+
+    def total_swapcache_pages(self):
+        pages = 0
+        for i in range(0, constants.lx_max_swapfiles):
+            swap_space = "swapper_spaces[" + str(i) + "].nrpages"
+            pages += int(gdb.parse_and_eval(swap_space))
+        return pages
+
+    def vm_commit_limit(self, totalram_pages):
+        overcommit = int(gdb.parse_and_eval("sysctl_overcommit_kbytes"))
+        overcommit_ratio = int(gdb.parse_and_eval("sysctl_overcommit_ratio"))
+        total_swap_pages = int(gdb.parse_and_eval("total_swap_pages"))
+        hugetlb_total_pages = 0  # hugetlb_total_pages()!!
+
+        if overcommit:
+            allowed = overcommit >> (constants.lx_page_shift - 10)
+        else:
+            allowed = ((totalram_pages - hugetlb_total_pages *
+                       overcommit_ratio / 100))
+
+        allowed += total_swap_pages
+        return allowed
+
+    # Main lx-meminfo command execution
+    def invoke(self, arg, from_tty):
+        totalram = int(gdb.parse_and_eval("totalram_pages"))
+        freeram = self.gps("NR_FREE_PAGES")
+        reclaimable = self.gps("NR_SLAB_RECLAIMABLE")
+        unreclaimable = self.gps("NR_SLAB_UNRECLAIMABLE")
+        slab = reclaimable + unreclaimable
+        # for_each_zone(zone)
+        #     wmark_low += zone->watermark[WMARK_LOW];
+        wmark_low = 0   # Zone parsing is unimplemented
+
+        available = freeram - wmark_low
+        available += reclaimable - min(reclaimable / 2, wmark_low)
+
+        bufferram = self.nr_blockdev_pages()
+        total_swapcache_pages = self.total_swapcache_pages()
+
+        file_pages = self.gps("NR_FILE_PAGES")
+        cached = file_pages - total_swapcache_pages - bufferram
+
+        # LRU Pages
+        active_pages_anon = self.gps("NR_ACTIVE_ANON")
+        inactive_pages_anon = self.gps("NR_INACTIVE_ANON")
+        active_pages_file = self.gps("NR_ACTIVE_FILE")
+        inactive_pages_file = self.gps("NR_INACTIVE_FILE")
+        unevictable_pages = self.gps("NR_UNEVICTABLE")
+        active_pages = active_pages_anon + active_pages_file
+        inactive_pages = inactive_pages_anon + inactive_pages_file
+
+        totalhigh = int(gdb.parse_and_eval("totalhigh_pages"))
+        # We can't run this on a core dump file ...
+        # if running target ()
+        freehigh = int(gdb.parse_and_eval("nr_free_highpages()"))
+        # else freehigh = 0
+
+        kernelstack = int(self.gps("NR_KERNEL_STACK") *
+                          constants.lx_thread_size / 1024)
+
+        commitlimit = self.vm_commit_limit(totalram)
+        committed_as = int(gdb.parse_and_eval("vm_committed_as.count"))
+
+        vmalloc_total = int(constants.lx_vmalloc_total >> 10)
+
+        gdb.write(
+            "MemTotal:       {:8d} kB\n".format(self.K(totalram)) +
+            "MemFree:        {:8d} kB\n".format(self.K(freeram)) +
+            "MemAvailable:   {:8d} kB\n".format(self.K(available)) +
+            "Buffers:        {:8d} kB\n".format(self.K(bufferram)) +
+            "Cached:         {:8d} kB\n".format(self.K(cached)) +
+            "SwapCached:     {:8d} kB\n".format(self.K(total_swapcache_pages)) +
+            "Active:         {:8d} kB\n".format(self.K(active_pages)) +
+            "Inactive:       {:8d} kB\n".format(self.K(inactive_pages)) +
+            "Active(anon):   {:8d} kB\n".format(self.K(active_pages_anon)) +
+            "Inactive(anon): {:8d} kB\n".format(self.K(inactive_pages_anon)) +
+            "Active(file):   {:8d} kB\n".format(self.K(active_pages_file)) +
+            "Inactive(file): {:8d} kB\n".format(self.K(inactive_pages_file)) +
+            "Unevictable:    {:8d} kB\n".format(self.K(unevictable_pages)) +
+            "Mlocked:        {:8d} kB\n".format(self.gps_K("NR_MLOCK"))
+            )
+        # ifdef CONFIG_HIGHMEM || core dump?
+        gdb.write(
+            "HighTotal:      {:8d} kB\n".format(self.K(totalhigh)) +
+            "HighFree:       {:8d} kB\n".format(self.K(freehigh)) +
+            "LowTotal:       {:8d} kB\n".format(self.K(totalram-totalhigh)) +
+            "LowFree:        {:8d} kB\n".format(self.K(freeram-freehigh))
+            )
+        # endif
+        # ifndef CONFIG_MMU
+        # gdb.write(
+        #    mmap_pages_allocated
+        #    )
+        # endif
+        gdb.write(
+            "SwapTotal:      {:8d} kB\n".format(self.K(0)) +
+            "SwapFree:       {:8d} kB\n".format(self.K(0)) +
+            "Dirty:          {:8d} kB\n".format(self.gps_K("NR_FILE_DIRTY")) +
+            "Writeback:      {:8d} kB\n".format(self.gps_K("NR_WRITEBACK")) +
+            "AnonPages:      {:8d} kB\n".format(self.gps_K("NR_ANON_PAGES")) +
+            "Mapped:         {:8d} kB\n".format(self.gps_K("NR_FILE_MAPPED")) +
+            "Shmem:          {:8d} kB\n".format(self.gps_K("NR_SHMEM")) +
+            "Slab:           {:8d} kB\n".format(self.K(slab)) +
+            "SReclaimable:   {:8d} kB\n".format(self.K(reclaimable)) +
+            "SUnreclaim:     {:8d} kB\n".format(self.K(unreclaimable)) +
+            "KernelStack:    {:8d} kB\n".format(kernelstack) +
+            "PageTables:     {:8d} kB\n".format(self.gps_K("NR_PAGETABLE"))
+            )
+
+        #  if CONFIG_QUICKLIST
+        #   "Quicklists:     {:8d} kB\n".format(self.K(quicklist)))
+
+        gdb.write(
+            "NFS_Unstable:   {:8d} kB\n".format(self.gps_K("NR_UNSTABLE_NFS")) +
+            "Bounce:         {:8d} kB\n".format(self.gps_K("NR_BOUNCE")) +
+            "WritebackTmp:   {:8d} kB\n".format(self.gps_K("NR_WRITEBACK_TEMP")) +
+            "CommitLimit:    {:8d} kB\n".format(self.K(commitlimit)) +
+            "Committed_AS:   {:8d} kB\n".format(self.K(committed_as)) +
+            "VmallocTotal:   {:8d} kB\n".format(vmalloc_total) +
+            "VmallocUsed:    {:8d} kB\n".format(0) +
+            "VmallocChunk:   {:8d} kB\n".format(0)
+            )
+        # if CONFIG_MEMORY_FAILURE
+        #   "HardwareCorrupted: %5lu kB\n"
+        # ifdef CONFIG_CMA
+        totalcma_pages = int(gdb.parse_and_eval("totalcma_pages"))
+        gdb.write(
+            "CmaTotal:       {:8d} kB\n".format(self.K(totalcma_pages)) +
+            "CmaFree:        {:8d} kB\n".format(self.gps_K("NR_FREE_CMA_PAGES"))
+            )
+
+LxMeminfo()
-- 
2.5.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ