* [RFC PATCH 0/5] scripts/gdb: Linux awareness debug commands @ 2016-01-20 11:15 Kieran Bingham 2016-01-20 11:15 ` [PATCH 1/5] scripts/gdb: Provide linux constants Kieran Bingham ` (4 more replies) 0 siblings, 5 replies; 20+ messages in thread From: Kieran Bingham @ 2016-01-20 11:15 UTC (permalink / raw) To: jan.kiszka Cc: Kieran Bingham, linux-kernel, maxime.coquelin, peter.griffin, lee.jones Hi Jan, Following on from the initial commands provided earlier, I wanted to send an early set of patches for review, feedback and iteration. There is an /proc/interrupts command on the way too but that will be later, and I wanted to get these started. Particular commentry is either in the comments area of the patch, or in the code itself. A particular coding-style question is on the docstrings. Most of the existing commands do not indent their multiline docstrings. Is this preferred? And also, what is your take on line-length. Should it be hard and fast always < 79, or OK > if it keeps things readable?: pep8 proc.py proc.py:321:80: E501 line too long (80 > 79 characters) proc.py:363:80: E501 line too long (80 > 79 characters) proc.py:365:80: E501 line too long (82 > 79 characters) proc.py:378:80: E501 line too long (80 > 79 characters) These 4 lines come from [PATCH 5/5] scripts/gdb: Add meminfo command If I move the helper class functions out to file scope, that could trim the 'self.' keyword, and make the lines a little shorter ... Anyway, I look forward to hearing your comments, and any input from any other interested parties too! If anyone has any ideas for commands that they would like to see available, or useful kernel parsers, now is a great time to get involved! Regards -- Kieran Kieran Bingham (5): scripts/gdb: Provide linux constants scripts/gdb: Provide a kernel list item generator scripts/gdb: Add io resource readers scripts/gdb: Add mount point list command scripts/gdb: Add meminfo command scripts/gdb/linux/Makefile | 9 +- scripts/gdb/linux/constants.py.in | 65 ++++++++ scripts/gdb/linux/lists.py | 9 + scripts/gdb/linux/proc.py | 340 ++++++++++++++++++++++++++++++++++++++ scripts/gdb/vmlinux-gdb.py | 1 + 5 files changed, 422 insertions(+), 2 deletions(-) create mode 100644 scripts/gdb/linux/constants.py.in -- 2.5.0 ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/5] scripts/gdb: Provide linux constants 2016-01-20 11:15 [RFC PATCH 0/5] scripts/gdb: Linux awareness debug commands Kieran Bingham @ 2016-01-20 11:15 ` Kieran Bingham 2016-01-23 15:05 ` Jan Kiszka 2016-01-20 11:15 ` [PATCH 2/5] scripts/gdb: Provide a kernel list item generator Kieran Bingham ` (3 subsequent siblings) 4 siblings, 1 reply; 20+ messages in thread From: Kieran Bingham @ 2016-01-20 11:15 UTC (permalink / raw) To: jan.kiszka Cc: Kieran Bingham, linux-kernel, maxime.coquelin, peter.griffin, lee.jones Some macro's and defines are needed when parsing memory, and without compiling the kernel as -g3 they are not available in the debug-symbols. We use the pre-processor here to extract constants to a dedicated module for the linux debugger extensions Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> --- I've added a 'constants.py' which is automatically generated. This allows values not available to the debugger, through #defines to be provided to our scripts. The alternative method for this is to create a c-object file to obtain values through symbols instead, and compile segments with -g3 to include macro definitions in the debug-info. I'd appreciate your thoughts on these options. scripts/gdb/linux/Makefile | 9 +++++++-- scripts/gdb/linux/constants.py.in | 22 ++++++++++++++++++++++ scripts/gdb/vmlinux-gdb.py | 1 + 3 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 scripts/gdb/linux/constants.py.in diff --git a/scripts/gdb/linux/Makefile b/scripts/gdb/linux/Makefile index 6cf1ecf61057..50864f408ca8 100644 --- a/scripts/gdb/linux/Makefile +++ b/scripts/gdb/linux/Makefile @@ -2,10 +2,15 @@ always := gdb-scripts SRCTREE := $(shell cd $(srctree) && /bin/pwd) -$(obj)/gdb-scripts: +$(obj)/gdb-scripts: $(obj)/constants.py ifneq ($(KBUILD_SRC),) $(Q)ln -fsn $(SRCTREE)/$(obj)/*.py $(objtree)/$(obj) endif @: -clean-files := *.pyc *.pyo $(if $(KBUILD_SRC),*.py) +$(obj)/constants.py: $(SRCTREE)/$(obj)/constants.py.in + @echo " GDB PP $@" + @$(CPP) -E -x c -P $(c_flags) $< > $@ + @sed -i '1,/<!-- end-c-headers -->/d;' $@ + +clean-files := *.pyc *.pyo $(if $(KBUILD_SRC),*.py) $(obj)/constants.py diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in new file mode 100644 index 000000000000..d84084ac945b --- /dev/null +++ b/scripts/gdb/linux/constants.py.in @@ -0,0 +1,22 @@ +/* + * gdb helper commands and functions for Linux kernel debugging + * + * Kernel constants derived from include files. + * + * Copyright (c) 2016 Linaro Ltd + * + * Authors: + * Kieran Bingham <kieran.bingham@linaro.org> + * + * This work is licensed under the terms of the GNU GPL version 2. + * + */ + +/* We need to stringify expanded macros so that they can be parsed */ +#define STRING(x) #x +#define XSTRING(x) STRING(x) + +/* The build system will take care of deleting everything above this marker */ +<!-- end-c-headers --> + +import gdb diff --git a/scripts/gdb/vmlinux-gdb.py b/scripts/gdb/vmlinux-gdb.py index d5943eca19cd..6e0b0afd888a 100644 --- a/scripts/gdb/vmlinux-gdb.py +++ b/scripts/gdb/vmlinux-gdb.py @@ -30,3 +30,4 @@ else: import linux.cpus import linux.lists import linux.proc + import linux.constants -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 1/5] scripts/gdb: Provide linux constants 2016-01-20 11:15 ` [PATCH 1/5] scripts/gdb: Provide linux constants Kieran Bingham @ 2016-01-23 15:05 ` Jan Kiszka 2016-01-24 0:11 ` Kieran Bingham 0 siblings, 1 reply; 20+ messages in thread From: Jan Kiszka @ 2016-01-23 15:05 UTC (permalink / raw) To: Kieran Bingham; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones On 2016-01-20 12:15, Kieran Bingham wrote: > Some macro's and defines are needed when parsing memory, and without > compiling the kernel as -g3 they are not available in the debug-symbols. > > We use the pre-processor here to extract constants to a dedicated module > for the linux debugger extensions > > Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> > --- > > I've added a 'constants.py' which is automatically generated. This allows > values not available to the debugger, through #defines to be provided to > our scripts. > > The alternative method for this is to create a c-object file to obtain values > through symbols instead, and compile segments with -g3 to include macro > definitions in the debug-info. > > I'd appreciate your thoughts on these options. I cannot assess your second proposal. How invasive will it be? Is it promising to reduce the maintenance? What will be the impact of -g3? This approach seems pragmatic and sufficient. Would be fine with me unless the other has significant advantages. Jan -- Siemens AG, Corporate Technology, CT RDA ITP SES-DE Corporate Competence Center Embedded Linux ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 1/5] scripts/gdb: Provide linux constants 2016-01-23 15:05 ` Jan Kiszka @ 2016-01-24 0:11 ` Kieran Bingham 0 siblings, 0 replies; 20+ messages in thread From: Kieran Bingham @ 2016-01-24 0:11 UTC (permalink / raw) To: Jan Kiszka; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones On 23/01/16 15:05, Jan Kiszka wrote: > On 2016-01-20 12:15, Kieran Bingham wrote: >> Some macro's and defines are needed when parsing memory, and without >> compiling the kernel as -g3 they are not available in the debug-symbols. >> >> We use the pre-processor here to extract constants to a dedicated module >> for the linux debugger extensions >> >> Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> >> --- >> >> I've added a 'constants.py' which is automatically generated. This allows >> values not available to the debugger, through #defines to be provided to >> our scripts. >> >> The alternative method for this is to create a c-object file to obtain values >> through symbols instead, and compile segments with -g3 to include macro >> definitions in the debug-info. >> >> I'd appreciate your thoughts on these options. > > I cannot assess your second proposal. How invasive will it be? Is it > promising to reduce the maintenance? What will be the impact of -g3? > > This approach seems pragmatic and sufficient. Would be fine with me > unless the other has significant advantages. At the moment, I believe the current method (generating a constants.py) is my preferred method. It's less intrusive, and can be generated for a kernel which is to be debugged, which perhaps didn't have GDB_SCRIPTS enabled at the time. A c-object file would be more limiting I believe. Kieran ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 2/5] scripts/gdb: Provide a kernel list item generator 2016-01-20 11:15 [RFC PATCH 0/5] scripts/gdb: Linux awareness debug commands Kieran Bingham 2016-01-20 11:15 ` [PATCH 1/5] scripts/gdb: Provide linux constants Kieran Bingham @ 2016-01-20 11:15 ` Kieran Bingham 2016-01-23 15:08 ` Jan Kiszka 2016-01-20 11:15 ` [PATCH 3/5] scripts/gdb: Add io resource readers Kieran Bingham ` (2 subsequent siblings) 4 siblings, 1 reply; 20+ messages in thread From: Kieran Bingham @ 2016-01-20 11:15 UTC (permalink / raw) To: jan.kiszka Cc: Kieran Bingham, linux-kernel, maxime.coquelin, peter.griffin, lee.jones Facilitate linked-list items by providing a generator to return the dereferenced, and type-cast objects from a kernel linked list Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> --- This is quite a useful wrapper to faciliate looping on lists. It is sort of equivalent to the list_for_each_entry macro. Let me know if it should be renamed, or live elsewhere. scripts/gdb/linux/lists.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/gdb/linux/lists.py b/scripts/gdb/linux/lists.py index 3a3775bc162b..d2c6ce165cb1 100644 --- a/scripts/gdb/linux/lists.py +++ b/scripts/gdb/linux/lists.py @@ -18,6 +18,15 @@ from linux import utils list_head = utils.CachedType("struct list_head") +def items(list_type, list_location, item_list): + """items Generator return items from a kernel linked list""" + item_list_head = item_list + next_item = item_list_head['next'].dereference() + while next_item != item_list_head: + yield utils.container_of(next_item, list_type, list_location) + next_item = next_item['next'].dereference() + + def list_check(head): nb = 0 if (head.type == list_head.get_type().pointer()): -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 2/5] scripts/gdb: Provide a kernel list item generator 2016-01-20 11:15 ` [PATCH 2/5] scripts/gdb: Provide a kernel list item generator Kieran Bingham @ 2016-01-23 15:08 ` Jan Kiszka 2016-01-24 0:15 ` Kieran Bingham 0 siblings, 1 reply; 20+ messages in thread From: Jan Kiszka @ 2016-01-23 15:08 UTC (permalink / raw) To: Kieran Bingham; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones On 2016-01-20 12:15, Kieran Bingham wrote: > Facilitate linked-list items by providing a generator to return > the dereferenced, and type-cast objects from a kernel linked list > > Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> > --- > > This is quite a useful wrapper to faciliate looping on lists. > It is sort of equivalent to the list_for_each_entry macro. > > Let me know if it should be renamed, or live elsewhere. Location is fine. Maybe call it list_items? > > scripts/gdb/linux/lists.py | 9 +++++++++ > 1 file changed, 9 insertions(+) > > diff --git a/scripts/gdb/linux/lists.py b/scripts/gdb/linux/lists.py > index 3a3775bc162b..d2c6ce165cb1 100644 > --- a/scripts/gdb/linux/lists.py > +++ b/scripts/gdb/linux/lists.py > @@ -18,6 +18,15 @@ from linux import utils > list_head = utils.CachedType("struct list_head") > > > +def items(list_type, list_location, item_list): > + """items Generator return items from a kernel linked list""" > + item_list_head = item_list > + next_item = item_list_head['next'].dereference() > + while next_item != item_list_head: > + yield utils.container_of(next_item, list_type, list_location) > + next_item = next_item['next'].dereference() > + > + > def list_check(head): > nb = 0 > if (head.type == list_head.get_type().pointer()): > Could you apply it on existing list iterations? module_list() seems like a candidate, e.g. Jan -- Siemens AG, Corporate Technology, CT RDA ITP SES-DE Corporate Competence Center Embedded Linux ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 2/5] scripts/gdb: Provide a kernel list item generator 2016-01-23 15:08 ` Jan Kiszka @ 2016-01-24 0:15 ` Kieran Bingham 0 siblings, 0 replies; 20+ messages in thread From: Kieran Bingham @ 2016-01-24 0:15 UTC (permalink / raw) To: Jan Kiszka; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones On 23/01/16 15:08, Jan Kiszka wrote: > On 2016-01-20 12:15, Kieran Bingham wrote: >> Facilitate linked-list items by providing a generator to return >> the dereferenced, and type-cast objects from a kernel linked list >> >> Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> >> --- >> >> This is quite a useful wrapper to faciliate looping on lists. >> It is sort of equivalent to the list_for_each_entry macro. >> >> Let me know if it should be renamed, or live elsewhere. > > Location is fine. Maybe call it list_items? > >> >> scripts/gdb/linux/lists.py | 9 +++++++++ >> 1 file changed, 9 insertions(+) >> >> diff --git a/scripts/gdb/linux/lists.py b/scripts/gdb/linux/lists.py >> index 3a3775bc162b..d2c6ce165cb1 100644 >> --- a/scripts/gdb/linux/lists.py >> +++ b/scripts/gdb/linux/lists.py >> @@ -18,6 +18,15 @@ from linux import utils >> list_head = utils.CachedType("struct list_head") >> >> >> +def items(list_type, list_location, item_list): >> + """items Generator return items from a kernel linked list""" >> + item_list_head = item_list >> + next_item = item_list_head['next'].dereference() >> + while next_item != item_list_head: >> + yield utils.container_of(next_item, list_type, list_location) >> + next_item = next_item['next'].dereference() >> + >> + >> def list_check(head): >> nb = 0 >> if (head.type == list_head.get_type().pointer()): >> > > Could you apply it on existing list iterations? module_list() seems like > a candidate, e.g. Yes, It probably is. I'll update, and add a patch to my series, and check to see if there are any more. -- Kieran > > Jan > ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 3/5] scripts/gdb: Add io resource readers 2016-01-20 11:15 [RFC PATCH 0/5] scripts/gdb: Linux awareness debug commands Kieran Bingham 2016-01-20 11:15 ` [PATCH 1/5] scripts/gdb: Provide linux constants Kieran Bingham 2016-01-20 11:15 ` [PATCH 2/5] scripts/gdb: Provide a kernel list item generator Kieran Bingham @ 2016-01-20 11:15 ` Kieran Bingham 2016-01-23 15:12 ` Jan Kiszka 2016-01-20 11:15 ` [PATCH 4/5] scripts/gdb: Add mount point list command Kieran Bingham 2016-01-20 11:15 ` [PATCH 5/5] scripts/gdb: Add meminfo command Kieran Bingham 4 siblings, 1 reply; 20+ messages in thread From: Kieran Bingham @ 2016-01-20 11:15 UTC (permalink / raw) To: jan.kiszka Cc: Kieran Bingham, linux-kernel, maxime.coquelin, peter.griffin, lee.jones Provide iomem_resource and ioports_resource printers and command hooks Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> --- These two readers are a useful extract of kernel information. This shows the power of having these commands in gdb/scripts as you can halt a kernel as it's booting and read these as the structures grow. It should be useful in the event that a kernel is not booting, you can identify what memory resources have been registered scripts/gdb/linux/proc.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py index 6e6709c1830c..d855b2fd9a06 100644 --- a/scripts/gdb/linux/proc.py +++ b/scripts/gdb/linux/proc.py @@ -39,3 +39,60 @@ class LxVersion(gdb.Command): gdb.write(gdb.parse_and_eval("linux_banner").string()) LxVersion() + + +# Resource Structure Printers +# /proc/iomem +# /proc/ioports + +def get_resources(resource, depth): + while resource: + yield resource, depth + + child = resource['child'] + if child: + for res, deep in get_resources(child, depth + 1): + yield res, deep + + resource = resource['sibling'] + + +def show_lx_resources(resource_str): + resource = gdb.parse_and_eval(resource_str) + width = 4 if resource['end'] < 0x10000 else 8 + # Iterate straight to the first child + for res, depth in get_resources(resource['child'], 0): + start = int(res['start']) + end = int(res['end']) + gdb.write(" " * depth * 2 + + "{0:0{1}x}-".format(start, width) + + "{0:0{1}x} : ".format(end, width) + + res['name'].string() + "\n") + + +class LxIOMem(gdb.Command): + """Identify the IO memory resource locations defined by the kernel + +Equivalent to cat /proc/iomem on a running target""" + + def __init__(self): + super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA) + + def invoke(self, arg, from_tty): + return show_lx_resources("iomem_resource") + +LxIOMem() + + +class LxIOPorts(gdb.Command): + """Identify the IO port resource locations defined by the kernel + +Equivalent to cat /proc/ioports on a running target""" + + def __init__(self): + super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA) + + def invoke(self, arg, from_tty): + return show_lx_resources("ioport_resource") + +LxIOPorts() -- 2.5.0 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 3/5] scripts/gdb: Add io resource readers 2016-01-20 11:15 ` [PATCH 3/5] scripts/gdb: Add io resource readers Kieran Bingham @ 2016-01-23 15:12 ` Jan Kiszka 2016-01-24 0:17 ` Kieran Bingham 0 siblings, 1 reply; 20+ messages in thread From: Jan Kiszka @ 2016-01-23 15:12 UTC (permalink / raw) To: Kieran Bingham; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones On 2016-01-20 12:15, Kieran Bingham wrote: > Provide iomem_resource and ioports_resource printers and command hooks > > Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> > > --- > > These two readers are a useful extract of kernel information. > This shows the power of having these commands in gdb/scripts as you can > halt a kernel as it's booting and read these as the structures grow. > > It should be useful in the event that a kernel is not booting, you > can identify what memory resources have been registered > Ack. Maybe provide this reasoning in the commit log? I explains why we want this which is too often lacking in the persistent logs... > > > scripts/gdb/linux/proc.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 57 insertions(+) > > diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py > index 6e6709c1830c..d855b2fd9a06 100644 > --- a/scripts/gdb/linux/proc.py > +++ b/scripts/gdb/linux/proc.py > @@ -39,3 +39,60 @@ class LxVersion(gdb.Command): > gdb.write(gdb.parse_and_eval("linux_banner").string()) > > LxVersion() > + > + > +# Resource Structure Printers > +# /proc/iomem > +# /proc/ioports > + > +def get_resources(resource, depth): > + while resource: > + yield resource, depth > + > + child = resource['child'] > + if child: > + for res, deep in get_resources(child, depth + 1): > + yield res, deep > + > + resource = resource['sibling'] > + > + > +def show_lx_resources(resource_str): > + resource = gdb.parse_and_eval(resource_str) > + width = 4 if resource['end'] < 0x10000 else 8 > + # Iterate straight to the first child > + for res, depth in get_resources(resource['child'], 0): > + start = int(res['start']) > + end = int(res['end']) > + gdb.write(" " * depth * 2 + > + "{0:0{1}x}-".format(start, width) + > + "{0:0{1}x} : ".format(end, width) + > + res['name'].string() + "\n") > + > + > +class LxIOMem(gdb.Command): > + """Identify the IO memory resource locations defined by the kernel > + > +Equivalent to cat /proc/iomem on a running target""" > + > + def __init__(self): > + super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA) > + > + def invoke(self, arg, from_tty): > + return show_lx_resources("iomem_resource") > + > +LxIOMem() > + > + > +class LxIOPorts(gdb.Command): > + """Identify the IO port resource locations defined by the kernel > + > +Equivalent to cat /proc/ioports on a running target""" > + > + def __init__(self): > + super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA) > + > + def invoke(self, arg, from_tty): > + return show_lx_resources("ioport_resource") > + > +LxIOPorts() > Looks good to me. Jan -- Siemens AG, Corporate Technology, CT RDA ITP SES-DE Corporate Competence Center Embedded Linux ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/5] scripts/gdb: Add io resource readers 2016-01-23 15:12 ` Jan Kiszka @ 2016-01-24 0:17 ` Kieran Bingham 0 siblings, 0 replies; 20+ messages in thread From: Kieran Bingham @ 2016-01-24 0:17 UTC (permalink / raw) To: Jan Kiszka; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones On 23/01/16 15:12, Jan Kiszka wrote: > On 2016-01-20 12:15, Kieran Bingham wrote: >> Provide iomem_resource and ioports_resource printers and command hooks >> >> Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> >> >> --- >> >> These two readers are a useful extract of kernel information. >> This shows the power of having these commands in gdb/scripts as you can >> halt a kernel as it's booting and read these as the structures grow. >> >> It should be useful in the event that a kernel is not booting, you >> can identify what memory resources have been registered >> > > Ack. Maybe provide this reasoning in the commit log? I explains why we > want this which is too often lacking in the persistent logs... > Perfect, I'll update the commit for v2. -- Kieran >> >> >> scripts/gdb/linux/proc.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 57 insertions(+) >> >> diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py >> index 6e6709c1830c..d855b2fd9a06 100644 >> --- a/scripts/gdb/linux/proc.py >> +++ b/scripts/gdb/linux/proc.py >> @@ -39,3 +39,60 @@ class LxVersion(gdb.Command): >> gdb.write(gdb.parse_and_eval("linux_banner").string()) >> >> LxVersion() >> + >> + >> +# Resource Structure Printers >> +# /proc/iomem >> +# /proc/ioports >> + >> +def get_resources(resource, depth): >> + while resource: >> + yield resource, depth >> + >> + child = resource['child'] >> + if child: >> + for res, deep in get_resources(child, depth + 1): >> + yield res, deep >> + >> + resource = resource['sibling'] >> + >> + >> +def show_lx_resources(resource_str): >> + resource = gdb.parse_and_eval(resource_str) >> + width = 4 if resource['end'] < 0x10000 else 8 >> + # Iterate straight to the first child >> + for res, depth in get_resources(resource['child'], 0): >> + start = int(res['start']) >> + end = int(res['end']) >> + gdb.write(" " * depth * 2 + >> + "{0:0{1}x}-".format(start, width) + >> + "{0:0{1}x} : ".format(end, width) + >> + res['name'].string() + "\n") >> + >> + >> +class LxIOMem(gdb.Command): >> + """Identify the IO memory resource locations defined by the kernel >> + >> +Equivalent to cat /proc/iomem on a running target""" >> + >> + def __init__(self): >> + super(LxIOMem, self).__init__("lx-iomem", gdb.COMMAND_DATA) >> + >> + def invoke(self, arg, from_tty): >> + return show_lx_resources("iomem_resource") >> + >> +LxIOMem() >> + >> + >> +class LxIOPorts(gdb.Command): >> + """Identify the IO port resource locations defined by the kernel >> + >> +Equivalent to cat /proc/ioports on a running target""" >> + >> + def __init__(self): >> + super(LxIOPorts, self).__init__("lx-ioports", gdb.COMMAND_DATA) >> + >> + def invoke(self, arg, from_tty): >> + return show_lx_resources("ioport_resource") >> + >> +LxIOPorts() >> > > Looks good to me. > > Jan > ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 4/5] scripts/gdb: Add mount point list command 2016-01-20 11:15 [RFC PATCH 0/5] scripts/gdb: Linux awareness debug commands Kieran Bingham ` (2 preceding siblings ...) 2016-01-20 11:15 ` [PATCH 3/5] scripts/gdb: Add io resource readers Kieran Bingham @ 2016-01-20 11:15 ` Kieran Bingham 2016-01-20 11:42 ` Jan Kiszka ` (2 more replies) 2016-01-20 11:15 ` [PATCH 5/5] scripts/gdb: Add meminfo command Kieran Bingham 4 siblings, 3 replies; 20+ messages in thread From: Kieran Bingham @ 2016-01-20 11:15 UTC (permalink / raw) To: jan.kiszka Cc: Kieran Bingham, linux-kernel, maxime.coquelin, peter.griffin, lee.jones 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 This is somewhat limited vs the /proc/mounts file, as that calls into vfs hooks through the s_op functions to obtain extra information. Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> --- In this patch, I'm interested in your opinions on coding styles. Would you prefer to see the function helpers, (dentry_name, info_opts) where they are, or inside the command as class members? Or perhaps defined in utils? This also shows where I need to take constant information from the kernel. In this case, they are simple numerical bitflags, and unlikely to change but I didn't want to duplicate their values. scripts/gdb/linux/constants.py.in | 21 ++++++++ scripts/gdb/linux/proc.py | 110 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 131 insertions(+) diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in index d84084ac945b..739a15d2e984 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) @@ -20,3 +24,20 @@ <!-- end-c-headers --> import gdb + +/* linux/fs.h */ +LX_MS_RDONLY = MS_RDONLY +LX_MS_SYNCHRONOUS = MS_SYNCHRONOUS +LX_MS_MANDLOCK = MS_MANDLOCK +LX_MS_DIRSYNC = MS_DIRSYNC +LX_MS_NOATIME = MS_NOATIME +LX_MS_NODIRATIME = MS_NODIRATIME + +/* linux/mount.h */ +LX_MNT_NOSUID = MNT_NOSUID +LX_MNT_NODEV = MNT_NODEV +LX_MNT_NOEXEC = MNT_NOEXEC +LX_MNT_NOATIME = MNT_NOATIME +LX_MNT_NODIRATIME = MNT_NODIRATIME +LX_MNT_RELATIME = MNT_RELATIME + diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py index d855b2fd9a06..b79ce2a33a3d 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,109 @@ 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): + if d['d_parent'] == d: + 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.items(mount_ptr_type, "mnt_list", namespace['list']): + # There appears to be a null entry at the end of the list... + if not vfs['mnt_parent']: + break + + 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 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 4/5] scripts/gdb: Add mount point list command 2016-01-20 11:15 ` [PATCH 4/5] scripts/gdb: Add mount point list command Kieran Bingham @ 2016-01-20 11:42 ` Jan Kiszka 2016-01-20 11:51 ` Kieran Bingham 2016-01-23 12:34 ` Jan Kiszka 2016-01-23 15:27 ` Jan Kiszka 2 siblings, 1 reply; 20+ messages in thread From: Jan Kiszka @ 2016-01-20 11:42 UTC (permalink / raw) To: Kieran Bingham; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones Hi Kieran, just a couple of quick comments: On 2016-01-20 12:15, Kieran Bingham wrote: > 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. current_task? See LxCurrentFunc, could be factored out if usable. Or what are you looking for? > > Optionally, a user can specify a PID to list from that process' > namespace > > This is somewhat limited vs the /proc/mounts file, as that calls into > vfs hooks through the s_op functions to obtain extra information. > > Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> > --- > > > In this patch, I'm interested in your opinions on coding styles. > Would you prefer to see the function helpers, (dentry_name, info_opts) where > they are, or inside the command as class members? Or perhaps defined in utils? Need to look into this. > > This also shows where I need to take constant information from the kernel. > In this case, they are simple numerical bitflags, and unlikely to change but > I didn't want to duplicate their values. Maybe we can generate python files with the required constants from the C headers during build? Similar to asm-offsets.c stuff. > > > scripts/gdb/linux/constants.py.in | 21 ++++++++ > scripts/gdb/linux/proc.py | 110 ++++++++++++++++++++++++++++++++++++++ > 2 files changed, 131 insertions(+) > > diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in > index d84084ac945b..739a15d2e984 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) > > @@ -20,3 +24,20 @@ > <!-- end-c-headers --> > > import gdb > + > +/* linux/fs.h */ > +LX_MS_RDONLY = MS_RDONLY > +LX_MS_SYNCHRONOUS = MS_SYNCHRONOUS > +LX_MS_MANDLOCK = MS_MANDLOCK > +LX_MS_DIRSYNC = MS_DIRSYNC > +LX_MS_NOATIME = MS_NOATIME > +LX_MS_NODIRATIME = MS_NODIRATIME > + > +/* linux/mount.h */ > +LX_MNT_NOSUID = MNT_NOSUID > +LX_MNT_NODEV = MNT_NODEV > +LX_MNT_NOEXEC = MNT_NOEXEC > +LX_MNT_NOATIME = MNT_NOATIME > +LX_MNT_NODIRATIME = MNT_NODIRATIME > +LX_MNT_RELATIME = MNT_RELATIME > + > diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py > index d855b2fd9a06..b79ce2a33a3d 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,109 @@ 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): > + if d['d_parent'] == d: > + 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.items(mount_ptr_type, "mnt_list", namespace['list']): > + # There appears to be a null entry at the end of the list... > + if not vfs['mnt_parent']: > + break > + > + 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() > -- Siemens AG, Corporate Technology, CT RDA ITP SES-DE Corporate Competence Center Embedded Linux ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 4/5] scripts/gdb: Add mount point list command 2016-01-20 11:42 ` Jan Kiszka @ 2016-01-20 11:51 ` Kieran Bingham 2016-01-20 12:08 ` Jan Kiszka 0 siblings, 1 reply; 20+ messages in thread From: Kieran Bingham @ 2016-01-20 11:51 UTC (permalink / raw) To: Jan Kiszka; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones Hi Jan, On 20/01/16 11:42, Jan Kiszka wrote: > Hi Kieran, > > just a couple of quick comments: > > On 2016-01-20 12:15, Kieran Bingham wrote: >> 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. > > current_task? See LxCurrentFunc, could be factored out if usable. Or > what are you looking for? LxCurrentFunc relies on gdb.parse_and_eval("¤t_task") which is not available on ARM. Although that is not what I was referring to in the comment. My meaning was that once we have gdb-thread objects created, (my next phase of work) then this command would operate on the thread currently selected in gdb, based on the inferior_ptid. >> >> Optionally, a user can specify a PID to list from that process' >> namespace >> >> This is somewhat limited vs the /proc/mounts file, as that calls into >> vfs hooks through the s_op functions to obtain extra information. >> >> Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> >> --- >> >> >> In this patch, I'm interested in your opinions on coding styles. >> Would you prefer to see the function helpers, (dentry_name, info_opts) where >> they are, or inside the command as class members? Or perhaps defined in utils? > > Need to look into this. > >> >> This also shows where I need to take constant information from the kernel. >> In this case, they are simple numerical bitflags, and unlikely to change but >> I didn't want to duplicate their values. > > Maybe we can generate python files with the required constants from the > C headers during build? Similar to asm-offsets.c stuff. > Yes, this is what I've implemented in [PATCH 1/5] ? Perhaps the mails have reached you out-of-order. >> >> >> scripts/gdb/linux/constants.py.in | 21 ++++++++ >> scripts/gdb/linux/proc.py | 110 ++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 131 insertions(+) >> >> diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in >> index d84084ac945b..739a15d2e984 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) >> >> @@ -20,3 +24,20 @@ >> <!-- end-c-headers --> >> >> import gdb >> + >> +/* linux/fs.h */ >> +LX_MS_RDONLY = MS_RDONLY >> +LX_MS_SYNCHRONOUS = MS_SYNCHRONOUS >> +LX_MS_MANDLOCK = MS_MANDLOCK >> +LX_MS_DIRSYNC = MS_DIRSYNC >> +LX_MS_NOATIME = MS_NOATIME >> +LX_MS_NODIRATIME = MS_NODIRATIME >> + >> +/* linux/mount.h */ >> +LX_MNT_NOSUID = MNT_NOSUID >> +LX_MNT_NODEV = MNT_NODEV >> +LX_MNT_NOEXEC = MNT_NOEXEC >> +LX_MNT_NOATIME = MNT_NOATIME >> +LX_MNT_NODIRATIME = MNT_NODIRATIME >> +LX_MNT_RELATIME = MNT_RELATIME >> + >> diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py >> index d855b2fd9a06..b79ce2a33a3d 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,109 @@ 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): >> + if d['d_parent'] == d: >> + 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.items(mount_ptr_type, "mnt_list", namespace['list']): >> + # There appears to be a null entry at the end of the list... >> + if not vfs['mnt_parent']: >> + break >> + >> + 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() >> > ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 4/5] scripts/gdb: Add mount point list command 2016-01-20 11:51 ` Kieran Bingham @ 2016-01-20 12:08 ` Jan Kiszka 0 siblings, 0 replies; 20+ messages in thread From: Jan Kiszka @ 2016-01-20 12:08 UTC (permalink / raw) To: Kieran Bingham; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones On 2016-01-20 12:51, Kieran Bingham wrote: > Hi Jan, > > On 20/01/16 11:42, Jan Kiszka wrote: >> Hi Kieran, >> >> just a couple of quick comments: >> >> On 2016-01-20 12:15, Kieran Bingham wrote: >>> 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. >> >> current_task? See LxCurrentFunc, could be factored out if usable. Or >> what are you looking for? > > LxCurrentFunc relies on gdb.parse_and_eval("¤t_task") which is not > available on ARM. Good point, not only affecting ARM. Needs to be fixed - lx-current() is an important service. > > Although that is not what I was referring to in the comment. My meaning > was that once we have gdb-thread objects created, (my next phase of > work) then this command would operate on the thread currently selected > in gdb, based on the inferior_ptid. I see. However, to have thread selection run with reasonable defaults, we will need current() support as well. > > >>> >>> Optionally, a user can specify a PID to list from that process' >>> namespace >>> >>> This is somewhat limited vs the /proc/mounts file, as that calls into >>> vfs hooks through the s_op functions to obtain extra information. >>> >>> Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> >>> --- >>> >>> >>> In this patch, I'm interested in your opinions on coding styles. >>> Would you prefer to see the function helpers, (dentry_name, info_opts) where >>> they are, or inside the command as class members? Or perhaps defined in utils? >> >> Need to look into this. >> >>> >>> This also shows where I need to take constant information from the kernel. >>> In this case, they are simple numerical bitflags, and unlikely to change but >>> I didn't want to duplicate their values. >> >> Maybe we can generate python files with the required constants from the >> C headers during build? Similar to asm-offsets.c stuff. >> > > > Yes, this is what I've implemented in [PATCH 1/5] ? Perhaps the mails > have reached you out-of-order. > No, they were only processed in random order. Perfect! Jan -- Siemens AG, Corporate Technology, CT RDA ITP SES-DE Corporate Competence Center Embedded Linux ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 4/5] scripts/gdb: Add mount point list command 2016-01-20 11:15 ` [PATCH 4/5] scripts/gdb: Add mount point list command Kieran Bingham 2016-01-20 11:42 ` Jan Kiszka @ 2016-01-23 12:34 ` Jan Kiszka 2016-01-23 15:27 ` Jan Kiszka 2 siblings, 0 replies; 20+ messages in thread From: Jan Kiszka @ 2016-01-23 12:34 UTC (permalink / raw) To: Kieran Bingham; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones On 2016-01-20 12:15, Kieran Bingham wrote: > 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 > > This is somewhat limited vs the /proc/mounts file, as that calls into > vfs hooks through the s_op functions to obtain extra information. > > Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> > --- > > > In this patch, I'm interested in your opinions on coding styles. > Would you prefer to see the function helpers, (dentry_name, info_opts) where > they are, or inside the command as class members? Or perhaps defined in utils? > > This also shows where I need to take constant information from the kernel. > In this case, they are simple numerical bitflags, and unlikely to change but > I didn't want to duplicate their values. > > > scripts/gdb/linux/constants.py.in | 21 ++++++++ > scripts/gdb/linux/proc.py | 110 ++++++++++++++++++++++++++++++++++++++ > 2 files changed, 131 insertions(+) > > diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in > index d84084ac945b..739a15d2e984 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) > This hunk is malformed, indicating that 4 lines are added while there are actually only 3 new ones. Could you check what went wrong? I'm applying it manually for now. Jan -- Siemens AG, Corporate Technology, CT RDA ITP SES-DE Corporate Competence Center Embedded Linux ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 4/5] scripts/gdb: Add mount point list command 2016-01-20 11:15 ` [PATCH 4/5] scripts/gdb: Add mount point list command Kieran Bingham 2016-01-20 11:42 ` Jan Kiszka 2016-01-23 12:34 ` Jan Kiszka @ 2016-01-23 15:27 ` Jan Kiszka 2016-01-24 0:24 ` Kieran Bingham 2 siblings, 1 reply; 20+ messages in thread From: Jan Kiszka @ 2016-01-23 15:27 UTC (permalink / raw) To: Kieran Bingham; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones On 2016-01-20 12:15, Kieran Bingham wrote: > 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 > > This is somewhat limited vs the /proc/mounts file, as that calls into > vfs hooks through the s_op functions to obtain extra information. > > Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> > --- > > > In this patch, I'm interested in your opinions on coding styles. > Would you prefer to see the function helpers, (dentry_name, info_opts) where > they are, or inside the command as class members? Or perhaps defined in utils? Do you think they could be useful beyond this class? If not, stick them inside. Refactoring can still be done once they are needed. > > This also shows where I need to take constant information from the kernel. > In this case, they are simple numerical bitflags, and unlikely to change but > I didn't want to duplicate their values. > > > scripts/gdb/linux/constants.py.in | 21 ++++++++ > scripts/gdb/linux/proc.py | 110 ++++++++++++++++++++++++++++++++++++++ > 2 files changed, 131 insertions(+) > > diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in > index d84084ac945b..739a15d2e984 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) > > @@ -20,3 +24,20 @@ > <!-- end-c-headers --> > > import gdb > + > +/* linux/fs.h */ > +LX_MS_RDONLY = MS_RDONLY > +LX_MS_SYNCHRONOUS = MS_SYNCHRONOUS > +LX_MS_MANDLOCK = MS_MANDLOCK > +LX_MS_DIRSYNC = MS_DIRSYNC > +LX_MS_NOATIME = MS_NOATIME > +LX_MS_NODIRATIME = MS_NODIRATIME > + > +/* linux/mount.h */ > +LX_MNT_NOSUID = MNT_NOSUID > +LX_MNT_NODEV = MNT_NODEV > +LX_MNT_NOEXEC = MNT_NOEXEC > +LX_MNT_NOATIME = MNT_NOATIME > +LX_MNT_NODIRATIME = MNT_NODIRATIME > +LX_MNT_RELATIME = MNT_RELATIME > + > diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py > index d855b2fd9a06..b79ce2a33a3d 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,109 @@ 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): > + if d['d_parent'] == d: > + 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.items(mount_ptr_type, "mnt_list", namespace['list']): > + # There appears to be a null entry at the end of the list... "There appears to be" - hmm... Did you check this against the code? > + if not vfs['mnt_parent']: > + break > + > + 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 I'm getting an error in this line: (gdb) lx-mounts devtmpfs /dev devtmpfs rw,relatime 0 0 tmpfs /dev/shm tmpfs rw,relatime 0 0 devpts /dev/pts devpts rw,relatime 0 0 /dev/sda2 / ext4 rw,relatime 0 0 proc /proc proc rw,nodiratime,relatime 0 0 sysfs /sys sysfs rw,relatime 0 0 debugfs /sys/kernel/debug debugfs rw,relatime 0 0 securityfs /sys/kernel/security securityfs rw,relatime 0 0 fusectl /sys/fs/fuse/connections fusectl rw,relatime 0 0 gvfs-fuse-daemon /home/jan/.gvfs fuse rw,relatime,nosuid,nodev 0 0 tracefs /sys/kernel/debug/tracing tracefs rw,relatime 0 0 Traceback (most recent call last): File "/data/linux/build-dbg/scripts/gdb/linux/proc.py", line 185, in invoke pathname = dentry_name(mntpoint) + pathname File "/data/linux/build-dbg/scripts/gdb/linux/proc.py", line 112, in dentry_name p = dentry_name(d['d_parent']) + "/" File "/data/linux/build-dbg/scripts/gdb/linux/proc.py", line 110, in dentry_name if d['d_parent'] == d: gdb.MemoryError: Cannot access memory at address 0x40 Error occurred in Python command: Cannot access memory at address 0x40 In this case, the dump should have stopped after the tracefs line. > + 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() > Jan -- Siemens AG, Corporate Technology, CT RDA ITP SES-DE Corporate Competence Center Embedded Linux ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 4/5] scripts/gdb: Add mount point list command 2016-01-23 15:27 ` Jan Kiszka @ 2016-01-24 0:24 ` Kieran Bingham 0 siblings, 0 replies; 20+ messages in thread From: Kieran Bingham @ 2016-01-24 0:24 UTC (permalink / raw) To: Jan Kiszka; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones On 23/01/16 15:27, Jan Kiszka wrote: > On 2016-01-20 12:15, Kieran Bingham wrote: >> 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 >> >> This is somewhat limited vs the /proc/mounts file, as that calls into >> vfs hooks through the s_op functions to obtain extra information. >> >> Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org> >> --- >> >> >> In this patch, I'm interested in your opinions on coding styles. >> Would you prefer to see the function helpers, (dentry_name, info_opts) where >> they are, or inside the command as class members? Or perhaps defined in utils? > > Do you think they could be useful beyond this class? If not, stick them > inside. Refactoring can still be done once they are needed. > Ok - that's good logic. Keep them close until needed elsewhere :) >> >> This also shows where I need to take constant information from the kernel. >> In this case, they are simple numerical bitflags, and unlikely to change but >> I didn't want to duplicate their values. >> >> >> scripts/gdb/linux/constants.py.in | 21 ++++++++ >> scripts/gdb/linux/proc.py | 110 ++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 131 insertions(+) >> >> diff --git a/scripts/gdb/linux/constants.py.in b/scripts/gdb/linux/constants.py.in >> index d84084ac945b..739a15d2e984 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) >> >> @@ -20,3 +24,20 @@ >> <!-- end-c-headers --> >> >> import gdb >> + >> +/* linux/fs.h */ >> +LX_MS_RDONLY = MS_RDONLY >> +LX_MS_SYNCHRONOUS = MS_SYNCHRONOUS >> +LX_MS_MANDLOCK = MS_MANDLOCK >> +LX_MS_DIRSYNC = MS_DIRSYNC >> +LX_MS_NOATIME = MS_NOATIME >> +LX_MS_NODIRATIME = MS_NODIRATIME >> + >> +/* linux/mount.h */ >> +LX_MNT_NOSUID = MNT_NOSUID >> +LX_MNT_NODEV = MNT_NODEV >> +LX_MNT_NOEXEC = MNT_NOEXEC >> +LX_MNT_NOATIME = MNT_NOATIME >> +LX_MNT_NODIRATIME = MNT_NODIRATIME >> +LX_MNT_RELATIME = MNT_RELATIME >> + >> diff --git a/scripts/gdb/linux/proc.py b/scripts/gdb/linux/proc.py >> index d855b2fd9a06..b79ce2a33a3d 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,109 @@ 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): >> + if d['d_parent'] == d: >> + 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.items(mount_ptr_type, "mnt_list", namespace['list']): >> + # There appears to be a null entry at the end of the list... > > "There appears to be" - hmm... Did you check this against the code? Not properly no... I'll check and see what happened. I'll have a think as to the best defences to put in. This one stopped a NULL dereference on mine, but as below clearly it didn't stop them all! > >> + if not vfs['mnt_parent']: >> + break >> + >> + 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 > > I'm getting an error in this line: > > (gdb) lx-mounts > devtmpfs /dev devtmpfs rw,relatime 0 0 > tmpfs /dev/shm tmpfs rw,relatime 0 0 > devpts /dev/pts devpts rw,relatime 0 0 > /dev/sda2 / ext4 rw,relatime 0 0 > proc /proc proc rw,nodiratime,relatime 0 0 > sysfs /sys sysfs rw,relatime 0 0 > debugfs /sys/kernel/debug debugfs rw,relatime 0 0 > securityfs /sys/kernel/security securityfs rw,relatime 0 0 > fusectl /sys/fs/fuse/connections fusectl rw,relatime 0 0 > gvfs-fuse-daemon /home/jan/.gvfs fuse rw,relatime,nosuid,nodev 0 0 > tracefs /sys/kernel/debug/tracing tracefs rw,relatime 0 0 > Traceback (most recent call last): > File "/data/linux/build-dbg/scripts/gdb/linux/proc.py", line 185, in invoke > pathname = dentry_name(mntpoint) + pathname > File "/data/linux/build-dbg/scripts/gdb/linux/proc.py", line 112, in dentry_name > p = dentry_name(d['d_parent']) + "/" > File "/data/linux/build-dbg/scripts/gdb/linux/proc.py", line 110, in dentry_name > if d['d_parent'] == d: > gdb.MemoryError: Cannot access memory at address 0x40 > Error occurred in Python command: Cannot access memory at address 0x40 > > In this case, the dump should have stopped after the tracefs line. > Interesting, I'll have to be more defensive. I'm sure when I looked the proc show command seemed to have only the list end and the dev name checks... But we could by our nature run at any time - so it should be a bit more defensive anyway >> + 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() >> > > Jan > Kieran ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 5/5] scripts/gdb: Add meminfo command 2016-01-20 11:15 [RFC PATCH 0/5] scripts/gdb: Linux awareness debug commands Kieran Bingham ` (3 preceding siblings ...) 2016-01-20 11:15 ` [PATCH 4/5] scripts/gdb: Add mount point list command Kieran Bingham @ 2016-01-20 11:15 ` Kieran Bingham 2016-01-23 15:21 ` Jan Kiszka 4 siblings, 1 reply; 20+ messages in thread From: Kieran Bingham @ 2016-01-20 11:15 UTC (permalink / raw) To: jan.kiszka Cc: Kieran Bingham, linux-kernel, maxime.coquelin, peter.griffin, lee.jones 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> --- 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 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 5/5] scripts/gdb: Add meminfo command 2016-01-20 11:15 ` [PATCH 5/5] scripts/gdb: Add meminfo command Kieran Bingham @ 2016-01-23 15:21 ` Jan Kiszka 2016-01-24 0:30 ` Kieran Bingham 0 siblings, 1 reply; 20+ messages in thread From: Jan Kiszka @ 2016-01-23 15:21 UTC (permalink / raw) To: Kieran Bingham; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones On 2016-01-20 12:15, 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> > --- > > 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. Yeah, seems so - see below ;) > > 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? I didn't grab the use cases yet, so just a general suggestion: if the inaccurate information may still have some value, you can mark it as inaccurate and still print it. > > 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! Why not convert the (relevant) configs inside constants.py into a python variable? CONFIG_IS_ENABLED should make this easy. > > > 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() Something goes wrong here: (gdb) lx-meminfo Traceback (most recent call last): File "/data/linux/build-dbg/scripts/gdb/linux/proc.py", line 286, in invoke bufferram = self.nr_blockdev_pages() File "/data/linux/build-dbg/scripts/gdb/linux/proc.py", line 246, in nr_blockdev_pages for bdev in lists.items(bdev_type, "bd_list", bdevs_head): File "/data/linux/build-dbg/scripts/gdb/linux/lists.py", line 26, in items yield utils.container_of(next_item, list_type, list_location) File "/data/linux/build-dbg/scripts/gdb/linux/utils.py", line 52, in container_of offset_of(typeobj, member)).cast(typeobj) File "/data/linux/build-dbg/scripts/gdb/linux/utils.py", line 46, in offset_of element = gdb.Value(0).cast(typeobj) RuntimeError: Argument must be a type. Error occurred in Python command: Argument must be a type. If you need my kernel config to reproduce, just let me know. > + 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() > Jan -- Siemens AG, Corporate Technology, CT RDA ITP SES-DE Corporate Competence Center Embedded Linux ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 5/5] scripts/gdb: Add meminfo command 2016-01-23 15:21 ` Jan Kiszka @ 2016-01-24 0:30 ` Kieran Bingham 0 siblings, 0 replies; 20+ messages in thread From: Kieran Bingham @ 2016-01-24 0:30 UTC (permalink / raw) To: Jan Kiszka; +Cc: linux-kernel, maxime.coquelin, peter.griffin, lee.jones On 23/01/16 15:21, Jan Kiszka wrote: > On 2016-01-20 12:15, 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> >> --- >> >> 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. > > Yeah, seems so - see below ;) > >> >> 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? > > I didn't grab the use cases yet, so just a general suggestion: if the > inaccurate information may still have some value, you can mark it as > inaccurate and still print it. > >> >> 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! > > Why not convert the (relevant) configs inside constants.py into a > python variable? CONFIG_IS_ENABLED should make this easy. Aha, Excellent. I think I must not have seen the wood-for-the-trees on this one! Had a play, and I can't use IS_ENABLED(x) directly, as it generates (0 || 1) from IS_BUILTIN and IS_MODULE - and which is not compatible with python. However, in our use-case - we actually only want to switch on BUILTIN's anyway, so I will use that. If other use cases come up later, we can always extend to create our own Python version of IS_ENABLED >> >> >> 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() > > Something goes wrong here: > > (gdb) lx-meminfo > Traceback (most recent call last): > File "/data/linux/build-dbg/scripts/gdb/linux/proc.py", line 286, in invoke > bufferram = self.nr_blockdev_pages() > File "/data/linux/build-dbg/scripts/gdb/linux/proc.py", line 246, in nr_blockdev_pages > for bdev in lists.items(bdev_type, "bd_list", bdevs_head): > File "/data/linux/build-dbg/scripts/gdb/linux/lists.py", line 26, in items > yield utils.container_of(next_item, list_type, list_location) > File "/data/linux/build-dbg/scripts/gdb/linux/utils.py", line 52, in container_of > offset_of(typeobj, member)).cast(typeobj) > File "/data/linux/build-dbg/scripts/gdb/linux/utils.py", line 46, in offset_of > element = gdb.Value(0).cast(typeobj) > RuntimeError: Argument must be a type. > Error occurred in Python command: Argument must be a type. > > If you need my kernel config to reproduce, just let me know. Yes please, send me a config, and I'll try to reproduce. What is your test environment by the way? I am running in QEmu for convenience mostly at the moment. I hope to set up some automated scripts to test on different arch's too. -- Kieran > >> + 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() >> > > Jan > ^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2016-01-24 0:30 UTC | newest] Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-01-20 11:15 [RFC PATCH 0/5] scripts/gdb: Linux awareness debug commands Kieran Bingham 2016-01-20 11:15 ` [PATCH 1/5] scripts/gdb: Provide linux constants Kieran Bingham 2016-01-23 15:05 ` Jan Kiszka 2016-01-24 0:11 ` Kieran Bingham 2016-01-20 11:15 ` [PATCH 2/5] scripts/gdb: Provide a kernel list item generator Kieran Bingham 2016-01-23 15:08 ` Jan Kiszka 2016-01-24 0:15 ` Kieran Bingham 2016-01-20 11:15 ` [PATCH 3/5] scripts/gdb: Add io resource readers Kieran Bingham 2016-01-23 15:12 ` Jan Kiszka 2016-01-24 0:17 ` Kieran Bingham 2016-01-20 11:15 ` [PATCH 4/5] scripts/gdb: Add mount point list command Kieran Bingham 2016-01-20 11:42 ` Jan Kiszka 2016-01-20 11:51 ` Kieran Bingham 2016-01-20 12:08 ` Jan Kiszka 2016-01-23 12:34 ` Jan Kiszka 2016-01-23 15:27 ` Jan Kiszka 2016-01-24 0:24 ` Kieran Bingham 2016-01-20 11:15 ` [PATCH 5/5] scripts/gdb: Add meminfo command Kieran Bingham 2016-01-23 15:21 ` Jan Kiszka 2016-01-24 0:30 ` Kieran Bingham
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).