Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1339635 > unrolled thread

[PATCHv2 0/8] gdb/scripts: Linux awareness debug commands

Started byKieran Bingham <kieran.bingham@linaro.org>
First post2016-02-22 16:30 +0100
Last post2016-02-29 18:10 +0100
Articles 10 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCHv2 0/8] gdb/scripts: Linux awareness debug commands Kieran Bingham <kieran.bingham@linaro.org> - 2016-02-22 16:30 +0100
    [PATCH 2/8] scripts/gdb: Provide a kernel list item generators Kieran Bingham <kieran.bingham@linaro.org> - 2016-02-22 16:30 +0100
    [PATCH 7/8] scripts/gdb: Add mount point list command Kieran Bingham <kieran.bingham@linaro.org> - 2016-02-22 16:30 +0100
    [PATCH 8/8] scripts/gdb: Add meminfo command Kieran Bingham <kieran.bingham@linaro.org> - 2016-02-22 16:30 +0100
      Re: [PATCH 8/8] scripts/gdb: Add meminfo command Kieran Bingham <kieran.bingham@linaro.org> - 2016-02-24 10:50 +0100
    [PATCH 4/8] scripts/gdb: Provide exception catching parser Kieran Bingham <kieran.bingham@linaro.org> - 2016-02-22 16:30 +0100
    [PATCH 3/8] scripts/gdb: Convert modules usage to lists functions Kieran Bingham <kieran.bingham@linaro.org> - 2016-02-22 16:30 +0100
    [PATCH 5/8] scripts/gdb: Support !CONFIG_MODULES gracefully Kieran Bingham <kieran.bingham@linaro.org> - 2016-02-22 16:30 +0100
    Re: [PATCHv2 0/8] gdb/scripts: Linux awareness debug commands Jan Kiszka <jan.kiszka@siemens.com> - 2016-02-29 17:40 +0100
      Re: [PATCHv2 0/8] gdb/scripts: Linux awareness debug commands Kieran Bingham <kieran.bingham@linaro.org> - 2016-02-29 18:10 +0100

#1339635 — [PATCHv2 0/8] gdb/scripts: Linux awareness debug commands

FromKieran Bingham <kieran.bingham@linaro.org>
Date2016-02-22 16:30 +0100
Subject[PATCHv2 0/8] gdb/scripts: Linux awareness debug commands
Message-ID<r50AW-7F1-13@gated-at.bofh.it>
Sending this revised series, which now provides ability to transfer configured
constants from the kernel to the python layer through the constants.py
infrastructure.

The iterators have been improved, in this instance thanks to the versions by
Jeff Mahoney on his py-kdump work; (which were better than mine, so I dropped
mine to replace with his)

Testing on an STM32, brought up a couple of issues with !CONFIG_MMU and
!CONFIG_MODULES which have been repaired, and further updates to both the
lx-mounts and lx-meminfo commands for fixes and improvements.

For convenience, this patch set submission can be found at
  http://git.linaro.org/people/kieran.bingham/linux.git gdb-scripts-2016-02-22-lkml-submission

Kieran Bingham (8):
  scripts/gdb: Provide linux constants
  scripts/gdb: Provide a kernel list item generators
  scripts/gdb: Convert modules usage to lists functions
  scripts/gdb: Provide exception catching parser
  scripts/gdb: Support !CONFIG_MODULES gracefully
  scripts/gdb: Add io resource readers
  scripts/gdb: Add mount point list command
  scripts/gdb: Add meminfo command

 Kbuild                            |  10 +
 scripts/gdb/linux/Makefile        |  12 +-
 scripts/gdb/linux/constants.py.in |  87 +++++++++
 scripts/gdb/linux/lists.py        |  20 ++
 scripts/gdb/linux/modules.py      |  22 +--
 scripts/gdb/linux/proc.py         | 384 ++++++++++++++++++++++++++++++++++++++
 scripts/gdb/linux/utils.py        |   7 +
 scripts/gdb/vmlinux-gdb.py        |   1 +
 8 files changed, 530 insertions(+), 13 deletions(-)
 create mode 100644 scripts/gdb/linux/constants.py.in

-- 
2.5.0

[toc] | [next] | [standalone]


#1339639 — [PATCH 2/8] scripts/gdb: Provide a kernel list item generators

