aboutsummaryrefslogtreecommitdiff
path: root/stdlib/errno-printer.py
diff options
context:
space:
mode:
authorZack Weinberg <zackw@panix.com>2017-06-22 18:28:45 -0400
committerZack Weinberg <zackw@panix.com>2017-06-22 18:28:45 -0400
commit09e65f085e8491db0ada73c558ffe8dc296ade47 (patch)
treec31ff4f8f871bab4762248bffc9c3c508037ef61 /stdlib/errno-printer.py
parentbf7aa82eab0f1f9c78d39cf57a3f6b25eefc47c1 (diff)
downloadglibc-zack/errno-prettyprint.zip
glibc-zack/errno-prettyprint.tar.gz
glibc-zack/errno-prettyprint.tar.bz2
Add pretty-printer for errno.zack/errno-prettyprint
This patch adds the actual pretty-printer for errno. I could have used Python's built-in errno module to get the symbolic names for the constants, but it seemed better to do something entirely under our control, so there's a .pysym file generated from errnos.texi, with a hook that allows the Hurd to add additional constants. Then a .py module is generated from that plus errno.h in the usual manner; many thanks to the authors of the .pysym mechanism. There is also a test which verifies that the .py file (not the .pysym file) covers all of the constants defined in errno.h. hurd-add-errno-constants.awk has been manually tested, but the makefile logic that runs it has not been tested. * stdlib/errno-printer.py: New pretty-printer. * stdlib/test-errno-constants.py: New special test. * stdlib/test-errno-printer.c, stdlib/test-errno-printer.py: New pretty-printer test. * stdlib/make-errno-constants.awk: New script to generate the .pysym file needed by errno-printer.py. * stdlib/Makefile: Install, run, and test all of the above, as appropriate. * sysdeps/mach/hurd/hurd-add-errno-constants.awk: New script to add Mach/Hurd-specific errno constants to the .pysym file used by stdlib/errno-printer.py. * sysdeps/mach/hurd/Makefile: Hook hurd-add-errno-constants.awk into the generation of that .pysym file.
Diffstat (limited to 'stdlib/errno-printer.py')
-rw-r--r--stdlib/errno-printer.py105
1 files changed, 105 insertions, 0 deletions
diff --git a/stdlib/errno-printer.py b/stdlib/errno-printer.py
new file mode 100644
index 0000000..aa09c78
--- /dev/null
+++ b/stdlib/errno-printer.py
@@ -0,0 +1,105 @@
+# Pretty printer for errno.
+# Copyright (C) 2016-2017 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+"""This file contains the gdb pretty printers for the following types:
+
+ * __error_t (the type of 'errno')
+ * error_t (cast any 'int' to 'error_t' to print it like an errno value)
+
+You can check which printers are registered and enabled by issuing the
+'info pretty-printer' gdb command. Printers should trigger automatically when
+trying to print a variable of one of the types mentioned above.
+"""
+
+
+import gdb
+import gdb.printing
+import errno_constants
+
+
+def make_errno_reverse_mapping():
+ """Construct a reverse mapping from errno values to symbolic names.
+ The result is a dictionary indexed by integers, not a list,
+ because errno values are not necessarily contiguous.
+ """
+
+ # Certain errno symbols are allowed to have the same numeric value.
+ # If they do, one of them (whichever one is in POSIX, or if both or
+ # neither are, the shortest) is selected as the preferred name.
+ # This map goes from non-preferred name(s) to preferred name.
+ permitted_collisions = {
+ "EDEADLOCK": "EDEADLK",
+ "EOPNOTSUPP": "ENOTSUP",
+ "EWOULDBLOCK": "EAGAIN",
+ }
+
+ errno_names = { 0: "Success" }
+ for name in dir(errno_constants):
+ if name[0] == 'E':
+ number = getattr(errno_constants, name)
+ other = errno_names.get(number)
+ if other is None:
+ errno_names[number] = name
+ else:
+ p1 = permitted_collisions.get(name)
+ p2 = permitted_collisions.get(other)
+ if p1 is not None and p1 == other:
+ pass # the value in errno_names is already what we want
+ elif p2 is not None and p2 == name:
+ errno_names[number] = name
+ else:
+ raise RuntimeError(
+ "errno value collision: {} = {}, {}"
+ .format(number, name, errno_names[number]))
+
+ return errno_names
+
+
+errno_names = make_errno_reverse_mapping()
+
+
+class ErrnoPrinter(object):
+ """Pretty printer for errno values."""
+
+ def __init__(self, val):
+ self._val = int(val)
+
+ def to_string(self):
+ """gdb API function.
+
+ This is called from gdb when we try to print an error_t.
+ """
+ if self._val in errno_names:
+ return "{:d} ({})".format(self._val, errno_names[self._val])
+ else:
+ return "{:d}".format(self._val)
+
+
+def register(objfile):
+ """Register pretty printers for the current objfile."""
+
+ printer = gdb.printing.RegexpCollectionPrettyPrinter("glibc-errno")
+ printer.add_printer('error_t', r'^(?:__)?error_t', ErrnoPrinter)
+
+ if objfile == None:
+ objfile = gdb
+
+ gdb.printing.register_pretty_printer(objfile, printer)
+
+
+register(gdb.current_objfile())