Skip to content

Commit a2e304b

Browse files
authored
fix: make strings distinguishable from char arrays in debug info (#1496)
This PR changes how DWARF debug information is generated for STRING types. Strings are now generated as aliased types in debug info, where the alias points to the underlying character array type. The aliases follow a naming scheme, __[W]STRING__<size>, such that they can be distinguished from regular character arrays by tools which rely on parsing debug information. Since these are aliased types, regular debugging functionality remains unaffected since debuggers will resolve aliased types to their base-types.
1 parent 075f404 commit a2e304b

6 files changed

+359
-329
lines changed

src/codegen/debug.rs

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,18 @@ impl<'ink> DebugBuilder<'ink> {
443443
.map(|it| it.to_owned())
444444
}
445445

446+
/// Creates debug information for string types using an array + typedef approach.
447+
///
448+
/// This function generates DWARF debug metadata for string types by creating:
449+
/// 1. A character array type based on the string's encoding (CHAR for UTF-8, WCHAR for UTF-16)
450+
/// 2. A typedef with a unique name based on encoding and length (e.g., "__STRING__81", "__WSTRING__26")
451+
///
452+
/// ## Typedef Naming
453+
///
454+
/// The typedef uses the `__STRING__<grapheme count>` or `__WSTRING__<grapheme count>` pattern where:
455+
/// - Double underscore prefix avoids clashing with user-defined types (reserved for compiler internals)
456+
/// - Length suffix ensures each string type has a unique DWARF reference
457+
/// - Consistent pattern enables easy detection by DWARF parsers
446458
fn create_string_type(
447459
&mut self,
448460
name: &str,
@@ -452,24 +464,37 @@ impl<'ink> DebugBuilder<'ink> {
452464
index: &Index,
453465
types_index: &LlvmTypedIndex,
454466
) -> Result<(), Diagnostic> {
455-
// Register a utf8 or 16 basic type
456-
let inner_type = match encoding {
467+
let char_datatype = match encoding {
457468
StringEncoding::Utf8 => index.get_effective_type_or_void_by_name(CHAR_TYPE),
458469
StringEncoding::Utf16 => index.get_effective_type_or_void_by_name(WCHAR_TYPE),
459470
};
460-
let inner_type = self.get_or_create_debug_type(inner_type, index, types_index)?;
461-
let llvm_type = types_index.get_associated_type(name)?;
462-
let align_bits = self.target_data.get_preferred_alignment(&llvm_type) * 8;
463-
//Register an array
471+
472+
let char_debug_type = self.get_or_create_debug_type(char_datatype, index, types_index)?;
473+
let array_align_bits =
474+
self.target_data.get_preferred_alignment(&types_index.get_associated_type(name)?) * 8;
464475
let array_type = self.debug_info.create_array_type(
465-
inner_type.into(),
476+
char_debug_type.into(),
466477
size,
467-
align_bits,
478+
array_align_bits,
468479
#[allow(clippy::single_range_in_vec_init)]
469-
&[(0..length)],
480+
&[0..length],
470481
);
482+
let typedef_name = match encoding {
483+
StringEncoding::Utf8 => format!("__STRING__{}", length),
484+
StringEncoding::Utf16 => format!("__WSTRING__{}", length),
485+
};
471486

472-
self.register_concrete_type(name, DebugType::Composite(array_type));
487+
let file = self.compile_unit.get_file();
488+
let string_typedef = self.debug_info.create_typedef(
489+
array_type.as_type(),
490+
&typedef_name,
491+
file,
492+
0, // Line 0 for built-in types
493+
file.as_debug_info_scope(),
494+
array_align_bits,
495+
);
496+
497+
self.register_concrete_type(name, DebugType::Derived(string_typedef));
473498
Ok(())
474499
}
475500

0 commit comments

Comments
 (0)