FromKieran Bingham <kieran.bingham@linaro.org>
Date2016-02-22 16:30 +0100
Subject[PATCH 2/8] scripts/gdb: Provide a kernel list item generators
Message-ID<r50AX-7F1-33@gated-at.bofh.it>
In reply to#1339635
Facilitate linked-list items by providing a generator to return
the dereferenced, and type-cast objects from a kernel linked list

CC: Jeff Mahoney <jeffm@suse.com>

Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org>
---
Changes since v1:
 * items function removed, and replaced with Jeff Mahoney's cleaner
   implementations of list_for_each, and list_for_each_entry
---
 scripts/gdb/linux/lists.py | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/scripts/gdb/linux/lists.py b/scripts/gdb/linux/lists.py
index 3a3775bc162b..9f4503738e26 100644
--- a/scripts/gdb/linux/lists.py
+++ b/scripts/gdb/linux/lists.py
@@ -18,6 +18,26 @@ from linux import utils
 list_head = utils.CachedType("struct list_head")
 
 
+def list_for_each(head):
+    if head.type == list_head.get_type().pointer():
+        head = head.dereference()
+    elif head.type != list_head.get_type():
+        raise gdb.GdbError("Must be struct list_head not %s" % list_head.type)
+
+    node = head['next'].dereference()
+    while node.address != head.address:
+        yield node.address
+        node = node['next'].dereference()
+
+
+def list_for_each_entry(head, gdbtype, member):
+    for node in list_for_each(head):
+        if node.type != list_head.get_type().pointer():
+            raise TypeError("Type %s found. "
+                            "Expected struct list_head *." % node.type)
+        yield utils.container_of(node, gdbtype, member)
+
+
 def list_check(head):
     nb = 0
     if (head.type == list_head.get_type().pointer()):
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1339640 — [PATCH 7/8] scripts/gdb: Add mount point list command

FromKieran Bingham <kieran.bingham@linaro.org>
Date2016-02-22 16:30 +0100
Subject[PATCH 7/8] scripts/gdb: Add mount point list command
Message-ID<r50AW-7F1-29@gated-at.bofh.it>
In reply to#1339635
lx-mounts will identify current mount points based on the 'init_task'
namespace by default, as we do not yet have a kernel thread list
implementation to select the current running thread.

Optionally, a user can specify a PID to list from that process'
namespace

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

---
Changes from v1:
 - Updated to use LX_ constant macros
 - Adjusted for new list_for_each_item() function
 - Removed unnessary Null check in vfs['mnt_parent']
   - Tested and not needed. It probably occured in early testing
     with a bad iterator
---
 scripts/gdb/linux/constants.py.in |  21 ++++++++
 scripts/gdb/linux/proc.py         | 108 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 129 insertions(+)

diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
index 79d9d0092452..57213ad8cf75 100644
--- a/scripts/gdb/linux/constants.py.in
+++ b/scripts/gdb/linux/constants.py.in
@@ -12,7 +12,11 @@
  *
  */
 
+#include <linux/fs.h>
+#include <linux/mount.h>
+
 /* We need to stringify expanded macros so that they can be parsed */
+
 #define STRING(x) #x
 #define XSTRING(x) STRING(x)
 
@@ -30,3 +34,20 @@
 <!-- end-c-headers -->
 
 import gdb
+
+/* linux/fs.h */
+LX_VALUE(MS_RDONLY)
+LX_VALUE(MS_SYNCHRONOUS)
+LX_VALUE(MS_MANDLOCK)
+LX_VALUE(MS_DIRSYNC)
+LX_VALUE(MS_NOATIME)
+LX_VALUE(MS_NODIRATIME)
+
+/* linux/mount.h */
+LX_VALUE(MNT_NOSUID)
+LX_VALUE(MNT_NODEV)
+LX_VALUE(MNT_NOEXEC)
+LX_VALUE(MNT_NOATIME)
+LX_VALUE(MNT_NODIRATIME)
+LX_VALUE(MNT_RELATIME)
+
diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py
index d855b2fd9a06..44804e10493e 100644
--- a/scripts/gdb/linux/proc.py
+++ b/scripts/gdb/linux/proc.py
@@ -12,6 +12,10 @@
 #
 
 import gdb
