From e34eebb8541f8a77dafd2398b637118a5f78dd21 Mon Sep 17 00:00:00 2001 From: DanielEScherzer Date: Wed, 9 Oct 2024 04:10:48 -0700 Subject: [PATCH] GDB: format output for class entries and class constants (#15955) For `zend_string` pointers in class entries, show the string contents (if not `NULL`). For class constants, the `ce` (class entry pointer) field is shown with the name of the class, and the `doc_comment` field is shown with the string contents if possible. --- main/debug_gdb_scripts.c | 52 ++++++++++++++++++++++++++++++++++++++++ scripts/gdb/php_gdb.py | 52 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/main/debug_gdb_scripts.c b/main/debug_gdb_scripts.c index de7d0c5c92df8..13288fc9adc8d 100644 --- a/main/debug_gdb_scripts.c +++ b/main/debug_gdb_scripts.c @@ -737,6 +737,12 @@ asm( ".ascii \"\\n\"\n" ".ascii \"pp_set.add_printer('zend_string', '^_zend_string$', ZendStringPrettyPrinter)\\n\"\n" ".ascii \"\\n\"\n" + ".ascii \"def zendStringPointerPrinter(ptr):\\n\"\n" + ".ascii \" \\\"Given a pointer to a zend_string, show the contents (if non-NULL)\\\"\\n\"\n" + ".ascii \" if int(ptr) == 0:\\n\"\n" + ".ascii \" return '0x0'\\n\"\n" + ".ascii \" return ZendStringPrettyPrinter(ptr.dereference()).to_string()\\n\"\n" + ".ascii \"\\n\"\n" ".ascii \"class ZendTypePrettyPrinter(gdb.printing.PrettyPrinter):\\n\"\n" ".ascii \" \\\"Print a zend_type\\\"\\n\"\n" ".ascii \"\\n\"\n" @@ -959,6 +965,52 @@ asm( ".ascii \"\\n\"\n" ".ascii \"pp_set.add_printer('zval', '^_zval_struct$', ZvalPrettyPrinter)\\n\"\n" ".ascii \"\\n\"\n" + ".ascii \"class ZendClassEntryPrettyPrinter(gdb.printing.PrettyPrinter):\\n\"\n" + ".ascii \" \\\"Print a zend_class_entry\\\"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" # String pointers, show the string contents if possible\\n\"\n" + ".ascii \" STRING_FIELDS = [ 'name', 'doc_comment' ]\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def __init__(self, val):\\n\"\n" + ".ascii \" self.val = val\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def to_string(self):\\n\"\n" + ".ascii \" return zendStringPointerPrinter(self.val['name'])\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def children(self):\\n\"\n" + ".ascii \" for field in self.val.type.fields():\\n\"\n" + ".ascii \" if field.name is not None:\\n\"\n" + ".ascii \" if field.name in self.STRING_FIELDS:\\n\"\n" + ".ascii \" yield (field.name, zendStringPointerPrinter(self.val[field.name]))\\n\"\n" + ".ascii \" else:\\n\"\n" + ".ascii \" yield (field.name, self.val[field.name])\\n\"\n" + ".ascii \" else:\\n\"\n" + ".ascii \" # Don't break on the union fields. Unfortunately, pretty\\n\"\n" + ".ascii \" # printers done in python cannot match the default formatting of\\n\"\n" + ".ascii \" # C anonymous fields, which omit the name entirely, see\\n\"\n" + ".ascii \" # binutils-gdb/gdb/cp-valprint.c#248 (as of commit\\n\"\n" + ".ascii \" # b6532accdd8e24329cc69bb58bc2883796008776)\\n\"\n" + ".ascii \" yield ('', self.val[field])\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"pp_set.add_printer('zend_class_entry', '^_zend_class_entry$', ZendClassEntryPrettyPrinter)\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"class ZendClassConstantPrettyPrinter(gdb.printing.PrettyPrinter):\\n\"\n" + ".ascii \" \\\"Print a zend_class_constant\\\"\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def __init__(self, val):\\n\"\n" + ".ascii \" self.val = val\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \" def children(self):\\n\"\n" + ".ascii \" for field in self.val.type.fields():\\n\"\n" + ".ascii \" if field.name == 'doc_comment':\\n\"\n" + ".ascii \" yield ('doc_comment', zendStringPointerPrinter(self.val['doc_comment']))\\n\"\n" + ".ascii \" elif field.name == 'ce':\\n\"\n" + ".ascii \" yield ('ce', zendStringPointerPrinter(self.val['ce']['name']))\\n\"\n" + ".ascii \" else:\\n\"\n" + ".ascii \" yield (field.name, self.val[field.name])\\n\"\n" + ".ascii \"\\n\"\n" + ".ascii \"pp_set.add_printer('zend_class_constant', '^_zend_class_constant$', ZendClassConstantPrettyPrinter)\\n\"\n" + ".ascii \"\\n\"\n" ".ascii \"type_bit_to_name = None\\n\"\n" ".ascii \"type_name_to_bit = None\\n\"\n" ".ascii \"\\n\"\n" diff --git a/scripts/gdb/php_gdb.py b/scripts/gdb/php_gdb.py index 7fef2ad1f49c8..b7258fb78f1a9 100644 --- a/scripts/gdb/php_gdb.py +++ b/scripts/gdb/php_gdb.py @@ -67,6 +67,12 @@ def format_string(self): pp_set.add_printer('zend_string', '^_zend_string$', ZendStringPrettyPrinter) +def zendStringPointerPrinter(ptr): + "Given a pointer to a zend_string, show the contents (if non-NULL)" + if int(ptr) == 0: + return '0x0' + return ZendStringPrettyPrinter(ptr.dereference()).to_string() + class ZendTypePrettyPrinter(gdb.printing.PrettyPrinter): "Print a zend_type" @@ -289,6 +295,52 @@ def children(self): pp_set.add_printer('zval', '^_zval_struct$', ZvalPrettyPrinter) +class ZendClassEntryPrettyPrinter(gdb.printing.PrettyPrinter): + "Print a zend_class_entry" + + # String pointers, show the string contents if possible + STRING_FIELDS = [ 'name', 'doc_comment' ] + + def __init__(self, val): + self.val = val + + def to_string(self): + return zendStringPointerPrinter(self.val['name']) + + def children(self): + for field in self.val.type.fields(): + if field.name is not None: + if field.name in self.STRING_FIELDS: + yield (field.name, zendStringPointerPrinter(self.val[field.name])) + else: + yield (field.name, self.val[field.name]) + else: + # Don't break on the union fields. Unfortunately, pretty + # printers done in python cannot match the default formatting of + # C anonymous fields, which omit the name entirely, see + # binutils-gdb/gdb/cp-valprint.c#248 (as of commit + # b6532accdd8e24329cc69bb58bc2883796008776) + yield ('', self.val[field]) + +pp_set.add_printer('zend_class_entry', '^_zend_class_entry$', ZendClassEntryPrettyPrinter) + +class ZendClassConstantPrettyPrinter(gdb.printing.PrettyPrinter): + "Print a zend_class_constant" + + def __init__(self, val): + self.val = val + + def children(self): + for field in self.val.type.fields(): + if field.name == 'doc_comment': + yield ('doc_comment', zendStringPointerPrinter(self.val['doc_comment'])) + elif field.name == 'ce': + yield ('ce', zendStringPointerPrinter(self.val['ce']['name'])) + else: + yield (field.name, self.val[field.name]) + +pp_set.add_printer('zend_class_constant', '^_zend_class_constant$', ZendClassConstantPrettyPrinter) + type_bit_to_name = None type_name_to_bit = None