diff --git a/misc/gdb_print_extension.py b/misc/gdb_print_extension.py new file mode 100644 index 000000000..513b573df --- /dev/null +++ b/misc/gdb_print_extension.py @@ -0,0 +1,208 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause + +"""gdb printing extension for Numba types.""" + +import re + +try: + import gdb.printing + import gdb +except ImportError: + raise ImportError("GDB python support is not available.") + + +class NumbaArrayPrinter: + def __init__(self, val): + self.val = val + + def to_string(self): + try: + import numpy as np + + HAVE_NUMPY = True + except ImportError: + HAVE_NUMPY = False + + try: + NULL = 0x0 + + # Raw data references, these need unpacking/interpreting. + + # Member "data" is... + # DW_TAG_member of DIDerivedType, tag of DW_TAG_pointer_type + # encoding e.g. DW_ATE_float + data = self.val["data"] + + # Member "itemsize" is... + # DW_TAG_member of DIBasicType encoding DW_ATE_signed + itemsize = self.val["itemsize"] + + # Members "shape" and "strides" are... + # DW_TAG_member of DIDerivedType, the type is a DICompositeType + # (it's a Numba UniTuple) with tag: DW_TAG_array_type, i.e. it's an + # array repr, it has a basetype of e.g. DW_ATE_unsigned and also + # "elements" which are referenced with a DISubrange(count: ) + # to say how many elements are in the array. + rshp = self.val["shape"] + rstrides = self.val["strides"] + + # bool on whether the data is aligned. + is_aligned = False + + # type information decode, simple type: + ty_str = str(self.val.type) + if HAVE_NUMPY and ("aligned" in ty_str or "Record" in ty_str): + ty_str = ty_str.replace("unaligned ", "").strip() + matcher = re.compile(r"array\((Record.*), (.*), (.*)\)\ \(.*") + # NOTE: need to deal with "Alignment" else dtype size is wrong + arr_info = [x.strip() for x in matcher.match(ty_str).groups()] + dtype_str, ndim_str, order_str = arr_info + rstr = r"Record\((.*\[.*\]);([0-9]+);(True|False)" + rstr_match = re.match(rstr, dtype_str) + # balign is unused, it's the alignment + fields, balign, is_aligned_str = rstr_match.groups() + is_aligned = is_aligned_str == "True" + field_dts = fields.split(",") + struct_entries = [] + for f in field_dts: + splitted = f.split("[") + name = splitted[0] + dt_part = splitted[1:] + if len(dt_part) > 1: + raise TypeError("Unsupported sub-type: %s" % f) + else: + dt_part = dt_part[0] + if "nestedarray" in dt_part: + raise TypeError("Unsupported sub-type: %s" % f) + dt_as_str = dt_part.split(";")[0].split("=")[1] + dtype = np.dtype(dt_as_str) + struct_entries.append((name, dtype)) + # The dtype is actually a record of some sort + dtype_str = struct_entries + else: # simple type + matcher = re.compile(r"array\((.*),(.*),(.*)\)\ \(.*") + arr_info = [x.strip() for x in matcher.match(ty_str).groups()] + dtype_str, ndim_str, order_str = arr_info + # fix up unichr dtype + if "unichr x " in dtype_str: + dtype_str = dtype_str[1:-1].replace("unichr x ", "