Skip to main content

dxil_reader/
debug_info.rs

1//! Debug information as a program built with `-Zi` keeps it in its module (`-Qembed_debug`, or the `ILDB` part of a
2//! container): LLVM 3.7's `DI*` metadata nodes, read from their metadata records as dxc 1.9.2609's bitcode reader reads
3//! them, and the source location of each instruction ([`DebugLoc`]).
4//!
5//! A node's references to other metadata are metadata ids ([`MetadataId`], `None` for a null reference), strings
6//! included: a name is the id of a metadata string ([`crate::module::Metadata::String`]), and a reference to a value
7//! (a subprogram's function, a global variable's variable, a template parameter's value) is the id of a value as
8//! metadata ([`crate::module::Metadata::Value`]). Numbers keep LLVM's widths: a line, column, tag or flags word is the
9//! `unsigned` LLVM keeps (the low 32 bits of the record's operand), sizes and offsets are 64 bits.
10use crate::module::MetadataId;
11use crate::{Result, error};
12
13/// A debug-information node: one of LLVM 3.7's `DI*` metadata classes.
14#[derive(Clone, Debug, PartialEq, Eq)]
15pub enum DebugNode {
16    /// `DILocation`: a source position, in a scope, maybe inlined at another location.
17    Location {
18        /// The line (0 for none).
19        line: u32,
20        /// The column (0 for none, and where the record's does not fit in 16 bits).
21        column: u32,
22        /// The scope (a subprogram or lexical block).
23        scope: MetadataId,
24        /// The location of the call this one was inlined into.
25        inlined_at: Option<MetadataId>,
26    },
27    /// `GenericDINode`: a DWARF entry LLVM has no class for.
28    Generic {
29        /// Its DWARF tag.
30        tag: u32,
31        /// Its header string.
32        header: Option<MetadataId>,
33        /// Its DWARF operands.
34        operands: Vec<Option<MetadataId>>,
35    },
36    /// `DISubrange`: an array dimension.
37    Subrange {
38        /// The element count (-1 for an unknown count).
39        count: i64,
40        /// The first index.
41        lower_bound: i64,
42    },
43    /// `DIEnumerator`: one value of an enumeration.
44    Enumerator {
45        /// Its value.
46        value: i64,
47        /// Its name.
48        name: Option<MetadataId>,
49    },
50    /// `DIBasicType`: a scalar type.
51    BasicType {
52        /// Its DWARF tag (`DW_TAG_base_type` and `DW_TAG_unspecified_type`).
53        tag: u32,
54        /// Its name.
55        name: Option<MetadataId>,
56        /// Its size in bits.
57        size: u64,
58        /// Its alignment in bits.
59        align: u64,
60        /// Its encoding (`DW_ATE_*`).
61        encoding: u32,
62    },
63    /// `DIDerivedType`: a type made from another (a member, typedef, pointer, qualifier, ...).
64    DerivedType {
65        /// Its DWARF tag.
66        tag: u32,
67        /// Its name.
68        name: Option<MetadataId>,
69        /// Its file.
70        file: Option<MetadataId>,
71        /// Its line.
72        line: u32,
73        /// Its scope.
74        scope: Option<MetadataId>,
75        /// The type it derives from.
76        base_type: Option<MetadataId>,
77        /// Its size in bits.
78        size: u64,
79        /// Its alignment in bits.
80        align: u64,
81        /// Its offset in bits (a member's).
82        offset: u64,
83        /// Its `DIFlag*` bits.
84        flags: u32,
85        /// Extra data (a static member's value, a pointer to member's class, ...).
86        extra_data: Option<MetadataId>,
87    },
88    /// `DICompositeType`: a structure, class, union, array or enumeration.
89    CompositeType {
90        /// Its DWARF tag.
91        tag: u32,
92        /// Its name.
93        name: Option<MetadataId>,
94        /// Its file.
95        file: Option<MetadataId>,
96        /// Its line.
97        line: u32,
98        /// Its scope.
99        scope: Option<MetadataId>,
100        /// Its base type (an array's elements, an enumeration's underlying type).
101        base_type: Option<MetadataId>,
102        /// Its size in bits.
103        size: u64,
104        /// Its alignment in bits.
105        align: u64,
106        /// Its offset in bits.
107        offset: u64,
108        /// Its `DIFlag*` bits.
109        flags: u32,
110        /// Its members, enumerators or subranges (a node listing them).
111        elements: Option<MetadataId>,
112        /// Its runtime language (`DW_LANG_*`, 0 for none).
113        runtime_lang: u32,
114        /// The type holding its virtual table.
115        vtable_holder: Option<MetadataId>,
116        /// Its template parameters (a node listing them).
117        template_params: Option<MetadataId>,
118        /// Its unique identifier.
119        identifier: Option<MetadataId>,
120    },
121    /// `DISubroutineType`: a function type.
122    SubroutineType {
123        /// Its `DIFlag*` bits.
124        flags: u32,
125        /// Its return type and parameter types (a node listing them).
126        types: Option<MetadataId>,
127    },
128    /// `DIFile`: a source file.
129    File {
130        /// The file's name.
131        filename: Option<MetadataId>,
132        /// Its directory.
133        directory: Option<MetadataId>,
134    },
135    /// `DICompileUnit`: the compilation the program's debug information describes.
136    CompileUnit {
137        /// The source language (`DW_LANG_*`).
138        language: u32,
139        /// The main file.
140        file: Option<MetadataId>,
141        /// The compiler that made it.
142        producer: Option<MetadataId>,
143        /// Whether it was optimized.
144        optimized: bool,
145        /// The compiler's flags.
146        flags: Option<MetadataId>,
147        /// The runtime version.
148        runtime_version: u32,
149        /// The file split debug information goes to.
150        split_debug_filename: Option<MetadataId>,
151        /// How much debug information it emits (1 full, 2 line tables only).
152        emission_kind: u32,
153        /// Its enumeration types (a node listing them).
154        enums: Option<MetadataId>,
155        /// The types it keeps whether used or not.
156        retained_types: Option<MetadataId>,
157        /// Its subprograms.
158        subprograms: Option<MetadataId>,
159        /// Its global variables.
160        globals: Option<MetadataId>,
161        /// Its imported entities.
162        imports: Option<MetadataId>,
163        /// The split debug information's id.
164        dwo_id: u64,
165    },
166    /// `DISubprogram`: a function.
167    Subprogram {
168        /// Its scope.
169        scope: Option<MetadataId>,
170        /// Its name.
171        name: Option<MetadataId>,
172        /// Its linkage (decorated) name.
173        linkage_name: Option<MetadataId>,
174        /// Its file.
175        file: Option<MetadataId>,
176        /// Its line.
177        line: u32,
178        /// Its type.
179        ty: Option<MetadataId>,
180        /// It is local to the compilation unit.
181        local: bool,
182        /// It is a definition.
183        definition: bool,
184        /// The line its body's scope starts at.
185        scope_line: u32,
186        /// The type holding its virtual table entry.
187        containing_type: Option<MetadataId>,
188        /// Its virtuality (`DW_VIRTUALITY_*`).
189        virtuality: u32,
190        /// Its index in the virtual table.
191        virtual_index: u32,
192        /// Its `DIFlag*` bits.
193        flags: u32,
194        /// It was optimized.
195        optimized: bool,
196        /// The function it describes (a value as metadata).
197        function: Option<MetadataId>,
198        /// Its template parameters.
199        template_params: Option<MetadataId>,
200        /// Its declaration.
201        declaration: Option<MetadataId>,
202        /// Its variables.
203        variables: Option<MetadataId>,
204    },
205    /// `DILexicalBlock`: a block scope.
206    LexicalBlock {
207        /// The enclosing scope.
208        scope: Option<MetadataId>,
209        /// Its file.
210        file: Option<MetadataId>,
211        /// Its line.
212        line: u32,
213        /// Its column.
214        column: u32,
215    },
216    /// `DILexicalBlockFile`: a part of a scope in another file.
217    LexicalBlockFile {
218        /// The enclosing scope.
219        scope: Option<MetadataId>,
220        /// Its file.
221        file: Option<MetadataId>,
222        /// Its discriminator.
223        discriminator: u32,
224    },
225    /// `DINamespace`: a namespace.
226    Namespace {
227        /// The enclosing scope.
228        scope: Option<MetadataId>,
229        /// Its file.
230        file: Option<MetadataId>,
231        /// Its name.
232        name: Option<MetadataId>,
233        /// Its line.
234        line: u32,
235    },
236    /// `DIModule`: a module of the source language.
237    Module {
238        /// The enclosing scope.
239        scope: Option<MetadataId>,
240        /// Its name.
241        name: Option<MetadataId>,
242        /// Its configuration macros.
243        config_macros: Option<MetadataId>,
244        /// Its include path.
245        include_path: Option<MetadataId>,
246        /// Its system root.
247        isysroot: Option<MetadataId>,
248    },
249    /// `DITemplateTypeParameter`: a template's type parameter.
250    TemplateType {
251        /// Its name.
252        name: Option<MetadataId>,
253        /// Its type.
254        ty: Option<MetadataId>,
255    },
256    /// `DITemplateValueParameter`: a template's value parameter.
257    TemplateValue {
258        /// Its DWARF tag.
259        tag: u32,
260        /// Its name.
261        name: Option<MetadataId>,
262        /// Its type.
263        ty: Option<MetadataId>,
264        /// Its value.
265        value: Option<MetadataId>,
266    },
267    /// `DIGlobalVariable`: a global variable.
268    GlobalVariable {
269        /// Its scope.
270        scope: Option<MetadataId>,
271        /// Its name.
272        name: Option<MetadataId>,
273        /// Its linkage (decorated) name.
274        linkage_name: Option<MetadataId>,
275        /// Its file.
276        file: Option<MetadataId>,
277        /// Its line.
278        line: u32,
279        /// Its type.
280        ty: Option<MetadataId>,
281        /// It is local to the compilation unit.
282        local: bool,
283        /// It is a definition.
284        definition: bool,
285        /// The global it describes (a value as metadata).
286        variable: Option<MetadataId>,
287        /// A static data member's declaration.
288        declaration: Option<MetadataId>,
289    },
290    /// `DILocalVariable`: a local variable or parameter.
291    LocalVariable {
292        /// Its DWARF tag (`DW_TAG_auto_variable` or `DW_TAG_arg_variable`).
293        tag: u32,
294        /// Its scope.
295        scope: Option<MetadataId>,
296        /// Its name.
297        name: Option<MetadataId>,
298        /// Its file.
299        file: Option<MetadataId>,
300        /// Its line.
301        line: u32,
302        /// Its type.
303        ty: Option<MetadataId>,
304        /// A parameter's position (from 1; 0 for a variable).
305        arg: u32,
306        /// Its `DIFlag*` bits.
307        flags: u32,
308    },
309    /// `DIExpression`: how a variable's value is reached from what the debug intrinsic names: DWARF operations and their
310    /// arguments, as stored.
311    Expression(Vec<u64>),
312    /// `DIObjCProperty`: an Objective-C property.
313    ObjcProperty {
314        /// Its name.
315        name: Option<MetadataId>,
316        /// Its file.
317        file: Option<MetadataId>,
318        /// Its line.
319        line: u32,
320        /// Its getter's name.
321        getter: Option<MetadataId>,
322        /// Its setter's name.
323        setter: Option<MetadataId>,
324        /// Its attributes.
325        attributes: u32,
326        /// Its type.
327        ty: Option<MetadataId>,
328    },
329    /// `DIImportedEntity`: a `using` declaration or directive.
330    ImportedEntity {
331        /// Its DWARF tag.
332        tag: u32,
333        /// Its scope.
334        scope: Option<MetadataId>,
335        /// What it imports.
336        entity: Option<MetadataId>,
337        /// Its line.
338        line: u32,
339        /// Its name.
340        name: Option<MetadataId>,
341    },
342}
343
344/// An instruction's source location (`FUNC_CODE_DEBUG_LOC`): the fields of the `DILocation` it is.
345#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
346pub struct DebugLoc {
347    /// The line.
348    pub line: u32,
349    /// The column (0 where the record's does not fit in 16 bits).
350    pub column: u32,
351    /// The scope.
352    pub scope: Option<MetadataId>,
353    /// The location it was inlined at.
354    pub inlined_at: Option<MetadataId>,
355}
356
357/// An `unsigned` field of a record as LLVM reads it: the operand's low 32 bits.
358pub(crate) fn unsigned(v: u64) -> u32 {
359    u32::try_from(v & 0xFFFF_FFFF).unwrap_or(0)
360}
361
362/// LLVM's `adjustColumn`: a column of 16 bits or more is unknown.
363pub(crate) fn column(column: u32) -> u32 {
364    if column >= 1 << 16 { 0 } else { column }
365}
366
367impl DebugNode {
368    /// The node's metadata operands in the order LLVM keeps them (`MDNode::operands`, which numbering the nodes of a
369    /// listing walks), strings and null references included.
370    pub fn operands(&self) -> Vec<Option<MetadataId>> {
371        use DebugNode as N;
372        match self {
373            N::Location {
374                scope, inlined_at, ..
375            } => {
376                let mut ops = vec![Some(*scope)];
377                if inlined_at.is_some() {
378                    ops.push(*inlined_at);
379                }
380                ops
381            }
382            N::Generic { header, operands, .. } => {
383                let mut ops = vec![*header];
384                ops.extend(operands);
385                ops
386            }
387            N::Subrange { .. } | N::Expression(_) => Vec::new(),
388            N::Enumerator { name, .. } => vec![*name],
389            N::BasicType { name, .. } => vec![None, None, *name],
390            N::DerivedType {
391                file,
392                scope,
393                name,
394                base_type,
395                extra_data,
396                ..
397            } => {
398                vec![*file, *scope, *name, *base_type, *extra_data]
399            }
400            N::CompositeType {
401                file,
402                scope,
403                name,
404                base_type,
405                elements,
406                vtable_holder,
407                template_params,
408                identifier,
409                ..
410            } => vec![
411                *file,
412                *scope,
413                *name,
414                *base_type,
415                *elements,
416                *vtable_holder,
417                *template_params,
418                *identifier,
419            ],
420            N::SubroutineType { types, .. } => vec![None, None, None, None, *types, None, None, None],
421            N::File { filename, directory } => vec![*filename, *directory],
422            N::CompileUnit {
423                file,
424                producer,
425                flags,
426                split_debug_filename,
427                enums,
428                retained_types,
429                subprograms,
430                globals,
431                imports,
432                ..
433            } => vec![
434                *file,
435                *producer,
436                *flags,
437                *split_debug_filename,
438                *enums,
439                *retained_types,
440                *subprograms,
441                *globals,
442                *imports,
443            ],
444            N::Subprogram {
445                file,
446                scope,
447                name,
448                linkage_name,
449                ty,
450                containing_type,
451                function,
452                template_params,
453                declaration,
454                variables,
455                ..
456            } => vec![
457                *file,
458                *scope,
459                *name,
460                *name,
461                *linkage_name,
462                *ty,
463                *containing_type,
464                *function,
465                *template_params,
466                *declaration,
467                *variables,
468            ],
469            N::LexicalBlock { file, scope, .. } | N::LexicalBlockFile { file, scope, .. } => {
470                vec![*file, *scope]
471            }
472            N::Namespace {
473                file, scope, name, ..
474            } => vec![*file, *scope, *name],
475            N::Module {
476                scope,
477                name,
478                config_macros,
479                include_path,
480                isysroot,
481            } => {
482                vec![*scope, *name, *config_macros, *include_path, *isysroot]
483            }
484            N::TemplateType { name, ty } => vec![*name, *ty],
485            N::TemplateValue { name, ty, value, .. } => vec![*name, *ty, *value],
486            N::GlobalVariable {
487                scope,
488                name,
489                file,
490                ty,
491                linkage_name,
492                variable,
493                declaration,
494                ..
495            } => {
496                vec![
497                    *scope,
498                    *name,
499                    *file,
500                    *ty,
501                    *name,
502                    *linkage_name,
503                    *variable,
504                    *declaration,
505                ]
506            }
507            N::LocalVariable {
508                scope,
509                name,
510                file,
511                ty,
512                ..
513            } => vec![*scope, *name, *file, *ty],
514            N::ObjcProperty {
515                name,
516                file,
517                getter,
518                setter,
519                ty,
520                ..
521            } => vec![*name, *file, *getter, *setter, *ty],
522            N::ImportedEntity {
523                scope, entity, name, ..
524            } => vec![*scope, *entity, *name],
525        }
526    }
527
528    /// The scope a local variable or location names (`getScope`), for finding the subprogram it belongs to.
529    pub fn scope(&self) -> Option<MetadataId> {
530        use DebugNode as N;
531        match self {
532            N::Location { scope, .. } => Some(*scope),
533            N::LexicalBlock { scope, .. }
534            | N::LexicalBlockFile { scope, .. }
535            | N::LocalVariable { scope, .. }
536            | N::Subprogram { scope, .. } => *scope,
537            _ => None,
538        }
539    }
540}
541
542/// Reads the debug-information metadata record `code` (`METADATA_LOCATION` 7, `METADATA_GENERIC_DEBUG` 12 to
543/// `METADATA_MODULE` 32) of `ops` as dxc's bitcode reader does: whether the node is distinct (the first operand), and the
544/// node. A record of another length than its kind's is refused, as the reader refuses it.
545pub(crate) fn read(code: u32, ops: &[u64], at: usize) -> Result<(bool, DebugNode)> {
546    let n = |i: usize| -> Result<u64> {
547        ops.get(i)
548            .copied()
549            .ok_or_else(|| error(at, format!("metadata record {code} lacks operand {i}")))
550    };
551    let u = |i: usize| -> Result<u32> { n(i).map(unsigned) };
552    let id = |v: u64| -> Result<MetadataId> { usize::try_from(v).map_err(|_| error(at, "metadata id")) };
553    // `getMDOrNull`: the id plus one, or 0 for null
554    let md = |i: usize| -> Result<Option<MetadataId>> {
555        match n(i)? {
556            0 => Ok(None),
557            v => id(v.saturating_sub(1)).map(Some),
558        }
559    };
560    let length = |want: &[usize]| -> Result<()> {
561        if want.contains(&ops.len()) {
562            Ok(())
563        } else {
564            Err(error(
565                at,
566                format!("metadata record {code} of {} operands", ops.len()),
567            ))
568        }
569    };
570    let distinct = n(0)? != 0;
571    use DebugNode as N;
572    let node = match code {
573        7 => {
574            length(&[5])?;
575            N::Location {
576                line: u(1)?,
577                column: column(u(2)?),
578                // the scope is not optional: its id is stored as is
579                scope: id(n(3)?)?,
580                inlined_at: md(4)?,
581            }
582        }
583        12 => {
584            if ops.len() < 4 {
585                return Err(error(
586                    at,
587                    format!("metadata record {code} of {} operands", ops.len()),
588                ));
589            }
590            let tag = u16::try_from(n(1)?).ok().filter(|_| n(2).is_ok_and(|v| v == 0));
591            let Some(tag) = tag else {
592                return Err(error(at, "a generic debug node of an unknown tag or version"));
593            };
594            N::Generic {
595                tag: u32::from(tag),
596                header: md(3)?,
597                operands: (4..ops.len()).map(md).collect::<Result<_>>()?,
598            }
599        }
600        13 => {
601            length(&[3])?;
602            N::Subrange {
603                count: n(1)? as i64,
604                lower_bound: unrotate(n(2)?),
605            }
606        }
607        14 => {
608            length(&[3])?;
609            N::Enumerator {
610                value: unrotate(n(1)?),
611                name: md(2)?,
612            }
613        }
614        15 => {
615            length(&[6])?;
616            N::BasicType {
617                tag: u(1)?,
618                name: md(2)?,
619                size: n(3)?,
620                align: n(4)?,
621                encoding: u(5)?,
622            }
623        }
624        17 => {
625            length(&[12])?;
626            N::DerivedType {
627                tag: u(1)?,
628                name: md(2)?,
629                file: md(3)?,
630                line: u(4)?,
631                scope: md(5)?,
632                base_type: md(6)?,
633                size: n(7)?,
634                align: n(8)?,
635                offset: n(9)?,
636                flags: u(10)?,
637                extra_data: md(11)?,
638            }
639        }
640        18 => {
641            length(&[16])?;
642            N::CompositeType {
643                tag: u(1)?,
644                name: md(2)?,
645                file: md(3)?,
646                line: u(4)?,
647                scope: md(5)?,
648                base_type: md(6)?,
649                size: n(7)?,
650                align: n(8)?,
651                offset: n(9)?,
652                flags: u(10)?,
653                elements: md(11)?,
654                runtime_lang: u(12)?,
655                vtable_holder: md(13)?,
656                template_params: md(14)?,
657                identifier: md(15)?,
658            }
659        }
660        19 => {
661            length(&[3])?;
662            N::SubroutineType {
663                flags: u(1)?,
664                types: md(2)?,
665            }
666        }
667        32 => {
668            length(&[6])?;
669            N::Module {
670                scope: md(1)?,
671                name: md(2)?,
672                config_macros: md(3)?,
673                include_path: md(4)?,
674                isysroot: md(5)?,
675            }
676        }
677        16 => {
678            length(&[3])?;
679            N::File {
680                filename: md(1)?,
681                directory: md(2)?,
682            }
683        }
684        20 => {
685            length(&[14, 15])?;
686            N::CompileUnit {
687                language: u(1)?,
688                file: md(2)?,
689                producer: md(3)?,
690                optimized: n(4)? != 0,
691                flags: md(5)?,
692                runtime_version: u(6)?,
693                split_debug_filename: md(7)?,
694                emission_kind: u(8)?,
695                enums: md(9)?,
696                retained_types: md(10)?,
697                subprograms: md(11)?,
698                globals: md(12)?,
699                imports: md(13)?,
700                dwo_id: ops.get(14).copied().unwrap_or(0),
701            }
702        }
703        21 => {
704            length(&[19])?;
705            N::Subprogram {
706                scope: md(1)?,
707                name: md(2)?,
708                linkage_name: md(3)?,
709                file: md(4)?,
710                line: u(5)?,
711                ty: md(6)?,
712                local: n(7)? != 0,
713                definition: n(8)? != 0,
714                scope_line: u(9)?,
715                containing_type: md(10)?,
716                virtuality: u(11)?,
717                virtual_index: u(12)?,
718                flags: u(13)?,
719                optimized: n(14)? != 0,
720                function: md(15)?,
721                template_params: md(16)?,
722                declaration: md(17)?,
723                variables: md(18)?,
724            }
725        }
726        22 => {
727            length(&[5])?;
728            N::LexicalBlock {
729                scope: md(1)?,
730                file: md(2)?,
731                line: u(3)?,
732                column: u(4)?,
733            }
734        }
735        23 => {
736            length(&[4])?;
737            N::LexicalBlockFile {
738                scope: md(1)?,
739                file: md(2)?,
740                discriminator: u(3)?,
741            }
742        }
743        24 => {
744            length(&[5])?;
745            N::Namespace {
746                scope: md(1)?,
747                file: md(2)?,
748                name: md(3)?,
749                line: u(4)?,
750            }
751        }
752        25 => {
753            length(&[3])?;
754            N::TemplateType {
755                name: md(1)?,
756                ty: md(2)?,
757            }
758        }
759        26 => {
760            length(&[5])?;
761            N::TemplateValue {
762                tag: u(1)?,
763                name: md(2)?,
764                ty: md(3)?,
765                value: md(4)?,
766            }
767        }
768        27 => {
769            length(&[11])?;
770            N::GlobalVariable {
771                scope: md(1)?,
772                name: md(2)?,
773                linkage_name: md(3)?,
774                file: md(4)?,
775                line: u(5)?,
776                ty: md(6)?,
777                local: n(7)? != 0,
778                definition: n(8)? != 0,
779                variable: md(9)?,
780                declaration: md(10)?,
781            }
782        }
783        28 => {
784            // a tenth operand is the obsolete `inlinedAt`, which the reader drops
785            length(&[9, 10])?;
786            N::LocalVariable {
787                tag: u(1)?,
788                scope: md(2)?,
789                name: md(3)?,
790                file: md(4)?,
791                line: u(5)?,
792                ty: md(6)?,
793                arg: u(7)?,
794                flags: u(8)?,
795            }
796        }
797        29 => N::Expression(ops.get(1..).unwrap_or_default().to_vec()),
798        30 => {
799            length(&[8])?;
800            N::ObjcProperty {
801                name: md(1)?,
802                file: md(2)?,
803                line: u(3)?,
804                getter: md(4)?,
805                setter: md(5)?,
806                attributes: u(6)?,
807                ty: md(7)?,
808            }
809        }
810        31 => {
811            length(&[6])?;
812            N::ImportedEntity {
813                tag: u(1)?,
814                scope: md(2)?,
815                entity: md(3)?,
816                line: u(4)?,
817                name: md(5)?,
818            }
819        }
820        other => {
821            return Err(error(
822                at,
823                format!("metadata record {other} is not debug information"),
824            ));
825        }
826    };
827    Ok((distinct, node))
828}
829
830/// `unrotateSign`: a signed number stored with its sign in the low bit, the rest complemented for a negative one (the
831/// metadata's encoding, not the instructions' `decodeSignRotatedValue`).
832fn unrotate(v: u64) -> i64 {
833    let magnitude = (v >> 1) as i64;
834    if v & 1 == 0 { magnitude } else { !magnitude }
835}