Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1339635 > unrolled thread
| Started by | Kieran Bingham <kieran.bingham@linaro.org> |
|---|---|
| First post | 2016-02-22 16:30 +0100 |
| Last post | 2016-02-29 18:10 +0100 |
| Articles | 10 — 2 participants |
Back to article view | Back to linux.kernel
[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
| From | Kieran Bingham <kieran.bingham@linaro.org> |
|---|---|
| Date | 2016-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]
| From | Kieran Bingham <kieran.bingham@linaro.org> |
|---|---|
| Date | 2016-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]
| From | Kieran Bingham <kieran.bingham@linaro.org> |
|---|---|
| Date | 2016-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]
| From | Kieran Bingham <kieran.bingham@linaro.org> |
|---|---|
| Date | 2016-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]
| From | Kieran Bingham <kieran.bingham@linaro.org> |
|---|---|
| Date | 2016-02-24 10:50 +0100 |
| Subject | Re: [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]
| From | Kieran Bingham <kieran.bingham@linaro.org> |
|---|---|
| Date | 2016-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]
| From | Kieran Bingham <kieran.bingham@linaro.org> |
|---|---|
| Date | 2016-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]
| From | Kieran Bingham <kieran.bingham@linaro.org> |
|---|---|
| Date | 2016-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]
| From | Jan Kiszka <jan.kiszka@siemens.com> |
|---|---|
| Date | 2016-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]
| From | Kieran Bingham <kieran.bingham@linaro.org> |
|---|---|
| Date | 2016-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