+from linux import constants
+from linux import utils
+from linux import tasks
+from linux import lists
 
 
 class LxCmdLine(gdb.Command):
@@ -96,3 +100,107 @@ Equivalent to cat /proc/ioports on a running target"""
         return show_lx_resources("ioport_resource")
 
 LxIOPorts()
+
+
+# Mount namespace viewer
+#  /proc/mounts
+
+
+def dentry_name(d):
+    parent = d['d_parent']
+    if parent == d or parent == 0:
+        return ""
+    p = dentry_name(d['d_parent']) + "/"
+    return p + d['d_iname'].string()
+
+
+def info_opts(lst, opt):
+    opts = ""
+    for key, string in lst.items():
+        if opt & key:
+            opts += string
+    return opts
+
+
+FS_INFO = {constants.LX_MS_SYNCHRONOUS: ",sync",
+           constants.LX_MS_MANDLOCK: ",mand",
+           constants.LX_MS_DIRSYNC: ",dirsync",
+           constants.LX_MS_NOATIME: ",noatime",
+           constants.LX_MS_NODIRATIME: ",nodiratime"}
+
+MNT_INFO = {constants.LX_MNT_NOSUID: ",nosuid",
+            constants.LX_MNT_NODEV: ",nodev",
+            constants.LX_MNT_NOEXEC: ",noexec",
+            constants.LX_MNT_NOATIME: ",noatime",
+            constants.LX_MNT_NODIRATIME: ",nodiratime",
+            constants.LX_MNT_RELATIME: ",relatime"}
+
+mount_type = utils.CachedType("struct mount")
+mount_ptr_type = mount_type.get_type().pointer()
+
+
+class LxMounts(gdb.Command):
+    """Report the VFS mounts of the current process namespace.
+
+Equivalent to cat /proc/mounts on a running target
+An integer value can be supplied to display the mount
+values of that process namespace"""
+
+    def __init__(self):
+        super(LxMounts, self).__init__("lx-mounts", gdb.COMMAND_DATA)
+
+    # Equivalent to proc_namespace.c:show_vfsmnt
+    # However, that has the ability to call into s_op functions
+    # whereas we cannot and must make do with the information we can obtain.
+    def invoke(self, arg, from_tty):
+        argv = gdb.string_to_argv(arg)
+        if len(argv) >= 1:
+            try:
+                pid = int(argv[0])
+            except:
+                raise gdb.GdbError("Provide a PID as integer value")
+        else:
+            pid = 1
+
+        task = tasks.get_task_by_pid(pid)
+        if not task:
+            raise gdb.GdbError("Couldn't find a process with PID {}"
+                               .format(pid))
+
+        namespace = task['nsproxy']['mnt_ns']
+        if not namespace:
+            raise gdb.GdbError("No namespace for current process")
+
+        for vfs in lists.list_for_each_entry(
+                                namespace['list'], mount_ptr_type, "mnt_list"):
+            devname = vfs['mnt_devname'].string()
+            devname = devname if devname else "none"
+
+            pathname = ""
+            parent = vfs
+            while True:
+                mntpoint = parent['mnt_mountpoint']
+                pathname = dentry_name(mntpoint) + pathname
+                if (parent == parent['mnt_parent']):
+                    break
+                parent = parent['mnt_parent']
+
+            if (pathname == ""):
+                pathname = "/"
+
+            superblock = vfs['mnt']['mnt_sb']
+            fstype = superblock['s_type']['name'].string()
+            s_flags = int(superblock['s_flags'])
+            m_flags = int(vfs['mnt']['mnt_flags'])
+            rd = "ro" if (s_flags & constants.LX_MS_RDONLY) else "rw"
+
+            gdb.write(
+                "{} {} {} {}{}{} 0 0\n"
+                .format(devname,
+                        pathname,
+                        fstype,
+                        rd,
+                        info_opts(FS_INFO, s_flags),
+                        info_opts(MNT_INFO, m_flags)))
+
+LxMounts()
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1339641 — [PATCH 8/8] scripts/gdb: Add meminfo command

FromKieran Bingham <kieran.bingham@linaro.org>
Date2016-02-22 16:30 +0100
Subject[PATCH 8/8] scripts/gdb: Add meminfo command
Message-ID<r50AX-7F1-35@gated-at.bofh.it>
In reply to#1339635
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@linaro.org>

---

Changes from v1:
 - Updated to use LX_ macros for constants
 - Utilise the LX_CONFIG() options for conditional printing
 - Fixed meminfo command on Jan's target .config
 - Added missing segments to meminfo command (HUGEPAGE, QUICKLIST)
 - Adjusted for new list_for_each_entry() function
 - Fixed up for !CONFIG_SWAP and !CONFIG_MMU targets (Tested STM32)
---
 scripts/gdb/linux/constants.py.in |  34 ++++++
 scripts/gdb/linux/proc.py         | 219 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 253 insertions(+)

diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
index 57213ad8cf75..66562a8242bd 100644
--- a/scripts/gdb/linux/constants.py.in
+++ b/scripts/gdb/linux/constants.py.in
@@ -12,8 +12,16 @@
  *
  */
 
+#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/huge_mm.h>
+#include <linux/vmalloc.h>
+
 
 /* We need to stringify expanded macros so that they can be parsed */
 
@@ -51,3 +59,29 @@ LX_VALUE(MNT_NOATIME)
 LX_VALUE(MNT_NODIRATIME)
 LX_VALUE(MNT_RELATIME)
 
+/* asm/page.h */
+LX_GDBPARSED(PAGE_SHIFT)
+
+/* asm/thread_info.h */
+LX_GDBPARSED(THREAD_SIZE)
+
+/* linux/vmalloc.h */
+LX_GDBPARSED(VMALLOC_TOTAL)
+
+/* linux/swap.h */
+LX_GDBPARSED(MAX_SWAPFILES)
+
+
+/* Kernel Configs */
+LX_CONFIG(CONFIG_HIGHMEM)
+LX_CONFIG(CONFIG_MEMORY_FAILURE)
+LX_CONFIG(CONFIG_TRANSPARENT_HUGEPAGE)
+LX_CONFIG(CONFIG_CMA)
+LX_CONFIG(CONFIG_MMU)
+LX_CONFIG(CONFIG_SWAP)
+
+#ifndef CONFIG_NR_QUICK
+#define CONFIG_NR_QUICK 0
+#endif
+LX_VALUE(CONFIG_NR_QUICK)
+LX_CONFIG(CONFIG_QUICKLIST)
diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py
index 44804e10493e..95933f66ea3e 100644
--- a/scripts/gdb/linux/proc.py
+++ b/scripts/gdb/linux/proc.py
@@ -204,3 +204,222 @@ values of that process namespace"""
                         info_opts(MNT_INFO, m_flags)))
 
 LxMounts()
