Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 11 additions & 14 deletions libcudacxx/share/libcudacxx/gdb/atomic.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from collections.abc import Iterator
from types import ModuleType

import memory_resource
import cccl_common

import gdb
import gdb.printing
Expand All @@ -26,30 +26,26 @@
}


def _template_name(type_name: str) -> str:
return type_name.split("<", 1)[0]


def _is_atomic_ref(type_name: str) -> bool:
return _template_name(type_name) in _ATOMIC_REF_NAMES
return cccl_common.template_name(type_name) in _ATOMIC_REF_NAMES


def _complete_type_name(value_type: gdb.Type) -> str:
"""Return the complete public type name, including CUDA thread scope."""
value_type = value_type.strip_typedefs().unqualified()
type_name = memory_resource.public_type_name(value_type)
template_name = _template_name(type_name)
value_type = cccl_common.canonical_type(value_type)
type_name = cccl_common.public_type_name(value_type)
template_name = cccl_common.template_name(type_name)
if template_name not in {"cuda::atomic", "cuda::atomic_ref"}:
return type_name

value_type_name = memory_resource.public_type_name(value_type.template_argument(0))
value_type_name = cccl_common.public_type_name(value_type.template_argument(0))
scope = int(value_type.template_argument(1))
return f"{template_name}<{value_type_name}, cuda::thread_scope_{_THREAD_SCOPE_NAMES[scope]}>"


def _is_cuda_atomic(value_type: gdb.Type) -> bool:
value_type = value_type.strip_typedefs().unqualified()
template_name = _template_name(memory_resource.public_type_name(value_type))
value_type = cccl_common.canonical_type(value_type)
template_name = cccl_common.template_name(cccl_common.public_type_name(value_type))
return template_name in _ATOMIC_NAMES


Expand All @@ -58,7 +54,7 @@ def _reference_pointer(value: gdb.Value) -> gdb.Value:


def _stored_value(value: gdb.Value, type_name: str) -> gdb.Value:
value_type = value.type.strip_typedefs().unqualified()
value_type = cccl_common.canonical_type(value.type)
storage = value["__a"]
stored = storage["__a_value"]

Expand All @@ -77,8 +73,9 @@ class AtomicPrinter:
"""Expose the value represented by a CUDA atomic without executing inferior code."""

def __init__(self, value: gdb.Value) -> None:
value = cccl_common.strip_reference_value(value)
self.value = value
self.type = value.type.strip_typedefs().unqualified()
self.type = cccl_common.canonical_type(value.type)
self.type_name = _complete_type_name(self.type)

def children(self) -> Iterator[tuple[str, gdb.Value]]:
Expand Down
14 changes: 5 additions & 9 deletions libcudacxx/share/libcudacxx/gdb/buffer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from collections.abc import Iterator
from types import ModuleType

import cccl_common
import memory_resource

import gdb
Expand All @@ -20,14 +21,8 @@
_CUDA_MEMCPY_DEFAULT = 4


def _template_name(value_type: gdb.Type) -> str:
return str(value_type).split("<", 1)[0]


