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}