+
+
+bdev_type = utils.CachedType("struct block_device")
+bdev_ptr_type = bdev_type.get_type().pointer()
+
+
+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.list_for_each_entry(bdevs_head, bdev_ptr_type, "bd_list"):
+            try:
+                pages += bdev['bd_inode']['i_mapping']['nrpages']
+            except:
+                # Any memory read failures are simply not counted
+                pass
+        return pages
+
+    def total_swapcache_pages(self):
+        pages = 0
+        if not constants.LX_CONFIG_SWAP:
+            return 0
+
+        for i in range(0, int(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):
+        total_swap_pages = 0
+        overcommit = int(gdb.parse_and_eval("sysctl_overcommit_kbytes"))
+        overcommit_ratio = int(gdb.parse_and_eval("sysctl_overcommit_ratio"))
+
+        if constants.LX_CONFIG_SWAP:
+            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
+
+    def quicklist_total_size(self):
+        count = 0
+        quicklist = utils.gdb_eval_or_none("quicklist")
+        if quicklist is None:
+            return 0
+
+        for cpu in cpus.each_online_cpu():
+            ql = cpus.per_cpu(quicklist, cpu)
+            for q in range(0, constants.LX_CONFIG_NR_QUICK):
+                # for (q = ql; q < ql + CONFIG_NR_QUICK; q++)
+                # count += q->nr_pages
+                count += ql[q]['nr_pages']
+
+        return count
+
+    # Main lx-meminfo command execution
+    # See fs/proc/meminfo.c:meminfo_proc_show()
+    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
+
+        kernelstack = int(self.gps("NR_KERNEL_STACK") *
+                          constants.LX_THREAD_SIZE / 1024)
+
+        commitlimit = int(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"))
+            )
+        if constants.LX_CONFIG_HIGHMEM:
+            totalhigh = int(gdb.parse_and_eval("totalhigh_pages"))
+            freehigh = int(gdb.parse_and_eval("nr_free_highpages()"))
+            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))
+                )
+        if not constants.LX_CONFIG_MMU:
+            mmap_pages_allocated = gdb.parse_and_eval("mmap_pages_allocated.counter")
+            gdb.write(
+                "MmapCopy:       {:8d} kB\n".format(self.K(mmap_pages_allocated))
+
+                )
+            pass
+
+        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 constants.LX_CONFIG_QUICKLIST:
+            quicklist = self.quicklist_total_size()
+            gdb.write(
+               "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"))
+            )
+
+        gdb.write(
+            "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)
+            )
+
+        # These are always zero now
+        gdb.write(
+            "VmallocUsed:    {:8d} kB\n".format(0) +
+            "VmallocChunk:   {:8d} kB\n".format(0)
+            )
+
+        if constants.LX_CONFIG_MEMORY_FAILURE:
+            gdb.write(
+                "HardwareCorrupted: {:8d} kB\n"
+            )
+        if constants.LX_CONFIG_TRANSPARENT_HUGEPAGE:
+            huge = self.gps("NR_ANON_TRANSPARENT_HUGEPAGES")
+            # HPAGE_PMD_NR can not be determined in constants.py
+            gdb.write(
+                "AnonHugePages:  {:8d} kB ( * HPAGE_PMD_NR )\n"
+                .format(self.K(huge))
+            )
+        if constants.LX_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