def _is_cuda_buffer(value_type: gdb.Type) -> bool:
# strip_typedefs resolves aliases that can hide accessibility properties.
value_type = value_type.strip_typedefs().unqualified()
template_name = _template_name(value_type)
template_name = cccl_common.template_name(cccl_common.canonical_type(value_type))
return (
template_name.startswith("cuda::")
and template_name.rsplit("::", 1)[-1] == "buffer"
Expand All @@ -38,9 +33,10 @@ class BufferPrinter:
"""Expose cuda::buffer metadata and elements to GDB."""

def __init__(self, value: gdb.Value) -> None:
value = cccl_common.strip_reference_value(value)
self.value = value
self.type = value.type.strip_typedefs().unqualified()
self.type_name = memory_resource.public_type_name(self.type)
self.type = cccl_common.canonical_type(value.type)
self.type_name = cccl_common.public_type_name(self.type)
self.value_type = self.type.template_argument(0)

storage = value["__buf_"]
Expand Down
53 changes: 53 additions & 0 deletions libcudacxx/share/libcudacxx/gdb/cccl_common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

"""Type and value helpers shared by the CCCL GDB pretty printers."""

from __future__ import annotations

import re

import gdb

_ABI_NAMESPACE_PATTERN = re.compile(r"::__(?:\d+|version_bump_ver\d+_)(?=::)")
_REFERENCE_CODES = (gdb.TYPE_CODE_REF, gdb.TYPE_CODE_RVALUE_REF)


def public_type_name(value_type: gdb.Type) -> str:
"""Return a type name without CUDA ABI inline namespaces."""
return _ABI_NAMESPACE_PATTERN.sub("", str(value_type))


def template_name(value_type: gdb.Type | str) -> str:
"""Return the part of a type name before the template argument list."""
name = value_type if isinstance(value_type, str) else str(value_type)
return name.split("<", 1)[0]


def strip_reference(value_type: gdb.Type) -> gdb.Type:
"""Return the referenced type, or the type itself if it is not a reference.

target() gives the referenced type, but on a non-reference it either
resolves a typedef or raises, so test the type code first.
"""
if value_type.code in _REFERENCE_CODES:
return value_type.target()
return value_type


def strip_reference_value(value: gdb.Value) -> gdb.Value:
"""Return the referenced value, or the value itself if it is not a reference."""
if value.type.code in _REFERENCE_CODES:
return value.referenced_value()
return value


def canonical_type(value_type: gdb.Type) -> gdb.Type:
"""Return the type behind any reference, typedef, or cv-qualifier."""
return strip_reference(value_type).strip_typedefs().unqualified()


def canonical_type_name(value_type: gdb.Type) -> str:
"""Return the public name of the type behind any reference or typedef."""
return public_type_name(canonical_type(value_type))
15 changes: 6 additions & 9 deletions libcudacxx/share/libcudacxx/gdb/complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,31 +9,28 @@
from collections.abc import Iterator
from types import ModuleType

import memory_resource
import cccl_common

import gdb
import gdb.printing

_COMPLEX_NAMES = frozenset({"cuda::complex", "cuda::std::complex"})


def _template_name(type_name: str) -> str:
return type_name.split("<", 1)[0]


def _is_cuda_complex(value_type: gdb.Type) -> bool:
value_type = value_type.strip_typedefs().unqualified()
template_name = _template_name(memory_resource.public_type_name(value_type))
value_type = cccl_common.canonical_type(value_type)
template_name = cccl_common.template_name(cccl_common.public_type_name(value_type))
return template_name in _COMPLEX_NAMES


class ComplexPrinter:
"""Expose cuda::std::complex and cuda::complex parts to GDB."""

def __init__(self, value: gdb.Value) -> None:
value = cccl_common.strip_reference_value(value)
self.value = value
self.type = value.type.strip_typedefs().unqualified()
self.type_name = memory_resource.public_type_name(self.type)
self.type = cccl_common.canonical_type(value.type)
self.type_name = cccl_common.public_type_name(self.type)

def children(self) -> Iterator[tuple[str, gdb.Value]]:
yield "real", self.value["__re_"]
Expand Down
12 changes: 6 additions & 6 deletions libcudacxx/share/libcudacxx/gdb/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from collections.abc import Iterator
from types import ModuleType

import memory_resource
import cccl_common

import gdb
import gdb.printing
Expand All @@ -18,15 +18,14 @@


def _event_type_name(value_type: gdb.Type) -> str | None:
value_type = value_type.strip_typedefs().unqualified()
type_name = memory_resource.public_type_name(value_type)
type_name = cccl_common.canonical_type_name(value_type)
if type_name in _EVENT_NAMES:
return type_name
return None


def _event_handle(value: gdb.Value) -> gdb.Value:
value_type = value.type.strip_typedefs().unqualified()
value_type = cccl_common.canonical_type(value.type)
value = value.cast(value_type)
for field in value_type.fields():
if field.name == "__event_":
Expand All @@ -43,9 +42,10 @@ class EventPrinter:
"""Expose the native handle stored by a cuda event type."""

def __init__(self, value: gdb.Value) -> None:
value = cccl_common.strip_reference_value(value)
self.value = value
self.type = value.type.strip_typedefs().unqualified()
self.type_name = memory_resource.public_type_name(self.type)
self.type = cccl_common.canonical_type(value.type)
self.type_name = cccl_common.public_type_name(self.type)

def children(self) -> Iterator[tuple[str, gdb.Value]]:
yield "handle", _event_handle(self.value)
Expand Down
15 changes: 6 additions & 9 deletions libcudacxx/share/libcudacxx/gdb/inplace_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,26 @@
from collections.abc import Iterator
from types import ModuleType

import memory_resource
import cccl_common

import gdb
import gdb.printing


def _template_name(type_name: str) -> str:
return type_name.split("<", 1)[0]


def _is_cuda_inplace_vector(value_type: gdb.Type) -> bool:
value_type = value_type.strip_typedefs().unqualified()
template_name = _template_name(memory_resource.public_type_name(value_type))
value_type = cccl_common.canonical_type(value_type)
template_name = cccl_common.template_name(cccl_common.public_type_name(value_type))
return template_name == "cuda::std::inplace_vector"


class InplaceVectorPrinter:
"""Expose cuda::std::inplace_vector size and constructed elements to GDB."""

def __init__(self, value: gdb.Value) -> None:
value = cccl_common.strip_reference_value(value)
self.value = value
self.type = value.type.strip_typedefs().unqualified()
self.type_name = memory_resource.public_type_name(self.type)
self.type = cccl_common.canonical_type(value.type)
self.type_name = cccl_common.public_type_name(self.type)
self.element_type = self.type.template_argument(0)
self.capacity = int(self.type.template_argument(1))
# The zero-capacity specialization has no members at all; do not read any.
Expand Down
24 changes: 7 additions & 17 deletions libcudacxx/share/libcudacxx/gdb/memory_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,30 @@

from __future__ import annotations

import re
from types import ModuleType

import cccl_common

import gdb
import gdb.printing

_ABI_NAMESPACE_PATTERN = re.compile(r"::__(?:\d+|version_bump_ver\d+_)(?=::)")
_RESOURCE_NAMES = frozenset(
{"any_resource", "any_synchronous_resource", "basic_any_resource"}
)


def public_type_name(value_type: gdb.Type) -> str:
"""Return a type name without CUDA ABI inline namespaces."""
return _ABI_NAMESPACE_PATTERN.sub("", str(value_type))


def _template_name(value_type: gdb.Type) -> str:
return str(value_type).split("<", 1)[0]


def _is_memory_resource(value_type: gdb.Type) -> bool:
value_type = value_type.strip_typedefs().unqualified()
type_name = public_type_name(value_type)
template_name = _template_name(value_type)
value_type = cccl_common.canonical_type(value_type)
type_name = cccl_common.public_type_name(value_type)
return (
type_name.startswith("cuda::mr::")
and template_name.rsplit("::", 1)[-1] in _RESOURCE_NAMES
and cccl_common.template_name(value_type).rsplit("::", 1)[-1] in _RESOURCE_NAMES
)


def memory_resource_description(value: gdb.Value) -> str:
value_type = value.type.strip_typedefs().unqualified()
type_name = public_type_name(value_type)
value = cccl_common.strip_reference_value(value)
type_name = cccl_common.canonical_type_name(value.type)
try:
address = int(value.address)
except (gdb.error, TypeError):
Expand Down
14 changes: 5 additions & 9 deletions libcudacxx/share/libcudacxx/gdb/std_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,14 @@
from collections.abc import Iterator
from types import ModuleType

import memory_resource
import cccl_common

import gdb
import gdb.printing


def _template_name(value_type: gdb.Type) -> str:
return str(value_type).split("<", 1)[0]


def _is_cuda_array(value_type: gdb.Type) -> bool:
value_type = value_type.strip_typedefs().unqualified()
template_name = _template_name(value_type)
template_name = cccl_common.template_name(cccl_common.canonical_type(value_type))
return (
template_name.startswith("cuda::std::")
and template_name.rsplit("::", 1)[-1] == "array"
Expand All @@ -32,9 +27,10 @@ class ArrayPrinter:
"""Expose cuda::std::array metadata and elements to GDB."""

def __init__(self, value: gdb.Value) -> None:
value = cccl_common.strip_reference_value(value)
self.value = value
self.type = value.type.strip_typedefs().unqualified()
self.type_name = memory_resource.public_type_name(self.type)
self.type = cccl_common.canonical_type(value.type)
self.type_name = cccl_common.public_type_name(self.type)
self.size = int(self.type.template_argument(1))

def children(self) -> Iterator[tuple[str, gdb.Value]]:
Expand Down
6 changes: 3 additions & 3 deletions libcudacxx/share/libcudacxx/gdb/stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from types import ModuleType
from typing import NamedTuple

import memory_resource
import cccl_common

import gdb
import gdb.printing
Expand All @@ -37,8 +37,7 @@ class StreamInfo(NamedTuple):


def _stream_type_name(value_type: gdb.Type) -> str | None:
value_type = value_type.strip_typedefs().unqualified()
type_name = memory_resource.public_type_name(value_type)
type_name = cccl_common.canonical_type_name(value_type)
if type_name in _STREAM_TYPES:
return type_name
return None
Expand Down Expand Up @@ -166,6 +165,7 @@ class StreamPrinter:
"""Expose CUDA stream metadata to GDB."""

def __init__(self, value: gdb.Value, type_name: str) -> None:
value = cccl_common.strip_reference_value(value)
self.value = value
self.type_name = type_name
self.info = _stream_info(value["__stream"])
Expand Down
Loading
Loading