[toc] | [prev] | [next] | [standalone]


#1341704 — Re: [PATCH 8/8] scripts/gdb: Add meminfo command

FromKieran Bingham <kieran.bingham@linaro.org>
Date2016-02-24 10:50 +0100
SubjectRe: [PATCH 8/8] scripts/gdb: Add meminfo command
Message-ID<r5Ef0-2yP-17@gated-at.bofh.it>
In reply to#1339641
I had missed some PEP8 line length warnings on this patch - I've now
fixed them up. And a spurious 'pass' statement appeared (highlighted
inline), which I've removed.
--
Kieran

On 22/02/16 15:24, Kieran Bingham wrote:
> 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@linaro.org>
> 
> ---
> 
> Changes from v1:
>  - Updated to use LX_ macros for constants
>  - Utilise the LX_CONFIG() options for conditional printing
>  - Fixed meminfo command on Jan's target .config
>  - Added missing segments to meminfo command (HUGEPAGE, QUICKLIST)
>  - Adjusted for new list_for_each_entry() function
>  - Fixed up for !CONFIG_SWAP and !CONFIG_MMU targets (Tested STM32)
> ---
>  scripts/gdb/linux/constants.py.in |  34 ++++++
>  scripts/gdb/linux/proc.py         | 219 ++++++++++++++++++++++++++++++++++++++
>  2 files changed, 253 insertions(+)
> 
> diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in
> index 57213ad8cf75..66562a8242bd 100644
> --- a/scripts/gdb/linux/constants.py.in
> +++ b/scripts/gdb/linux/constants.py.in
> @@ -12,8 +12,16 @@
>   *
>   */
>  
> +#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/huge_mm.h>
> +#include <linux/vmalloc.h>
> +
>  
>  /* We need to stringify expanded macros so that they can be parsed */
>  
> @@ -51,3 +59,29 @@ LX_VALUE(MNT_NOATIME)
>  LX_VALUE(MNT_NODIRATIME)
>  LX_VALUE(MNT_RELATIME)
>  
> +/* asm/page.h */
> +LX_GDBPARSED(PAGE_SHIFT)
> +
> +/* asm/thread_info.h */
> +LX_GDBPARSED(THREAD_SIZE)
> +
> +/* linux/vmalloc.h */
> +LX_GDBPARSED(VMALLOC_TOTAL)
> +
> +/* linux/swap.h */
> +LX_GDBPARSED(MAX_SWAPFILES)
> +
> +
> +/* Kernel Configs */
> +LX_CONFIG(CONFIG_HIGHMEM)
> +LX_CONFIG(CONFIG_MEMORY_FAILURE)
> +LX_CONFIG(CONFIG_TRANSPARENT_HUGEPAGE)
> +LX_CONFIG(CONFIG_CMA)
> +LX_CONFIG(CONFIG_MMU)
> +LX_CONFIG(CONFIG_SWAP)
> +
> +#ifndef CONFIG_NR_QUICK
> +#define CONFIG_NR_QUICK 0
> +#endif
> +LX_VALUE(CONFIG_NR_QUICK)
> +LX_CONFIG(CONFIG_QUICKLIST)
> diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py
> index 44804e10493e..95933f66ea3e 100644
> --- a/scripts/gdb/linux/proc.py
> +++ b/scripts/gdb/linux/proc.py
> @@ -204,3 +204,222 @@ values of that process namespace"""
>                          info_opts(MNT_INFO, m_flags)))
>  
>  LxMounts()
> +
> +
> +bdev_type = utils.CachedType("struct block_device")
> +bdev_ptr_type = bdev_type.get_type().pointer()
> +
> +
> +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.list_for_each_entry(bdevs_head, bdev_ptr_type, "bd_list"):
> +            try:
> +                pages += bdev['bd_inode']['i_mapping']['nrpages']
> +            except:
> +                # Any memory read failures are simply not counted
> +                pass
> +        return pages
> +
> +    def total_swapcache_pages(self):
> +        pages = 0
> +        if not constants.LX_CONFIG_SWAP:
> +            return 0
> +
> +        for i in range(0, int(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):
> +        total_swap_pages = 0
> +        overcommit = int(gdb.parse_and_eval("sysctl_overcommit_kbytes"))
> +        overcommit_ratio = int(gdb.parse_and_eval("sysctl_overcommit_ratio"))
> +
> +        if constants.LX_CONFIG_SWAP:
> +            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
> +
> +    def quicklist_total_size(self):
> +        count = 0
> +        quicklist = utils.gdb_eval_or_none("quicklist")
> +        if quicklist is None:
> +            return 0
> +
> +        for cpu in cpus.each_online_cpu():
> +            ql = cpus.per_cpu(quicklist, cpu)
> +            for q in range(0, constants.LX_CONFIG_NR_QUICK):
> +                # for (q = ql; q < ql + CONFIG_NR_QUICK; q++)
> +                # count += q->nr_pages
> +                count += ql[q]['nr_pages']
> +
> +        return count
> +
> +    # Main lx-meminfo command execution
> +    # See fs/proc/meminfo.c:meminfo_proc_show()
> +    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
> +
> +        kernelstack = int(self.gps("NR_KERNEL_STACK") *
> +                          constants.LX_THREAD_SIZE / 1024)
> +
> +        commitlimit = int(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"))
> +            )
> +        if constants.LX_CONFIG_HIGHMEM:
> +            totalhigh = int(gdb.parse_and_eval("totalhigh_pages"))
> +            freehigh = int(gdb.parse_and_eval("nr_free_highpages()"))
> +            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))
> +                )
> +        if not constants.LX_CONFIG_MMU:
> +            mmap_pages_allocated = gdb.parse_and_eval("mmap_pages_allocated.counter")
> +            gdb.write(
> +                "MmapCopy:       {:8d} kB\n".format(self.K(mmap_pages_allocated))
> +
> +                )

> +            pass

Hrm ... No idea where this 'pass' statement crept in ... It has been
dropped for the next patch version.

> +
> +        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 constants.LX_CONFIG_QUICKLIST:
> +            quicklist = self.quicklist_total_size()
> +            gdb.write(
> +               "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"))
> +            )
> +
> +        gdb.write(
> +            "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)
> +            )
> +
> +        # These are always zero now
> +        gdb.write(
> +            "VmallocUsed:    {:8d} kB\n".format(0) +
> +            "VmallocChunk:   {:8d} kB\n".format(0)
> +            )
> +
> +        if constants.LX_CONFIG_MEMORY_FAILURE:
> +            gdb.write(
> +                "HardwareCorrupted: {:8d} kB\n"
> +            )
> +        if constants.LX_CONFIG_TRANSPARENT_HUGEPAGE:
> +            huge = self.gps("NR_ANON_TRANSPARENT_HUGEPAGES")
> +            # HPAGE_PMD_NR can not be determined in constants.py
> +            gdb.write(
> +                "AnonHugePages:  {:8d} kB ( * HPAGE_PMD_NR )\n"
> +                .format(self.K(huge))
> +            )
> +        if constants.LX_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()
> 

[toc] | [prev] | [next] | [standalone]


#1339645 — [PATCH 4/8] scripts/gdb: Provide exception catching parser

FromKieran Bingham <kieran.bingham@linaro.org>
Date2016-02-22 16:30 +0100
Subject[PATCH 4/8] scripts/gdb: Provide exception catching parser
Message-ID<r50AX-7F1-45@gated-at.bofh.it>
In reply to#1339635
If we attempt to read a value that is not available to GDB, an exception
is raised. Most of the time, this is a good thing; however on occasion
we will want to be able to determine if a symbol is available.

By catching the exception to simply return None, we can determine if we
tried to read an invalid value, without the exception taking our execution
context away from us

Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org>
---
 scripts/gdb/linux/utils.py | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/scripts/gdb/linux/utils.py b/scripts/gdb/linux/utils.py
index 0893b326a28b..dbe2ad78048c 100644
--- a/scripts/gdb/linux/utils.py
+++ b/scripts/gdb/linux/utils.py
@@ -154,3 +154,10 @@ def get_gdbserver_type():
         if gdbserver_type is not None and hasattr(gdb, 'events'):
             gdb.events.exited.connect(exit_handler)
     return gdbserver_type
+
+
+def gdb_eval_or_none(expresssion):
+    try:
+        return gdb.parse_and_eval(expresssion)
+    except:
+        return None
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1339646 — [PATCH 3/8] scripts/gdb: Convert modules usage to lists functions

FromKieran Bingham <kieran.bingham@linaro.org>
Date2016-02-22 16:30 +0100
Subject[PATCH 3/8] scripts/gdb: Convert modules usage to lists functions
Message-ID<r50AX-7F1-49@gated-at.bofh.it>
In reply to#1339635
Simplify the module list functions with the new list_for_each_entry
abstractions

Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org>
---
 scripts/gdb/linux/modules.py | 17 ++++++-----------
 1 file changed, 6 insertions(+), 11 deletions(-)

diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py
index 25db8cff44a2..571489b3b9c2 100644
--- a/scripts/gdb/linux/modules.py
+++ b/scripts/gdb/linux/modules.py
@@ -13,7 +13,7 @@
 
 import gdb
 
-from linux import cpus, utils
+from linux import cpus, utils, lists
 
 
 module_type = utils.CachedType("struct module")
@@ -23,12 +23,9 @@ def module_list():
     global module_type
     module_ptr_type = module_type.get_type().pointer()
     modules = gdb.parse_and_eval("modules")
-    entry = modules['next']
-    end_of_list = modules.address
 
-    while entry != end_of_list:
-        yield utils.container_of(entry, module_ptr_type, "list")
-        entry = entry['next']
+    for module in lists.list_for_each_entry(modules, module_ptr_type, "list"):
+        yield module
 
 
 def find_module_by_name(name):
@@ -79,17 +76,15 @@ class LxLsmod(gdb.Command):
                 size=str(module['core_size']),
                 ref=str(module['refcnt']['counter'])))
 
-            source_list = module['source_list']
             t = self._module_use_type.get_type().pointer()
-            entry = source_list['next']
             first = True
-            while entry != source_list.address:
-                use = utils.container_of(entry, t, "source_list")
+            sources = module['source_list']
+            for use in lists.list_for_each_entry(sources, t, "source_list"):
                 gdb.write("{separator}{name}".format(
                     separator=" " if first else ",",
                     name=use['source']['name'].string()))
                 first = False
-                entry = entry['next']
+
             gdb.write("\n")
 
 
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1339652 — [PATCH 5/8] scripts/gdb: Support !CONFIG_MODULES gracefully

FromKieran Bingham <kieran.bingham@linaro.org>
Date2016-02-22 16:30 +0100
Subject[PATCH 5/8] scripts/gdb: Support !CONFIG_MODULES gracefully
Message-ID<r50AY-7F1-61@gated-at.bofh.it>
In reply to#1339635
If CONFIG_MODULES is not enabled, lx-lsmod tries to find
a non-existent symbol and generates an unfriendly traceback:

(gdb) lx-lsmod
Address    Module                  Size  Used by
Traceback (most recent call last):
  File "scripts/gdb/linux/modules.py", line 75, in invoke
    for module in module_list():
  File "scripts/gdb/linux/modules.py", line 24, in module_list
    module_ptr_type = module_type.get_type().pointer()
  File "scripts/gdb/linux/utils.py", line 28, in get_type
    self._type = gdb.lookup_type(self._name)
gdb.error: No struct type named module.
Error occurred in Python command: No struct type named module.

Catch the error and return an empty module_list() for a clean command
output as follows:

(gdb) lx-lsmod
Address    Module                  Size  Used by
(gdb)

Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org>
---
 scripts/gdb/linux/modules.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/scripts/gdb/linux/modules.py b/scripts/gdb/linux/modules.py
index 571489b3b9c2..60224d8bbfb2 100644
--- a/scripts/gdb/linux/modules.py
+++ b/scripts/gdb/linux/modules.py
@@ -21,8 +21,11 @@ module_type = utils.CachedType("struct module")
 
 def module_list():
     global module_type
+    modules = utils.gdb_eval_or_none("modules")
+    if modules is None:
+        return
+
     module_ptr_type = module_type.get_type().pointer()
-    modules = gdb.parse_and_eval("modules")
 
     for module in lists.list_for_each_entry(modules, module_ptr_type, "list"):
         yield module
-- 
2.5.0

[toc] | [prev] | [next] | [standalone]


#1345981

FromJan Kiszka <jan.kiszka@siemens.com>
Date2016-02-29 17:40 +0100
Message-ID<r7z1x-5sW-37@gated-at.bofh.it>
In reply to#1339635
Hi Kieran,

On 2016-02-22 16:24, Kieran Bingham wrote:
> Sending this revised series, which now provides ability to transfer configured
> constants from the kernel to the python layer through the constants.py
> infrastructure.
> 
> The iterators have been improved, in this instance thanks to the versions by
> Jeff Mahoney on his py-kdump work; (which were better than mine, so I dropped
> mine to replace with his)
> 
> Testing on an STM32, brought up a couple of issues with !CONFIG_MMU and
> !CONFIG_MODULES which have been repaired, and further updates to both the
> lx-mounts and lx-meminfo commands for fixes and improvements.
> 
> For convenience, this patch set submission can be found at
>   http://git.linaro.org/people/kieran.bingham/linux.git gdb-scripts-2016-02-22-lkml-submission

Thanks for the updated patches! This is just a note that review and
testing are still in my queue...

Jan

-- 
Siemens AG, Corporate Technology, CT RDA ITP SES-DE
Corporate Competence Center Embedded Linux

[toc] | [prev] | [next] | [standalone]


#1345999

FromKieran Bingham <kieran.bingham@linaro.org>
Date2016-02-29 18:10 +0100
Message-ID<r7zuy-5TD-15@gated-at.bofh.it>
In reply to#1345981
On 29/02/16 16:36, Jan Kiszka wrote:
> Hi Kieran,
> 
> On 2016-02-22 16:24, Kieran Bingham wrote:
>> Sending this revised series, which now provides ability to transfer configured
>> constants from the kernel to the python layer through the constants.py
>> infrastructure.
>>
>> The iterators have been improved, in this instance thanks to the versions by
>> Jeff Mahoney on his py-kdump work; (which were better than mine, so I dropped
>> mine to replace with his)
>>
>> Testing on an STM32, brought up a couple of issues with !CONFIG_MMU and
>> !CONFIG_MODULES which have been repaired, and further updates to both the
>> lx-mounts and lx-meminfo commands for fixes and improvements.
>>
>> For convenience, this patch set submission can be found at
>>   http://git.linaro.org/people/kieran.bingham/linux.git gdb-scripts-2016-02-22-lkml-submission
> 
> Thanks for the updated patches! This is just a note that review and
> testing are still in my queue...

Not a problem,
Thanks for the update.

--
Kieran

> Jan
> 

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web