1use alloc::vec::Vec;
2use core::num::{NonZeroU64, Wrapping};
3
4use crate::common::{
5 DebugLineOffset, DebugLineStrOffset, DebugStrOffset, DebugStrOffsetsIndex, Encoding, Format,
6 LineEncoding, SectionId,
7};
8use crate::constants;
9use crate::endianity::Endianity;
10use crate::read::{
11 AttributeValue, EndianSlice, Error, Reader, ReaderAddress, ReaderOffset, Result, Section,
12};
13
14#[derive(Debug, Default, Clone, Copy)]
17pub struct DebugLine<R> {
18 debug_line_section: R,
19}
20
21impl<'input, Endian> DebugLine<EndianSlice<'input, Endian>>
22where
23 Endian: Endianity,
24{
25 pub fn new(debug_line_section: &'input [u8], endian: Endian) -> Self {
40 Self::from(EndianSlice::new(debug_line_section, endian))
41 }
42}
43
44impl<R: Reader> DebugLine<R> {
45 pub fn program(
70 &self,
71 offset: DebugLineOffset<R::Offset>,
72 address_size: u8,
73 comp_dir: Option<R>,
74 comp_name: Option<R>,
75 ) -> Result<IncompleteLineProgram<R>> {
76 let input = &mut self.debug_line_section.clone();
77 input.skip(offset.0)?;
78 let header = LineProgramHeader::parse(input, offset, address_size, comp_dir, comp_name)?;
79 let program = IncompleteLineProgram { header };
80 Ok(program)
81 }
82}
83
84impl<T> DebugLine<T> {
85 pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> DebugLine<R>
91 where
92 F: FnMut(&'a T) -> R,
93 {
94 borrow(&self.debug_line_section).into()
95 }
96}
97
98impl<R> Section<R> for DebugLine<R> {
99 fn id() -> SectionId {
100 SectionId::DebugLine
101 }
102
103 fn reader(&self) -> &R {
104 &self.debug_line_section
105 }
106}
107
108impl<R> From<R> for DebugLine<R> {
109 fn from(debug_line_section: R) -> Self {
110 DebugLine { debug_line_section }
111 }
112}
113
114#[deprecated(note = "LineNumberProgram has been renamed to LineProgram, use that instead.")]
116pub type LineNumberProgram<R, Offset> = dyn LineProgram<R, Offset>;
117
118pub trait LineProgram<R, Offset = <R as Reader>::Offset>
122where
123 R: Reader<Offset = Offset>,
124 Offset: ReaderOffset,
125{
126 fn header(&self) -> &LineProgramHeader<R, Offset>;
128 fn add_file(&mut self, file: FileEntry<R, Offset>);
130}
131
132impl<R, Offset> LineProgram<R, Offset> for IncompleteLineProgram<R, Offset>
133where
134 R: Reader<Offset = Offset>,
135 Offset: ReaderOffset,
136{
137 fn header(&self) -> &LineProgramHeader<R, Offset> {
138 &self.header
139 }
140 fn add_file(&mut self, file: FileEntry<R, Offset>) {
141 self.header.file_names.push(file);
142 }
143}
144
145impl<'program, R, Offset> LineProgram<R, Offset> for &'program CompleteLineProgram<R, Offset>
146where
147 R: Reader<Offset = Offset>,
148 Offset: ReaderOffset,
149{
150 fn header(&self) -> &LineProgramHeader<R, Offset> {
151 &self.header
152 }
153 fn add_file(&mut self, _: FileEntry<R, Offset>) {
154 }
156}
157
158#[deprecated(note = "StateMachine has been renamed to LineRows, use that instead.")]
160pub type StateMachine<R, Program, Offset> = LineRows<R, Program, Offset>;
161
162#[derive(Debug, Clone)]
168pub struct LineRows<R, Program, Offset = <R as Reader>::Offset>
169where
170 Program: LineProgram<R, Offset>,
171 R: Reader<Offset = Offset>,
172 Offset: ReaderOffset,
173{
174 program: Program,
175 row: LineRow,
176 instructions: LineInstructions<R>,
177}
178
179type OneShotLineRows<R, Offset = <R as Reader>::Offset> =
180 LineRows<R, IncompleteLineProgram<R, Offset>, Offset>;
181
182type ResumedLineRows<'program, R, Offset = <R as Reader>::Offset> =
183 LineRows<R, &'program CompleteLineProgram<R, Offset>, Offset>;
184
185impl<R, Program, Offset> LineRows<R, Program, Offset>
186where
187 Program: LineProgram<R, Offset>,
188 R: Reader<Offset = Offset>,
189 Offset: ReaderOffset,
190{
191 fn new(program: IncompleteLineProgram<R, Offset>) -> OneShotLineRows<R, Offset> {
192 let row = LineRow::new(program.header());
193 let instructions = LineInstructions {
194 input: program.header().program_buf.clone(),
195 };
196 LineRows {
197 program,
198 row,
199 instructions,
200 }
201 }
202
203 fn resume<'program>(
204 program: &'program CompleteLineProgram<R, Offset>,
205 sequence: &LineSequence<R>,
206 ) -> ResumedLineRows<'program, R, Offset> {
207 let row = LineRow::new(program.header());
208 let instructions = sequence.instructions.clone();
209 LineRows {
210 program,
211 row,
212 instructions,
213 }
214 }
215
216 #[inline]
219 pub fn header(&self) -> &LineProgramHeader<R, Offset> {
220 self.program.header()
221 }
222
223 pub fn next_row(&mut self) -> Result<Option<(&LineProgramHeader<R, Offset>, &LineRow)>> {
234 self.row.reset(self.program.header());
236
237 loop {
238 match self.instructions.next_instruction(self.program.header()) {
240 Err(err) => return Err(err),
241 Ok(None) => return Ok(None),
242 Ok(Some(instruction)) => {
243 if self.row.execute(instruction, &mut self.program)? {
244 if self.row.tombstone {
245 self.row.reset(self.program.header());
249 } else {
250 return Ok(Some((self.header(), &self.row)));
251 }
252 }
253 }
256 }
257 }
258 }
259}
260
261#[deprecated(note = "Opcode has been renamed to LineInstruction, use that instead.")]
263pub type Opcode<R> = LineInstruction<R, <R as Reader>::Offset>;
264
265#[derive(Clone, Copy, Debug, PartialEq, Eq)]
267pub enum LineInstruction<R, Offset = <R as Reader>::Offset>
268where
269 R: Reader<Offset = Offset>,
270 Offset: ReaderOffset,
271{
272 Special(u8),
296
297 Copy,
302
303 AdvancePc(u64),
307
308 AdvanceLine(i64),
311
312 SetFile(u64),
315
316 SetColumn(u64),
319
320 NegateStatement,
324
325 SetBasicBlock,
328
329 ConstAddPc,
341
342 FixedAddPc(u16),
348
349 SetPrologueEnd,
351
352 SetEpilogueBegin,
355
356 SetIsa(u64),
359
360 UnknownStandard0(constants::DwLns),
362
363 UnknownStandard1(constants::DwLns, u64),
365
366 UnknownStandardN(constants::DwLns, R),
368
369 EndSequence,
377
378 SetAddress(u64),
387
388 DefineFile(FileEntry<R, Offset>),
391
392 SetDiscriminator(u64),
396
397 UnknownExtended(constants::DwLne, R),
399}
400
401impl<R, Offset> LineInstruction<R, Offset>
402where
403 R: Reader<Offset = Offset>,
404 Offset: ReaderOffset,
405{
406 fn parse<'header>(
407 header: &'header LineProgramHeader<R>,
408 input: &mut R,
409 ) -> Result<LineInstruction<R>>
410 where
411 R: 'header,
412 {
413 let opcode = input.read_u8()?;
414 if opcode == 0 {
415 let length = input.read_uleb128().and_then(R::Offset::from_u64)?;
416 let mut instr_rest = input.split(length)?;
417 let opcode = instr_rest.read_u8()?;
418
419 match constants::DwLne(opcode) {
420 constants::DW_LNE_end_sequence => Ok(LineInstruction::EndSequence),
421
422 constants::DW_LNE_set_address => {
423 let address = instr_rest.read_address(header.address_size())?;
424 Ok(LineInstruction::SetAddress(address))
425 }
426
427 constants::DW_LNE_define_file => {
428 if header.version() <= 4 {
429 let path_name = instr_rest.read_null_terminated_slice()?;
430 let entry = FileEntry::parse(&mut instr_rest, path_name)?;
431 Ok(LineInstruction::DefineFile(entry))
432 } else {
433 Ok(LineInstruction::UnknownExtended(
434 constants::DW_LNE_define_file,
435 instr_rest,
436 ))
437 }
438 }
439
440 constants::DW_LNE_set_discriminator => {
441 let discriminator = instr_rest.read_uleb128()?;
442 Ok(LineInstruction::SetDiscriminator(discriminator))
443 }
444
445 otherwise => Ok(LineInstruction::UnknownExtended(otherwise, instr_rest)),
446 }
447 } else if opcode >= header.opcode_base {
448 Ok(LineInstruction::Special(opcode))
449 } else {
450 match constants::DwLns(opcode) {
451 constants::DW_LNS_copy => Ok(LineInstruction::Copy),
452
453 constants::DW_LNS_advance_pc => {
454 let advance = input.read_uleb128()?;
455 Ok(LineInstruction::AdvancePc(advance))
456 }
457
458 constants::DW_LNS_advance_line => {
459 let increment = input.read_sleb128()?;
460 Ok(LineInstruction::AdvanceLine(increment))
461 }
462
463 constants::DW_LNS_set_file => {
464 let file = input.read_uleb128()?;
465 Ok(LineInstruction::SetFile(file))
466 }
467
468 constants::DW_LNS_set_column => {
469 let column = input.read_uleb128()?;
470 Ok(LineInstruction::SetColumn(column))
471 }
472
473 constants::DW_LNS_negate_stmt => Ok(LineInstruction::NegateStatement),
474
475 constants::DW_LNS_set_basic_block => Ok(LineInstruction::SetBasicBlock),
476
477 constants::DW_LNS_const_add_pc => Ok(LineInstruction::ConstAddPc),
478
479 constants::DW_LNS_fixed_advance_pc => {
480 let advance = input.read_u16()?;
481 Ok(LineInstruction::FixedAddPc(advance))
482 }
483
484 constants::DW_LNS_set_prologue_end => Ok(LineInstruction::SetPrologueEnd),
485
486 constants::DW_LNS_set_epilogue_begin => Ok(LineInstruction::SetEpilogueBegin),
487
488 constants::DW_LNS_set_isa => {
489 let isa = input.read_uleb128()?;
490 Ok(LineInstruction::SetIsa(isa))
491 }
492
493 otherwise => {
494 let mut opcode_lengths = header.standard_opcode_lengths().clone();
495 opcode_lengths.skip(R::Offset::from_u8(opcode - 1))?;
496 let num_args = opcode_lengths.read_u8()? as usize;
497 match num_args {
498 0 => Ok(LineInstruction::UnknownStandard0(otherwise)),
499 1 => {
500 let arg = input.read_uleb128()?;
501 Ok(LineInstruction::UnknownStandard1(otherwise, arg))
502 }
503 _ => {
504 let mut args = input.clone();
505 for _ in 0..num_args {
506 input.read_uleb128()?;
507 }
508 let len = input.offset_from(&args);
509 args.truncate(len)?;
510 Ok(LineInstruction::UnknownStandardN(otherwise, args))
511 }
512 }
513 }
514 }
515 }
516 }
517}
518
519#[deprecated(note = "OpcodesIter has been renamed to LineInstructions, use that instead.")]
521pub type OpcodesIter<R> = LineInstructions<R>;
522
523#[derive(Clone, Debug)]
529pub struct LineInstructions<R: Reader> {
530 input: R,
531}
532
533impl<R: Reader> LineInstructions<R> {
534 fn remove_trailing(&self, other: &LineInstructions<R>) -> Result<LineInstructions<R>> {
535 let offset = other.input.offset_from(&self.input);
536 let mut input = self.input.clone();
537 input.truncate(offset)?;
538 Ok(LineInstructions { input })
539 }
540}
541
542impl<R: Reader> LineInstructions<R> {
543 #[inline(always)]
554 pub fn next_instruction(
555 &mut self,
556 header: &LineProgramHeader<R>,
557 ) -> Result<Option<LineInstruction<R>>> {
558 if self.input.is_empty() {
559 return Ok(None);
560 }
561
562 match LineInstruction::parse(header, &mut self.input) {
563 Ok(instruction) => Ok(Some(instruction)),
564 Err(e) => {
565 self.input.empty();
566 Err(e)
567 }
568 }
569 }
570}
571
572#[deprecated(note = "LineNumberRow has been renamed to LineRow, use that instead.")]
574pub type LineNumberRow = LineRow;
575
576#[derive(Clone, Copy, Debug, PartialEq, Eq)]
580pub struct LineRow {
581 tombstone: bool,
582 address: u64,
583 op_index: Wrapping<u64>,
584 file: u64,
585 line: Wrapping<u64>,
586 column: u64,
587 is_stmt: bool,
588 basic_block: bool,
589 end_sequence: bool,
590 prologue_end: bool,
591 epilogue_begin: bool,
592 isa: u64,
593 discriminator: u64,
594}
595
596impl LineRow {
597 pub fn new<R: Reader>(header: &LineProgramHeader<R>) -> Self {
599 LineRow {
600 tombstone: false,
603 address: 0,
604 op_index: Wrapping(0),
605 file: 1,
606 line: Wrapping(1),
607 column: 0,
608 is_stmt: header.line_encoding.default_is_stmt,
610 basic_block: false,
611 end_sequence: false,
612 prologue_end: false,
613 epilogue_begin: false,
614 isa: 0,
619 discriminator: 0,
620 }
621 }
622
623 #[inline]
626 pub fn address(&self) -> u64 {
627 self.address
628 }
629
630 #[inline]
638 pub fn op_index(&self) -> u64 {
639 self.op_index.0
640 }
641
642 #[inline]
645 pub fn file_index(&self) -> u64 {
646 self.file
647 }
648
649 #[inline]
651 pub fn file<'header, R: Reader>(
652 &self,
653 header: &'header LineProgramHeader<R>,
654 ) -> Option<&'header FileEntry<R>> {
655 header.file(self.file)
656 }
657
658 #[inline]
663 pub fn line(&self) -> Option<NonZeroU64> {
664 NonZeroU64::new(self.line.0)
665 }
666
667 #[inline]
671 pub fn column(&self) -> ColumnType {
672 NonZeroU64::new(self.column)
673 .map(ColumnType::Column)
674 .unwrap_or(ColumnType::LeftEdge)
675 }
676
677 #[inline]
682 pub fn is_stmt(&self) -> bool {
683 self.is_stmt
684 }
685
686 #[inline]
689 pub fn basic_block(&self) -> bool {
690 self.basic_block
691 }
692
693 #[inline]
698 pub fn end_sequence(&self) -> bool {
699 self.end_sequence
700 }
701
702 #[inline]
706 pub fn prologue_end(&self) -> bool {
707 self.prologue_end
708 }
709
710 #[inline]
714 pub fn epilogue_begin(&self) -> bool {
715 self.epilogue_begin
716 }
717
718 #[inline]
727 pub fn isa(&self) -> u64 {
728 self.isa
729 }
730
731 #[inline]
738 pub fn discriminator(&self) -> u64 {
739 self.discriminator
740 }
741
742 #[inline]
747 pub fn execute<R, Program>(
748 &mut self,
749 instruction: LineInstruction<R>,
750 program: &mut Program,
751 ) -> Result<bool>
752 where
753 Program: LineProgram<R>,
754 R: Reader,
755 {
756 Ok(match instruction {
757 LineInstruction::Special(opcode) => {
758 self.exec_special_opcode(opcode, program.header())?;
759 true
760 }
761
762 LineInstruction::Copy => true,
763
764 LineInstruction::AdvancePc(operation_advance) => {
765 self.apply_operation_advance(operation_advance, program.header())?;
766 false
767 }
768
769 LineInstruction::AdvanceLine(line_increment) => {
770 self.apply_line_advance(line_increment);
771 false
772 }
773
774 LineInstruction::SetFile(file) => {
775 self.file = file;
776 false
777 }
778
779 LineInstruction::SetColumn(column) => {
780 self.column = column;
781 false
782 }
783
784 LineInstruction::NegateStatement => {
785 self.is_stmt = !self.is_stmt;
786 false
787 }
788
789 LineInstruction::SetBasicBlock => {
790 self.basic_block = true;
791 false
792 }
793
794 LineInstruction::ConstAddPc => {
795 let adjusted = self.adjust_opcode(255, program.header());
796 let operation_advance = adjusted / program.header().line_encoding.line_range;
797 self.apply_operation_advance(u64::from(operation_advance), program.header())?;
798 false
799 }
800
801 LineInstruction::FixedAddPc(operand) => {
802 if !self.tombstone {
803 let address_size = program.header().address_size();
804 self.address = self.address.add_sized(u64::from(operand), address_size)?;
805 self.op_index.0 = 0;
806 }
807 false
808 }
809
810 LineInstruction::SetPrologueEnd => {
811 self.prologue_end = true;
812 false
813 }
814
815 LineInstruction::SetEpilogueBegin => {
816 self.epilogue_begin = true;
817 false
818 }
819
820 LineInstruction::SetIsa(isa) => {
821 self.isa = isa;
822 false
823 }
824
825 LineInstruction::EndSequence => {
826 self.end_sequence = true;
827 true
828 }
829
830 LineInstruction::SetAddress(address) => {
831 let tombstone_address = !0 >> (64 - program.header().encoding.address_size * 8);
832 self.tombstone = address == tombstone_address;
833 if !self.tombstone {
834 if address < self.address {
835 return Err(Error::InvalidAddressRange);
836 }
837 self.address = address;
838 self.op_index.0 = 0;
839 }
840 false
841 }
842
843 LineInstruction::DefineFile(entry) => {
844 program.add_file(entry);
845 false
846 }
847
848 LineInstruction::SetDiscriminator(discriminator) => {
849 self.discriminator = discriminator;
850 false
851 }
852
853 LineInstruction::UnknownStandard0(_)
855 | LineInstruction::UnknownStandard1(_, _)
856 | LineInstruction::UnknownStandardN(_, _)
857 | LineInstruction::UnknownExtended(_, _) => false,
858 })
859 }
860
861 #[inline]
863 pub fn reset<R: Reader>(&mut self, header: &LineProgramHeader<R>) {
864 if self.end_sequence {
865 *self = Self::new(header);
868 } else {
869 self.discriminator = 0;
874 self.basic_block = false;
875 self.prologue_end = false;
876 self.epilogue_begin = false;
877 }
878 }
879
880 fn apply_line_advance(&mut self, line_increment: i64) {
882 if line_increment < 0 {
883 let decrement = -line_increment as u64;
884 if decrement <= self.line.0 {
885 self.line.0 -= decrement;
886 } else {
887 self.line.0 = 0;
888 }
889 } else {
890 self.line += Wrapping(line_increment as u64);
891 }
892 }
893
894 fn apply_operation_advance<R: Reader>(
896 &mut self,
897 operation_advance: u64,
898 header: &LineProgramHeader<R>,
899 ) -> Result<()> {
900 if self.tombstone {
901 return Ok(());
902 }
903
904 let operation_advance = Wrapping(operation_advance);
905
906 let minimum_instruction_length = u64::from(header.line_encoding.minimum_instruction_length);
907 let minimum_instruction_length = Wrapping(minimum_instruction_length);
908
909 let maximum_operations_per_instruction =
910 u64::from(header.line_encoding.maximum_operations_per_instruction);
911 let maximum_operations_per_instruction = Wrapping(maximum_operations_per_instruction);
912
913 let address_advance = if maximum_operations_per_instruction.0 == 1 {
914 self.op_index.0 = 0;
915 minimum_instruction_length * operation_advance
916 } else {
917 let op_index_with_advance = self.op_index + operation_advance;
918 self.op_index = op_index_with_advance % maximum_operations_per_instruction;
919 minimum_instruction_length
920 * (op_index_with_advance / maximum_operations_per_instruction)
921 };
922 self.address = self
923 .address
924 .add_sized(address_advance.0, header.address_size())?;
925 Ok(())
926 }
927
928 #[inline]
929 fn adjust_opcode<R: Reader>(&self, opcode: u8, header: &LineProgramHeader<R>) -> u8 {
930 opcode - header.opcode_base
931 }
932
933 fn exec_special_opcode<R: Reader>(
935 &mut self,
936 opcode: u8,
937 header: &LineProgramHeader<R>,
938 ) -> Result<()> {
939 let adjusted_opcode = self.adjust_opcode(opcode, header);
940
941 let line_range = header.line_encoding.line_range;
942 let line_advance = adjusted_opcode % line_range;
943 let operation_advance = adjusted_opcode / line_range;
944
945 let line_base = i64::from(header.line_encoding.line_base);
947 self.apply_line_advance(line_base + i64::from(line_advance));
948
949 self.apply_operation_advance(u64::from(operation_advance), header)?;
951 Ok(())
952 }
953}
954
955#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
957pub enum ColumnType {
958 LeftEdge,
961 Column(NonZeroU64),
963}
964
965#[deprecated(note = "LineNumberSequence has been renamed to LineSequence, use that instead.")]
967pub type LineNumberSequence<R> = LineSequence<R>;
968
969#[derive(Clone, Debug)]
973pub struct LineSequence<R: Reader> {
974 pub start: u64,
977 pub end: u64,
980 instructions: LineInstructions<R>,
981}
982
983#[deprecated(
985 note = "LineNumberProgramHeader has been renamed to LineProgramHeader, use that instead."
986)]
987pub type LineNumberProgramHeader<R, Offset> = LineProgramHeader<R, Offset>;
988
989#[derive(Clone, Debug, Eq, PartialEq)]
992pub struct LineProgramHeader<R, Offset = <R as Reader>::Offset>
993where
994 R: Reader<Offset = Offset>,
995 Offset: ReaderOffset,
996{
997 encoding: Encoding,
998 offset: DebugLineOffset<Offset>,
999 unit_length: Offset,
1000
1001 header_length: Offset,
1002
1003 line_encoding: LineEncoding,
1004
1005 opcode_base: u8,
1007
1008 standard_opcode_lengths: R,
1013
1014 directory_entry_format: Vec<FileEntryFormat>,
1016
1017 include_directories: Vec<AttributeValue<R, Offset>>,
1026
1027 file_name_entry_format: Vec<FileEntryFormat>,
1029
1030 file_names: Vec<FileEntry<R, Offset>>,
1034
1035 program_buf: R,
1037
1038 comp_dir: Option<R>,
1040
1041 comp_file: Option<FileEntry<R, Offset>>,
1043}
1044
1045impl<R, Offset> LineProgramHeader<R, Offset>
1046where
1047 R: Reader<Offset = Offset>,
1048 Offset: ReaderOffset,
1049{
1050 pub fn offset(&self) -> DebugLineOffset<R::Offset> {
1052 self.offset
1053 }
1054
1055 pub fn unit_length(&self) -> R::Offset {
1058 self.unit_length
1059 }
1060
1061 pub fn encoding(&self) -> Encoding {
1063 self.encoding
1064 }
1065
1066 pub fn version(&self) -> u16 {
1068 self.encoding.version
1069 }
1070
1071 pub fn header_length(&self) -> R::Offset {
1074 self.header_length
1075 }
1076
1077 pub fn address_size(&self) -> u8 {
1079 self.encoding.address_size
1080 }
1081
1082 pub fn format(&self) -> Format {
1084 self.encoding.format
1085 }
1086
1087 pub fn line_encoding(&self) -> LineEncoding {
1089 self.line_encoding
1090 }
1091
1092 pub fn minimum_instruction_length(&self) -> u8 {
1095 self.line_encoding.minimum_instruction_length
1096 }
1097
1098 pub fn maximum_operations_per_instruction(&self) -> u8 {
1101 self.line_encoding.maximum_operations_per_instruction
1102 }
1103
1104 pub fn default_is_stmt(&self) -> bool {
1107 self.line_encoding.default_is_stmt
1108 }
1109
1110 pub fn line_base(&self) -> i8 {
1112 self.line_encoding.line_base
1113 }
1114
1115 pub fn line_range(&self) -> u8 {
1117 self.line_encoding.line_range
1118 }
1119
1120 pub fn opcode_base(&self) -> u8 {
1122 self.opcode_base
1123 }
1124
1125 pub fn standard_opcode_lengths(&self) -> &R {
1128 &self.standard_opcode_lengths
1129 }
1130
1131 pub fn directory_entry_format(&self) -> &[FileEntryFormat] {
1133 &self.directory_entry_format[..]
1134 }
1135
1136 pub fn include_directories(&self) -> &[AttributeValue<R, Offset>] {
1141 &self.include_directories[..]
1142 }
1143
1144 pub fn directory(&self, directory: u64) -> Option<AttributeValue<R, Offset>> {
1148 if self.encoding.version <= 4 {
1149 if directory == 0 {
1150 self.comp_dir.clone().map(AttributeValue::String)
1151 } else {
1152 let directory = directory as usize - 1;
1153 self.include_directories.get(directory).cloned()
1154 }
1155 } else {
1156 self.include_directories.get(directory as usize).cloned()
1157 }
1158 }
1159
1160 pub fn file_name_entry_format(&self) -> &[FileEntryFormat] {
1162 &self.file_name_entry_format[..]
1163 }
1164
1165 pub fn file_has_timestamp(&self) -> bool {
1170 self.encoding.version <= 4
1171 || self
1172 .file_name_entry_format
1173 .iter()
1174 .any(|x| x.content_type == constants::DW_LNCT_timestamp)
1175 }
1176
1177 pub fn file_has_size(&self) -> bool {
1182 self.encoding.version <= 4
1183 || self
1184 .file_name_entry_format
1185 .iter()
1186 .any(|x| x.content_type == constants::DW_LNCT_size)
1187 }
1188
1189 pub fn file_has_md5(&self) -> bool {
1191 self.file_name_entry_format
1192 .iter()
1193 .any(|x| x.content_type == constants::DW_LNCT_MD5)
1194 }
1195
1196 pub fn file_has_source(&self) -> bool {
1198 self.file_name_entry_format
1199 .iter()
1200 .any(|x| x.content_type == constants::DW_LNCT_LLVM_source)
1201 }
1202
1203 pub fn file_names(&self) -> &[FileEntry<R, Offset>] {
1205 &self.file_names[..]
1206 }
1207
1208 pub fn file(&self, file: u64) -> Option<&FileEntry<R, Offset>> {
1214 if self.encoding.version <= 4 {
1215 if file == 0 {
1216 self.comp_file.as_ref()
1217 } else {
1218 let file = file as usize - 1;
1219 self.file_names.get(file)
1220 }
1221 } else {
1222 self.file_names.get(file as usize)
1223 }
1224 }
1225
1226 pub fn raw_program_buf(&self) -> R {
1245 self.program_buf.clone()
1246 }
1247
1248 pub fn instructions(&self) -> LineInstructions<R> {
1251 LineInstructions {
1252 input: self.program_buf.clone(),
1253 }
1254 }
1255
1256 fn parse(
1257 input: &mut R,
1258 offset: DebugLineOffset<Offset>,
1259 mut address_size: u8,
1260 mut comp_dir: Option<R>,
1261 comp_name: Option<R>,
1262 ) -> Result<LineProgramHeader<R, Offset>> {
1263 let (unit_length, format) = input.read_initial_length()?;
1264 let rest = &mut input.split(unit_length)?;
1265
1266 let version = rest.read_u16()?;
1267 if version < 2 || version > 5 {
1268 return Err(Error::UnknownVersion(u64::from(version)));
1269 }
1270
1271 if version >= 5 {
1272 address_size = rest.read_address_size()?;
1273 let segment_selector_size = rest.read_u8()?;
1274 if segment_selector_size != 0 {
1275 return Err(Error::UnsupportedSegmentSize);
1276 }
1277 }
1278
1279 let encoding = Encoding {
1280 format,
1281 version,
1282 address_size,
1283 };
1284
1285 let header_length = rest.read_length(format)?;
1286
1287 let mut program_buf = rest.clone();
1288 program_buf.skip(header_length)?;
1289 rest.truncate(header_length)?;
1290
1291 let minimum_instruction_length = rest.read_u8()?;
1292 if minimum_instruction_length == 0 {
1293 return Err(Error::MinimumInstructionLengthZero);
1294 }
1295
1296 let maximum_operations_per_instruction = if version >= 4 { rest.read_u8()? } else { 1 };
1299 if maximum_operations_per_instruction == 0 {
1300 return Err(Error::MaximumOperationsPerInstructionZero);
1301 }
1302
1303 let default_is_stmt = rest.read_u8()? != 0;
1304 let line_base = rest.read_i8()?;
1305 let line_range = rest.read_u8()?;
1306 if line_range == 0 {
1307 return Err(Error::LineRangeZero);
1308 }
1309 let line_encoding = LineEncoding {
1310 minimum_instruction_length,
1311 maximum_operations_per_instruction,
1312 default_is_stmt,
1313 line_base,
1314 line_range,
1315 };
1316
1317 let opcode_base = rest.read_u8()?;
1318 if opcode_base == 0 {
1319 return Err(Error::OpcodeBaseZero);
1320 }
1321
1322 let standard_opcode_count = R::Offset::from_u8(opcode_base - 1);
1323 let standard_opcode_lengths = rest.split(standard_opcode_count)?;
1324
1325 let directory_entry_format;
1326 let mut include_directories = Vec::new();
1327 if version <= 4 {
1328 directory_entry_format = Vec::new();
1329 loop {
1330 let directory = rest.read_null_terminated_slice()?;
1331 if directory.is_empty() {
1332 break;
1333 }
1334 include_directories.push(AttributeValue::String(directory));
1335 }
1336 } else {
1337 comp_dir = None;
1338 directory_entry_format = FileEntryFormat::parse(rest)?;
1339 let count = rest.read_uleb128()?;
1340 for _ in 0..count {
1341 include_directories.push(parse_directory_v5(
1342 rest,
1343 encoding,
1344 &directory_entry_format,
1345 )?);
1346 }
1347 }
1348
1349 let comp_file;
1350 let file_name_entry_format;
1351 let mut file_names = Vec::new();
1352 if version <= 4 {
1353 comp_file = comp_name.map(|name| FileEntry {
1354 path_name: AttributeValue::String(name),
1355 directory_index: 0,
1356 timestamp: 0,
1357 size: 0,
1358 md5: [0; 16],
1359 source: None,
1360 });
1361
1362 file_name_entry_format = Vec::new();
1363 loop {
1364 let path_name = rest.read_null_terminated_slice()?;
1365 if path_name.is_empty() {
1366 break;
1367 }
1368 file_names.push(FileEntry::parse(rest, path_name)?);
1369 }
1370 } else {
1371 comp_file = None;
1372 file_name_entry_format = FileEntryFormat::parse(rest)?;
1373 let count = rest.read_uleb128()?;
1374 for _ in 0..count {
1375 file_names.push(parse_file_v5(rest, encoding, &file_name_entry_format)?);
1376 }
1377 }
1378
1379 let header = LineProgramHeader {
1380 encoding,
1381 offset,
1382 unit_length,
1383 header_length,
1384 line_encoding,
1385 opcode_base,
1386 standard_opcode_lengths,
1387 directory_entry_format,
1388 include_directories,
1389 file_name_entry_format,
1390 file_names,
1391 program_buf,
1392 comp_dir,
1393 comp_file,
1394 };
1395 Ok(header)
1396 }
1397}
1398
1399#[deprecated(
1401 note = "IncompleteLineNumberProgram has been renamed to IncompleteLineProgram, use that instead."
1402)]
1403pub type IncompleteLineNumberProgram<R, Offset> = IncompleteLineProgram<R, Offset>;
1404
1405#[derive(Clone, Debug, Eq, PartialEq)]
1407pub struct IncompleteLineProgram<R, Offset = <R as Reader>::Offset>
1408where
1409 R: Reader<Offset = Offset>,
1410 Offset: ReaderOffset,
1411{
1412 header: LineProgramHeader<R, Offset>,
1413}
1414
1415impl<R, Offset> IncompleteLineProgram<R, Offset>
1416where
1417 R: Reader<Offset = Offset>,
1418 Offset: ReaderOffset,
1419{
1420 pub fn header(&self) -> &LineProgramHeader<R, Offset> {
1422 &self.header
1423 }
1424
1425 pub fn rows(self) -> OneShotLineRows<R, Offset> {
1428 OneShotLineRows::new(self)
1429 }
1430
1431 #[allow(clippy::type_complexity)]
1452 pub fn sequences(self) -> Result<(CompleteLineProgram<R, Offset>, Vec<LineSequence<R>>)> {
1453 let mut sequences = Vec::new();
1454 let mut rows = self.rows();
1455 let mut instructions = rows.instructions.clone();
1456 let mut sequence_start_addr = None;
1457 loop {
1458 let sequence_end_addr;
1459 if rows.next_row()?.is_none() {
1460 break;
1461 }
1462
1463 let row = &rows.row;
1464 if row.end_sequence() {
1465 sequence_end_addr = row.address();
1466 } else if sequence_start_addr.is_none() {
1467 sequence_start_addr = Some(row.address());
1468 continue;
1469 } else {
1470 continue;
1471 }
1472
1473 sequences.push(LineSequence {
1475 start: sequence_start_addr.unwrap_or(0),
1478 end: sequence_end_addr,
1479 instructions: instructions.remove_trailing(&rows.instructions)?,
1480 });
1481 sequence_start_addr = None;
1482 instructions = rows.instructions.clone();
1483 }
1484
1485 let program = CompleteLineProgram {
1486 header: rows.program.header,
1487 };
1488 Ok((program, sequences))
1489 }
1490}
1491
1492#[deprecated(
1494 note = "CompleteLineNumberProgram has been renamed to CompleteLineProgram, use that instead."
1495)]
1496pub type CompleteLineNumberProgram<R, Offset> = CompleteLineProgram<R, Offset>;
1497
1498#[derive(Clone, Debug, Eq, PartialEq)]
1500pub struct CompleteLineProgram<R, Offset = <R as Reader>::Offset>
1501where
1502 R: Reader<Offset = Offset>,
1503 Offset: ReaderOffset,
1504{
1505 header: LineProgramHeader<R, Offset>,
1506}
1507
1508impl<R, Offset> CompleteLineProgram<R, Offset>
1509where
1510 R: Reader<Offset = Offset>,
1511 Offset: ReaderOffset,
1512{
1513 pub fn header(&self) -> &LineProgramHeader<R, Offset> {
1515 &self.header
1516 }
1517
1518 pub fn resume_from<'program>(
1540 &'program self,
1541 sequence: &LineSequence<R>,
1542 ) -> ResumedLineRows<'program, R, Offset> {
1543 ResumedLineRows::resume(self, sequence)
1544 }
1545}
1546
1547#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1549pub struct FileEntry<R, Offset = <R as Reader>::Offset>
1550where
1551 R: Reader<Offset = Offset>,
1552 Offset: ReaderOffset,
1553{
1554 path_name: AttributeValue<R, Offset>,
1555 directory_index: u64,
1556 timestamp: u64,
1557 size: u64,
1558 md5: [u8; 16],
1559 source: Option<AttributeValue<R, Offset>>,
1560}
1561
1562impl<R, Offset> FileEntry<R, Offset>
1563where
1564 R: Reader<Offset = Offset>,
1565 Offset: ReaderOffset,
1566{
1567 fn parse(input: &mut R, path_name: R) -> Result<FileEntry<R, Offset>> {
1569 let directory_index = input.read_uleb128()?;
1570 let timestamp = input.read_uleb128()?;
1571 let size = input.read_uleb128()?;
1572
1573 let entry = FileEntry {
1574 path_name: AttributeValue::String(path_name),
1575 directory_index,
1576 timestamp,
1577 size,
1578 md5: [0; 16],
1579 source: None,
1580 };
1581
1582 Ok(entry)
1583 }
1584
1585 pub fn path_name(&self) -> AttributeValue<R, Offset> {
1591 self.path_name.clone()
1592 }
1593
1594 pub fn directory_index(&self) -> u64 {
1606 self.directory_index
1607 }
1608
1609 pub fn directory(&self, header: &LineProgramHeader<R>) -> Option<AttributeValue<R, Offset>> {
1613 header.directory(self.directory_index)
1614 }
1615
1616 pub fn timestamp(&self) -> u64 {
1619 self.timestamp
1620 }
1621
1622 #[doc(hidden)]
1626 pub fn last_modification(&self) -> u64 {
1627 self.timestamp
1628 }
1629
1630 pub fn size(&self) -> u64 {
1632 self.size
1633 }
1634
1635 #[doc(hidden)]
1639 pub fn length(&self) -> u64 {
1640 self.size
1641 }
1642
1643 pub fn md5(&self) -> &[u8; 16] {
1647 &self.md5
1648 }
1649
1650 pub fn source(&self) -> Option<AttributeValue<R, Offset>> {
1657 self.source.clone()
1658 }
1659}
1660
1661#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1663pub struct FileEntryFormat {
1664 pub content_type: constants::DwLnct,
1666
1667 pub form: constants::DwForm,
1669}
1670
1671impl FileEntryFormat {
1672 fn parse<R: Reader>(input: &mut R) -> Result<Vec<FileEntryFormat>> {
1673 let format_count = input.read_u8()? as usize;
1674 let mut format = Vec::with_capacity(format_count);
1675 let mut path_count = 0;
1676 for _ in 0..format_count {
1677 let content_type = input.read_uleb128()?;
1678 let content_type = if content_type > u64::from(u16::MAX) {
1679 constants::DwLnct(u16::MAX)
1680 } else {
1681 constants::DwLnct(content_type as u16)
1682 };
1683 if content_type == constants::DW_LNCT_path {
1684 path_count += 1;
1685 }
1686
1687 let form = constants::DwForm(input.read_uleb128_u16()?);
1688
1689 format.push(FileEntryFormat { content_type, form });
1690 }
1691 if path_count != 1 {
1692 return Err(Error::MissingFileEntryFormatPath);
1693 }
1694 Ok(format)
1695 }
1696}
1697
1698fn parse_directory_v5<R: Reader>(
1699 input: &mut R,
1700 encoding: Encoding,
1701 formats: &[FileEntryFormat],
1702) -> Result<AttributeValue<R>> {
1703 let mut path_name = None;
1704
1705 for format in formats {
1706 let value = parse_attribute(input, encoding, format.form)?;
1707 if format.content_type == constants::DW_LNCT_path {
1708 path_name = Some(value);
1709 }
1710 }
1711
1712 Ok(path_name.unwrap())
1713}
1714
1715fn parse_file_v5<R: Reader>(
1716 input: &mut R,
1717 encoding: Encoding,
1718 formats: &[FileEntryFormat],
1719) -> Result<FileEntry<R>> {
1720 let mut path_name = None;
1721 let mut directory_index = 0;
1722 let mut timestamp = 0;
1723 let mut size = 0;
1724 let mut md5 = [0; 16];
1725 let mut source = None;
1726
1727 for format in formats {
1728 let value = parse_attribute(input, encoding, format.form)?;
1729 match format.content_type {
1730 constants::DW_LNCT_path => path_name = Some(value),
1731 constants::DW_LNCT_directory_index => {
1732 if let Some(value) = value.udata_value() {
1733 directory_index = value;
1734 }
1735 }
1736 constants::DW_LNCT_timestamp => {
1737 if let Some(value) = value.udata_value() {
1738 timestamp = value;
1739 }
1740 }
1741 constants::DW_LNCT_size => {
1742 if let Some(value) = value.udata_value() {
1743 size = value;
1744 }
1745 }
1746 constants::DW_LNCT_MD5 => {
1747 if let AttributeValue::Block(mut value) = value {
1748 if value.len().into_u64() == 16 {
1749 md5 = value.read_u8_array()?;
1750 }
1751 }
1752 }
1753 constants::DW_LNCT_LLVM_source => {
1754 source = Some(value);
1755 }
1756 _ => {}
1758 }
1759 }
1760
1761 Ok(FileEntry {
1762 path_name: path_name.unwrap(),
1763 directory_index,
1764 timestamp,
1765 size,
1766 md5,
1767 source,
1768 })
1769}
1770
1771fn parse_attribute<R: Reader>(
1773 input: &mut R,
1774 encoding: Encoding,
1775 form: constants::DwForm,
1776) -> Result<AttributeValue<R>> {
1777 Ok(match form {
1778 constants::DW_FORM_block1 => {
1779 let len = input.read_u8().map(R::Offset::from_u8)?;
1780 let block = input.split(len)?;
1781 AttributeValue::Block(block)
1782 }
1783 constants::DW_FORM_block2 => {
1784 let len = input.read_u16().map(R::Offset::from_u16)?;
1785 let block = input.split(len)?;
1786 AttributeValue::Block(block)
1787 }
1788 constants::DW_FORM_block4 => {
1789 let len = input.read_u32().map(R::Offset::from_u32)?;
1790 let block = input.split(len)?;
1791 AttributeValue::Block(block)
1792 }
1793 constants::DW_FORM_block => {
1794 let len = input.read_uleb128().and_then(R::Offset::from_u64)?;
1795 let block = input.split(len)?;
1796 AttributeValue::Block(block)
1797 }
1798 constants::DW_FORM_data1 => {
1799 let data = input.read_u8()?;
1800 AttributeValue::Data1(data)
1801 }
1802 constants::DW_FORM_data2 => {
1803 let data = input.read_u16()?;
1804 AttributeValue::Data2(data)
1805 }
1806 constants::DW_FORM_data4 => {
1807 let data = input.read_u32()?;
1808 AttributeValue::Data4(data)
1809 }
1810 constants::DW_FORM_data8 => {
1811 let data = input.read_u64()?;
1812 AttributeValue::Data8(data)
1813 }
1814 constants::DW_FORM_data16 => {
1815 let block = input.split(R::Offset::from_u8(16))?;
1816 AttributeValue::Block(block)
1817 }
1818 constants::DW_FORM_udata => {
1819 let data = input.read_uleb128()?;
1820 AttributeValue::Udata(data)
1821 }
1822 constants::DW_FORM_sdata => {
1823 let data = input.read_sleb128()?;
1824 AttributeValue::Sdata(data)
1825 }
1826 constants::DW_FORM_flag => {
1827 let present = input.read_u8()?;
1828 AttributeValue::Flag(present != 0)
1829 }
1830 constants::DW_FORM_sec_offset => {
1831 let offset = input.read_offset(encoding.format)?;
1832 AttributeValue::SecOffset(offset)
1833 }
1834 constants::DW_FORM_string => {
1835 let string = input.read_null_terminated_slice()?;
1836 AttributeValue::String(string)
1837 }
1838 constants::DW_FORM_strp => {
1839 let offset = input.read_offset(encoding.format)?;
1840 AttributeValue::DebugStrRef(DebugStrOffset(offset))
1841 }
1842 constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt => {
1843 let offset = input.read_offset(encoding.format)?;
1844 AttributeValue::DebugStrRefSup(DebugStrOffset(offset))
1845 }
1846 constants::DW_FORM_line_strp => {
1847 let offset = input.read_offset(encoding.format)?;
1848 AttributeValue::DebugLineStrRef(DebugLineStrOffset(offset))
1849 }
1850 constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => {
1851 let index = input.read_uleb128().and_then(R::Offset::from_u64)?;
1852 AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1853 }
1854 constants::DW_FORM_strx1 => {
1855 let index = input.read_u8().map(R::Offset::from_u8)?;
1856 AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1857 }
1858 constants::DW_FORM_strx2 => {
1859 let index = input.read_u16().map(R::Offset::from_u16)?;
1860 AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1861 }
1862 constants::DW_FORM_strx3 => {
1863 let index = input.read_uint(3).and_then(R::Offset::from_u64)?;
1864 AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1865 }
1866 constants::DW_FORM_strx4 => {
1867 let index = input.read_u32().map(R::Offset::from_u32)?;
1868 AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1869 }
1870 _ => {
1871 return Err(Error::UnknownForm(form));
1872 }
1873 })
1874}
1875
1876#[cfg(test)]
1877mod tests {
1878 use super::*;
1879 use crate::constants;
1880 use crate::endianity::LittleEndian;
1881 use crate::read::{EndianSlice, Error};
1882 use crate::test_util::GimliSectionMethods;
1883 use test_assembler::{Endian, Label, LabelMaker, Section};
1884
1885 #[test]
1886 fn test_parse_debug_line_32_ok() {
1887 #[rustfmt::skip]
1888 let buf = [
1889 0x3e, 0x00, 0x00, 0x00,
1891 0x04, 0x00,
1893 0x28, 0x00, 0x00, 0x00,
1895 0x01,
1897 0x01,
1899 0x01,
1901 0x00,
1903 0x01,
1905 0x03,
1907 0x01, 0x02,
1909 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
1911 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
1914 0x00,
1915 0x00,
1916 0x00,
1917 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
1919 0x01,
1920 0x00,
1921 0x00,
1922 0x00,
1924
1925 0x00, 0x00, 0x00, 0x00,
1927 0x00, 0x00, 0x00, 0x00,
1928 0x00, 0x00, 0x00, 0x00,
1929 0x00, 0x00, 0x00, 0x00,
1930
1931 0x00, 0x00, 0x00, 0x00,
1933 0x00, 0x00, 0x00, 0x00,
1934 0x00, 0x00, 0x00, 0x00,
1935 0x00, 0x00, 0x00, 0x00,
1936 ];
1937
1938 let rest = &mut EndianSlice::new(&buf, LittleEndian);
1939 let comp_dir = EndianSlice::new(b"/comp_dir", LittleEndian);
1940 let comp_name = EndianSlice::new(b"/comp_name", LittleEndian);
1941
1942 let header =
1943 LineProgramHeader::parse(rest, DebugLineOffset(0), 4, Some(comp_dir), Some(comp_name))
1944 .expect("should parse header ok");
1945
1946 assert_eq!(
1947 *rest,
1948 EndianSlice::new(&buf[buf.len() - 16..], LittleEndian)
1949 );
1950
1951 assert_eq!(header.offset, DebugLineOffset(0));
1952 assert_eq!(header.version(), 4);
1953 assert_eq!(header.minimum_instruction_length(), 1);
1954 assert_eq!(header.maximum_operations_per_instruction(), 1);
1955 assert!(header.default_is_stmt());
1956 assert_eq!(header.line_base(), 0);
1957 assert_eq!(header.line_range(), 1);
1958 assert_eq!(header.opcode_base(), 3);
1959 assert_eq!(header.directory(0), Some(AttributeValue::String(comp_dir)));
1960 assert_eq!(
1961 header.file(0).unwrap().path_name,
1962 AttributeValue::String(comp_name)
1963 );
1964
1965 let expected_lengths = [1, 2];
1966 assert_eq!(header.standard_opcode_lengths().slice(), &expected_lengths);
1967
1968 let expected_include_directories = [
1969 AttributeValue::String(EndianSlice::new(b"/inc", LittleEndian)),
1970 AttributeValue::String(EndianSlice::new(b"/inc2", LittleEndian)),
1971 ];
1972 assert_eq!(header.include_directories(), &expected_include_directories);
1973
1974 let expected_file_names = [
1975 FileEntry {
1976 path_name: AttributeValue::String(EndianSlice::new(b"foo.rs", LittleEndian)),
1977 directory_index: 0,
1978 timestamp: 0,
1979 size: 0,
1980 md5: [0; 16],
1981 source: None,
1982 },
1983 FileEntry {
1984 path_name: AttributeValue::String(EndianSlice::new(b"bar.h", LittleEndian)),
1985 directory_index: 1,
1986 timestamp: 0,
1987 size: 0,
1988 md5: [0; 16],
1989 source: None,
1990 },
1991 ];
1992 assert_eq!(header.file_names(), &expected_file_names);
1993 }
1994
1995 #[test]
1996 fn test_parse_debug_line_header_length_too_short() {
1997 #[rustfmt::skip]
1998 let buf = [
1999 0x3e, 0x00, 0x00, 0x00,
2001 0x04, 0x00,
2003 0x15, 0x00, 0x00, 0x00,
2005 0x01,
2007 0x01,
2009 0x01,
2011 0x00,
2013 0x01,
2015 0x03,
2017 0x01, 0x02,
2019 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
2021 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
2024 0x00,
2025 0x00,
2026 0x00,
2027 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
2029 0x01,
2030 0x00,
2031 0x00,
2032 0x00,
2034
2035 0x00, 0x00, 0x00, 0x00,
2037 0x00, 0x00, 0x00, 0x00,
2038 0x00, 0x00, 0x00, 0x00,
2039 0x00, 0x00, 0x00, 0x00,
2040
2041 0x00, 0x00, 0x00, 0x00,
2043 0x00, 0x00, 0x00, 0x00,
2044 0x00, 0x00, 0x00, 0x00,
2045 0x00, 0x00, 0x00, 0x00,
2046 ];
2047
2048 let input = &mut EndianSlice::new(&buf, LittleEndian);
2049
2050 match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) {
2051 Err(Error::UnexpectedEof(_)) => {}
2052 otherwise => panic!("Unexpected result: {:?}", otherwise),
2053 }
2054 }
2055
2056 #[test]
2057 fn test_parse_debug_line_unit_length_too_short() {
2058 #[rustfmt::skip]
2059 let buf = [
2060 0x28, 0x00, 0x00, 0x00,
2062 0x04, 0x00,
2064 0x28, 0x00, 0x00, 0x00,
2066 0x01,
2068 0x01,
2070 0x01,
2072 0x00,
2074 0x01,
2076 0x03,
2078 0x01, 0x02,
2080 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
2082 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
2085 0x00,
2086 0x00,
2087 0x00,
2088 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
2090 0x01,
2091 0x00,
2092 0x00,
2093 0x00,
2095
2096 0x00, 0x00, 0x00, 0x00,
2098 0x00, 0x00, 0x00, 0x00,
2099 0x00, 0x00, 0x00, 0x00,
2100 0x00, 0x00, 0x00, 0x00,
2101
2102 0x00, 0x00, 0x00, 0x00,
2104 0x00, 0x00, 0x00, 0x00,
2105 0x00, 0x00, 0x00, 0x00,
2106 0x00, 0x00, 0x00, 0x00,
2107 ];
2108
2109 let input = &mut EndianSlice::new(&buf, LittleEndian);
2110
2111 match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) {
2112 Err(Error::UnexpectedEof(_)) => {}
2113 otherwise => panic!("Unexpected result: {:?}", otherwise),
2114 }
2115 }
2116
2117 const OPCODE_BASE: u8 = 13;
2118 const STANDARD_OPCODE_LENGTHS: &[u8] = &[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1];
2119
2120 fn make_test_header(
2121 buf: EndianSlice<'_, LittleEndian>,
2122 ) -> LineProgramHeader<EndianSlice<'_, LittleEndian>> {
2123 let encoding = Encoding {
2124 format: Format::Dwarf32,
2125 version: 4,
2126 address_size: 8,
2127 };
2128 let line_encoding = LineEncoding {
2129 line_base: -3,
2130 line_range: 12,
2131 ..Default::default()
2132 };
2133 LineProgramHeader {
2134 encoding,
2135 offset: DebugLineOffset(0),
2136 unit_length: 1,
2137 header_length: 1,
2138 line_encoding,
2139 opcode_base: OPCODE_BASE,
2140 standard_opcode_lengths: EndianSlice::new(STANDARD_OPCODE_LENGTHS, LittleEndian),
2141 file_names: vec![
2142 FileEntry {
2143 path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)),
2144 directory_index: 0,
2145 timestamp: 0,
2146 size: 0,
2147 md5: [0; 16],
2148 source: None,
2149 },
2150 FileEntry {
2151 path_name: AttributeValue::String(EndianSlice::new(b"bar.rs", LittleEndian)),
2152 directory_index: 0,
2153 timestamp: 0,
2154 size: 0,
2155 md5: [0; 16],
2156 source: None,
2157 },
2158 ],
2159 include_directories: vec![],
2160 directory_entry_format: vec![],
2161 file_name_entry_format: vec![],
2162 program_buf: buf,
2163 comp_dir: None,
2164 comp_file: None,
2165 }
2166 }
2167
2168 fn make_test_program(
2169 buf: EndianSlice<'_, LittleEndian>,
2170 ) -> IncompleteLineProgram<EndianSlice<'_, LittleEndian>> {
2171 IncompleteLineProgram {
2172 header: make_test_header(buf),
2173 }
2174 }
2175
2176 #[test]
2177 fn test_parse_special_opcodes() {
2178 for i in OPCODE_BASE..u8::MAX {
2179 let input = [i, 0, 0, 0];
2180 let input = EndianSlice::new(&input, LittleEndian);
2181 let header = make_test_header(input);
2182
2183 let mut rest = input;
2184 let opcode =
2185 LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2186
2187 assert_eq!(*rest, *input.range_from(1..));
2188 assert_eq!(opcode, LineInstruction::Special(i));
2189 }
2190 }
2191
2192 #[test]
2193 fn test_parse_standard_opcodes() {
2194 fn test<Operands>(
2195 raw: constants::DwLns,
2196 operands: Operands,
2197 expected: LineInstruction<EndianSlice<'_, LittleEndian>>,
2198 ) where
2199 Operands: AsRef<[u8]>,
2200 {
2201 let mut input = Vec::new();
2202 input.push(raw.0);
2203 input.extend_from_slice(operands.as_ref());
2204
2205 let expected_rest = [0, 1, 2, 3, 4];
2206 input.extend_from_slice(&expected_rest);
2207
2208 let input = EndianSlice::new(&input, LittleEndian);
2209 let header = make_test_header(input);
2210
2211 let mut rest = input;
2212 let opcode =
2213 LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2214
2215 assert_eq!(opcode, expected);
2216 assert_eq!(*rest, expected_rest);
2217 }
2218
2219 test(constants::DW_LNS_copy, [], LineInstruction::Copy);
2220 test(
2221 constants::DW_LNS_advance_pc,
2222 [42],
2223 LineInstruction::AdvancePc(42),
2224 );
2225 test(
2226 constants::DW_LNS_advance_line,
2227 [9],
2228 LineInstruction::AdvanceLine(9),
2229 );
2230 test(constants::DW_LNS_set_file, [7], LineInstruction::SetFile(7));
2231 test(
2232 constants::DW_LNS_set_column,
2233 [1],
2234 LineInstruction::SetColumn(1),
2235 );
2236 test(
2237 constants::DW_LNS_negate_stmt,
2238 [],
2239 LineInstruction::NegateStatement,
2240 );
2241 test(
2242 constants::DW_LNS_set_basic_block,
2243 [],
2244 LineInstruction::SetBasicBlock,
2245 );
2246 test(
2247 constants::DW_LNS_const_add_pc,
2248 [],
2249 LineInstruction::ConstAddPc,
2250 );
2251 test(
2252 constants::DW_LNS_fixed_advance_pc,
2253 [42, 0],
2254 LineInstruction::FixedAddPc(42),
2255 );
2256 test(
2257 constants::DW_LNS_set_prologue_end,
2258 [],
2259 LineInstruction::SetPrologueEnd,
2260 );
2261 test(
2262 constants::DW_LNS_set_isa,
2263 [57 + 0x80, 100],
2264 LineInstruction::SetIsa(12857),
2265 );
2266 }
2267
2268 #[test]
2269 fn test_parse_unknown_standard_opcode_no_args() {
2270 let input = [OPCODE_BASE, 1, 2, 3];
2271 let input = EndianSlice::new(&input, LittleEndian);
2272 let mut standard_opcode_lengths = Vec::new();
2273 let mut header = make_test_header(input);
2274 standard_opcode_lengths.extend(header.standard_opcode_lengths.slice());
2275 standard_opcode_lengths.push(0);
2276 header.opcode_base += 1;
2277 header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian);
2278
2279 let mut rest = input;
2280 let opcode =
2281 LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2282
2283 assert_eq!(
2284 opcode,
2285 LineInstruction::UnknownStandard0(constants::DwLns(OPCODE_BASE))
2286 );
2287 assert_eq!(*rest, *input.range_from(1..));
2288 }
2289
2290 #[test]
2291 fn test_parse_unknown_standard_opcode_one_arg() {
2292 let input = [OPCODE_BASE, 1, 2, 3];
2293 let input = EndianSlice::new(&input, LittleEndian);
2294 let mut standard_opcode_lengths = Vec::new();
2295 let mut header = make_test_header(input);
2296 standard_opcode_lengths.extend(header.standard_opcode_lengths.slice());
2297 standard_opcode_lengths.push(1);
2298 header.opcode_base += 1;
2299 header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian);
2300
2301 let mut rest = input;
2302 let opcode =
2303 LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2304
2305 assert_eq!(
2306 opcode,
2307 LineInstruction::UnknownStandard1(constants::DwLns(OPCODE_BASE), 1)
2308 );
2309 assert_eq!(*rest, *input.range_from(2..));
2310 }
2311
2312 #[test]
2313 fn test_parse_unknown_standard_opcode_many_args() {
2314 let input = [OPCODE_BASE, 1, 2, 3];
2315 let input = EndianSlice::new(&input, LittleEndian);
2316 let args = input.range_from(1..);
2317 let mut standard_opcode_lengths = Vec::new();
2318 let mut header = make_test_header(input);
2319 standard_opcode_lengths.extend(header.standard_opcode_lengths.slice());
2320 standard_opcode_lengths.push(3);
2321 header.opcode_base += 1;
2322 header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian);
2323
2324 let mut rest = input;
2325 let opcode =
2326 LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2327
2328 assert_eq!(
2329 opcode,
2330 LineInstruction::UnknownStandardN(constants::DwLns(OPCODE_BASE), args)
2331 );
2332 assert_eq!(*rest, []);
2333 }
2334
2335 #[test]
2336 fn test_parse_extended_opcodes() {
2337 fn test<Operands>(
2338 raw: constants::DwLne,
2339 operands: Operands,
2340 expected: LineInstruction<EndianSlice<'_, LittleEndian>>,
2341 ) where
2342 Operands: AsRef<[u8]>,
2343 {
2344 let mut input = Vec::new();
2345 input.push(0);
2346
2347 let operands = operands.as_ref();
2348 input.push(1 + operands.len() as u8);
2349
2350 input.push(raw.0);
2351 input.extend_from_slice(operands);
2352
2353 let expected_rest = [0, 1, 2, 3, 4];
2354 input.extend_from_slice(&expected_rest);
2355
2356 let input = EndianSlice::new(&input, LittleEndian);
2357 let header = make_test_header(input);
2358
2359 let mut rest = input;
2360 let opcode =
2361 LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2362
2363 assert_eq!(opcode, expected);
2364 assert_eq!(*rest, expected_rest);
2365 }
2366
2367 test(
2368 constants::DW_LNE_end_sequence,
2369 [],
2370 LineInstruction::EndSequence,
2371 );
2372 test(
2373 constants::DW_LNE_set_address,
2374 [1, 2, 3, 4, 5, 6, 7, 8],
2375 LineInstruction::SetAddress(578_437_695_752_307_201),
2376 );
2377 test(
2378 constants::DW_LNE_set_discriminator,
2379 [42],
2380 LineInstruction::SetDiscriminator(42),
2381 );
2382
2383 let mut file = Vec::new();
2384 let path_name = [b'f', b'o', b'o', b'.', b'c', 0];
2386 file.extend_from_slice(&path_name);
2387 file.push(0);
2389 file.push(1);
2391 file.push(2);
2393
2394 test(
2395 constants::DW_LNE_define_file,
2396 file,
2397 LineInstruction::DefineFile(FileEntry {
2398 path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)),
2399 directory_index: 0,
2400 timestamp: 1,
2401 size: 2,
2402 md5: [0; 16],
2403 source: None,
2404 }),
2405 );
2406
2407 let operands = [1, 2, 3, 4, 5, 6];
2409 let opcode = constants::DwLne(99);
2410 test(
2411 opcode,
2412 operands,
2413 LineInstruction::UnknownExtended(opcode, EndianSlice::new(&operands, LittleEndian)),
2414 );
2415 }
2416
2417 #[test]
2418 fn test_file_entry_directory() {
2419 let path_name = [b'f', b'o', b'o', b'.', b'r', b's', 0];
2420
2421 let mut file = FileEntry {
2422 path_name: AttributeValue::String(EndianSlice::new(&path_name, LittleEndian)),
2423 directory_index: 1,
2424 timestamp: 0,
2425 size: 0,
2426 md5: [0; 16],
2427 source: None,
2428 };
2429
2430 let mut header = make_test_header(EndianSlice::new(&[], LittleEndian));
2431
2432 let dir = AttributeValue::String(EndianSlice::new(b"dir", LittleEndian));
2433 header.include_directories.push(dir);
2434
2435 assert_eq!(file.directory(&header), Some(dir));
2436
2437 file.directory_index = 0;
2439 assert_eq!(file.directory(&header), None);
2440 }
2441
2442 fn assert_exec_opcode<'input>(
2443 header: LineProgramHeader<EndianSlice<'input, LittleEndian>>,
2444 mut registers: LineRow,
2445 opcode: LineInstruction<EndianSlice<'input, LittleEndian>>,
2446 expected_registers: LineRow,
2447 expect_new_row: bool,
2448 ) {
2449 let mut program = IncompleteLineProgram { header };
2450 let is_new_row = registers.execute(opcode, &mut program);
2451
2452 assert_eq!(is_new_row, Ok(expect_new_row));
2453 assert_eq!(registers, expected_registers);
2454 }
2455
2456 #[test]
2457 fn test_exec_special_noop() {
2458 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2459
2460 let initial_registers = LineRow::new(&header);
2461 let opcode = LineInstruction::Special(16);
2462 let expected_registers = initial_registers;
2463
2464 assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2465 }
2466
2467 #[test]
2468 fn test_exec_special_negative_line_advance() {
2469 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2470
2471 let mut initial_registers = LineRow::new(&header);
2472 initial_registers.line.0 = 10;
2473
2474 let opcode = LineInstruction::Special(13);
2475
2476 let mut expected_registers = initial_registers;
2477 expected_registers.line.0 -= 3;
2478
2479 assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2480 }
2481
2482 #[test]
2483 fn test_exec_special_positive_line_advance() {
2484 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2485
2486 let initial_registers = LineRow::new(&header);
2487
2488 let opcode = LineInstruction::Special(19);
2489
2490 let mut expected_registers = initial_registers;
2491 expected_registers.line.0 += 3;
2492
2493 assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2494 }
2495
2496 #[test]
2497 fn test_exec_special_positive_address_advance() {
2498 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2499
2500 let initial_registers = LineRow::new(&header);
2501
2502 let opcode = LineInstruction::Special(52);
2503
2504 let mut expected_registers = initial_registers;
2505 expected_registers.address += 3;
2506
2507 assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2508 }
2509
2510 #[test]
2511 fn test_exec_special_positive_address_and_line_advance() {
2512 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2513
2514 let initial_registers = LineRow::new(&header);
2515
2516 let opcode = LineInstruction::Special(55);
2517
2518 let mut expected_registers = initial_registers;
2519 expected_registers.address += 3;
2520 expected_registers.line.0 += 3;
2521
2522 assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2523 }
2524
2525 #[test]
2526 fn test_exec_special_positive_address_and_negative_line_advance() {
2527 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2528
2529 let mut initial_registers = LineRow::new(&header);
2530 initial_registers.line.0 = 10;
2531
2532 let opcode = LineInstruction::Special(49);
2533
2534 let mut expected_registers = initial_registers;
2535 expected_registers.address += 3;
2536 expected_registers.line.0 -= 3;
2537
2538 assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2539 }
2540
2541 #[test]
2542 fn test_exec_special_line_underflow() {
2543 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2544
2545 let mut initial_registers = LineRow::new(&header);
2546 initial_registers.line.0 = 2;
2547
2548 let opcode = LineInstruction::Special(13);
2550
2551 let mut expected_registers = initial_registers;
2552 expected_registers.line.0 = 0;
2555
2556 assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2557 }
2558
2559 #[test]
2560 fn test_exec_copy() {
2561 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2562
2563 let mut initial_registers = LineRow::new(&header);
2564 initial_registers.address = 1337;
2565 initial_registers.line.0 = 42;
2566
2567 let opcode = LineInstruction::Copy;
2568
2569 let expected_registers = initial_registers;
2570
2571 assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2572 }
2573
2574 #[test]
2575 fn test_exec_advance_pc() {
2576 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2577 let initial_registers = LineRow::new(&header);
2578 let opcode = LineInstruction::AdvancePc(42);
2579
2580 let mut expected_registers = initial_registers;
2581 expected_registers.address += 42;
2582
2583 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2584 }
2585
2586 #[test]
2587 fn test_exec_advance_pc_overflow_32() {
2588 let mut header = make_test_header(EndianSlice::new(&[], LittleEndian));
2589 header.encoding.address_size = 4;
2590 let mut registers = LineRow::new(&header);
2591 registers.address = u32::MAX.into();
2592 let opcode = LineInstruction::AdvancePc(42);
2593 let mut program = IncompleteLineProgram { header };
2594 let result = registers.execute(opcode, &mut program);
2595 assert_eq!(result, Err(Error::AddressOverflow));
2596 }
2597
2598 #[test]
2599 fn test_exec_advance_pc_overflow_64() {
2600 let mut header = make_test_header(EndianSlice::new(&[], LittleEndian));
2601 header.encoding.address_size = 8;
2602 let mut registers = LineRow::new(&header);
2603 registers.address = u64::MAX;
2604 let opcode = LineInstruction::AdvancePc(42);
2605 let mut program = IncompleteLineProgram { header };
2606 let result = registers.execute(opcode, &mut program);
2607 assert_eq!(result, Err(Error::AddressOverflow));
2608 }
2609
2610 #[test]
2611 fn test_exec_advance_line() {
2612 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2613 let initial_registers = LineRow::new(&header);
2614 let opcode = LineInstruction::AdvanceLine(42);
2615
2616 let mut expected_registers = initial_registers;
2617 expected_registers.line.0 += 42;
2618
2619 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2620 }
2621
2622 #[test]
2623 fn test_exec_advance_line_overflow() {
2624 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2625 let opcode = LineInstruction::AdvanceLine(42);
2626
2627 let mut initial_registers = LineRow::new(&header);
2628 initial_registers.line.0 = u64::MAX;
2629
2630 let mut expected_registers = initial_registers;
2631 expected_registers.line.0 = 41;
2632
2633 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2634 }
2635
2636 #[test]
2637 fn test_exec_set_file_in_bounds() {
2638 for file_idx in 1..3 {
2639 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2640 let initial_registers = LineRow::new(&header);
2641 let opcode = LineInstruction::SetFile(file_idx);
2642
2643 let mut expected_registers = initial_registers;
2644 expected_registers.file = file_idx;
2645
2646 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2647 }
2648 }
2649
2650 #[test]
2651 fn test_exec_set_file_out_of_bounds() {
2652 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2653 let initial_registers = LineRow::new(&header);
2654 let opcode = LineInstruction::SetFile(100);
2655
2656 let mut expected_registers = initial_registers;
2663 expected_registers.file = 100;
2664
2665 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2666 }
2667
2668 #[test]
2669 fn test_file_entry_file_index_out_of_bounds() {
2670 let out_of_bounds_indices = [0, 100];
2673
2674 for file_idx in &out_of_bounds_indices[..] {
2675 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2676 let mut row = LineRow::new(&header);
2677
2678 row.file = *file_idx;
2679
2680 assert_eq!(row.file(&header), None);
2681 }
2682 }
2683
2684 #[test]
2685 fn test_file_entry_file_index_in_bounds() {
2686 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2687 let mut row = LineRow::new(&header);
2688
2689 row.file = 2;
2690
2691 assert_eq!(row.file(&header), Some(&header.file_names()[1]));
2692 }
2693
2694 #[test]
2695 fn test_exec_set_column() {
2696 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2697 let initial_registers = LineRow::new(&header);
2698 let opcode = LineInstruction::SetColumn(42);
2699
2700 let mut expected_registers = initial_registers;
2701 expected_registers.column = 42;
2702
2703 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2704 }
2705
2706 #[test]
2707 fn test_exec_negate_statement() {
2708 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2709 let initial_registers = LineRow::new(&header);
2710 let opcode = LineInstruction::NegateStatement;
2711
2712 let mut expected_registers = initial_registers;
2713 expected_registers.is_stmt = !initial_registers.is_stmt;
2714
2715 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2716 }
2717
2718 #[test]
2719 fn test_exec_set_basic_block() {
2720 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2721
2722 let mut initial_registers = LineRow::new(&header);
2723 initial_registers.basic_block = false;
2724
2725 let opcode = LineInstruction::SetBasicBlock;
2726
2727 let mut expected_registers = initial_registers;
2728 expected_registers.basic_block = true;
2729
2730 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2731 }
2732
2733 #[test]
2734 fn test_exec_const_add_pc() {
2735 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2736 let initial_registers = LineRow::new(&header);
2737 let opcode = LineInstruction::ConstAddPc;
2738
2739 let mut expected_registers = initial_registers;
2740 expected_registers.address += 20;
2741
2742 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2743 }
2744
2745 #[test]
2746 fn test_exec_const_add_pc_overflow() {
2747 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2748 let mut registers = LineRow::new(&header);
2749 registers.address = u64::MAX;
2750 let opcode = LineInstruction::ConstAddPc;
2751 let mut program = IncompleteLineProgram { header };
2752 let result = registers.execute(opcode, &mut program);
2753 assert_eq!(result, Err(Error::AddressOverflow));
2754 }
2755
2756 #[test]
2757 fn test_exec_fixed_add_pc() {
2758 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2759
2760 let mut initial_registers = LineRow::new(&header);
2761 initial_registers.op_index.0 = 1;
2762
2763 let opcode = LineInstruction::FixedAddPc(10);
2764
2765 let mut expected_registers = initial_registers;
2766 expected_registers.address += 10;
2767 expected_registers.op_index.0 = 0;
2768
2769 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2770 }
2771
2772 #[test]
2773 fn test_exec_fixed_add_pc_overflow() {
2774 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2775 let mut registers = LineRow::new(&header);
2776 registers.address = u64::MAX;
2777 registers.op_index.0 = 1;
2778 let opcode = LineInstruction::FixedAddPc(10);
2779 let mut program = IncompleteLineProgram { header };
2780 let result = registers.execute(opcode, &mut program);
2781 assert_eq!(result, Err(Error::AddressOverflow));
2782 }
2783
2784 #[test]
2785 fn test_exec_set_prologue_end() {
2786 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2787
2788 let mut initial_registers = LineRow::new(&header);
2789 initial_registers.prologue_end = false;
2790
2791 let opcode = LineInstruction::SetPrologueEnd;
2792
2793 let mut expected_registers = initial_registers;
2794 expected_registers.prologue_end = true;
2795
2796 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2797 }
2798
2799 #[test]
2800 fn test_exec_set_isa() {
2801 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2802 let initial_registers = LineRow::new(&header);
2803 let opcode = LineInstruction::SetIsa(1993);
2804
2805 let mut expected_registers = initial_registers;
2806 expected_registers.isa = 1993;
2807
2808 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2809 }
2810
2811 #[test]
2812 fn test_exec_unknown_standard_0() {
2813 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2814 let initial_registers = LineRow::new(&header);
2815 let opcode = LineInstruction::UnknownStandard0(constants::DwLns(111));
2816 let expected_registers = initial_registers;
2817 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2818 }
2819
2820 #[test]
2821 fn test_exec_unknown_standard_1() {
2822 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2823 let initial_registers = LineRow::new(&header);
2824 let opcode = LineInstruction::UnknownStandard1(constants::DwLns(111), 2);
2825 let expected_registers = initial_registers;
2826 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2827 }
2828
2829 #[test]
2830 fn test_exec_unknown_standard_n() {
2831 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2832 let initial_registers = LineRow::new(&header);
2833 let opcode = LineInstruction::UnknownStandardN(
2834 constants::DwLns(111),
2835 EndianSlice::new(&[2, 2, 2], LittleEndian),
2836 );
2837 let expected_registers = initial_registers;
2838 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2839 }
2840
2841 #[test]
2842 fn test_exec_end_sequence() {
2843 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2844 let initial_registers = LineRow::new(&header);
2845 let opcode = LineInstruction::EndSequence;
2846
2847 let mut expected_registers = initial_registers;
2848 expected_registers.end_sequence = true;
2849
2850 assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2851 }
2852
2853 #[test]
2854 fn test_exec_set_address() {
2855 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2856 let initial_registers = LineRow::new(&header);
2857 let opcode = LineInstruction::SetAddress(3030);
2858
2859 let mut expected_registers = initial_registers;
2860 expected_registers.address = 3030;
2861
2862 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2863 }
2864
2865 #[test]
2866 fn test_exec_set_address_tombstone() {
2867 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2868 let initial_registers = LineRow::new(&header);
2869 let opcode = LineInstruction::SetAddress(!0);
2870
2871 let mut expected_registers = initial_registers;
2872 expected_registers.tombstone = true;
2873
2874 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2875 }
2876
2877 #[test]
2878 fn test_exec_set_address_backwards() {
2879 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2880 let mut registers = LineRow::new(&header);
2881 registers.address = 1;
2882 let opcode = LineInstruction::SetAddress(0);
2883
2884 let mut program = IncompleteLineProgram { header };
2885 let result = registers.execute(opcode, &mut program);
2886 assert_eq!(result, Err(Error::InvalidAddressRange));
2887 }
2888
2889 #[test]
2890 fn test_exec_define_file() {
2891 let mut program = make_test_program(EndianSlice::new(&[], LittleEndian));
2892 let mut row = LineRow::new(program.header());
2893
2894 let file = FileEntry {
2895 path_name: AttributeValue::String(EndianSlice::new(b"test.cpp", LittleEndian)),
2896 directory_index: 0,
2897 timestamp: 0,
2898 size: 0,
2899 md5: [0; 16],
2900 source: None,
2901 };
2902
2903 let opcode = LineInstruction::DefineFile(file);
2904 let is_new_row = row.execute(opcode, &mut program).unwrap();
2905
2906 assert!(!is_new_row);
2907 assert_eq!(Some(&file), program.header().file_names.last());
2908 }
2909
2910 #[test]
2911 fn test_exec_set_discriminator() {
2912 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2913 let initial_registers = LineRow::new(&header);
2914 let opcode = LineInstruction::SetDiscriminator(9);
2915
2916 let mut expected_registers = initial_registers;
2917 expected_registers.discriminator = 9;
2918
2919 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2920 }
2921
2922 #[test]
2923 fn test_exec_unknown_extended() {
2924 let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2925 let initial_registers = LineRow::new(&header);
2926 let opcode = LineInstruction::UnknownExtended(
2927 constants::DwLne(74),
2928 EndianSlice::new(&[], LittleEndian),
2929 );
2930 let expected_registers = initial_registers;
2931 assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2932 }
2933
2934 #[allow(dead_code, unreachable_code, unused_variables)]
2937 #[allow(clippy::diverging_sub_expression)]
2938 fn test_line_rows_variance<'a, 'b>(_: &'a [u8], _: &'b [u8])
2939 where
2940 'a: 'b,
2941 {
2942 let a: &OneShotLineRows<EndianSlice<'a, LittleEndian>> = unimplemented!();
2943 let _: &OneShotLineRows<EndianSlice<'b, LittleEndian>> = a;
2944 }
2945
2946 #[test]
2947 fn test_parse_debug_line_v5_ok() {
2948 let expected_lengths = &[1, 2];
2949 let expected_program = &[0, 1, 2, 3, 4];
2950 let expected_rest = &[5, 6, 7, 8, 9];
2951 let expected_include_directories = [
2952 AttributeValue::String(EndianSlice::new(b"dir1", LittleEndian)),
2953 AttributeValue::String(EndianSlice::new(b"dir2", LittleEndian)),
2954 ];
2955 let expected_file_names = [
2956 FileEntry {
2957 path_name: AttributeValue::String(EndianSlice::new(b"file1", LittleEndian)),
2958 directory_index: 0,
2959 timestamp: 0,
2960 size: 0,
2961 md5: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
2962 source: Some(AttributeValue::String(EndianSlice::new(
2963 b"foobar",
2964 LittleEndian,
2965 ))),
2966 },
2967 FileEntry {
2968 path_name: AttributeValue::String(EndianSlice::new(b"file2", LittleEndian)),
2969 directory_index: 1,
2970 timestamp: 0,
2971 size: 0,
2972 md5: [
2973 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
2974 ],
2975 source: Some(AttributeValue::String(EndianSlice::new(
2976 b"quux",
2977 LittleEndian,
2978 ))),
2979 },
2980 ];
2981
2982 for format in [Format::Dwarf32, Format::Dwarf64] {
2983 let length = Label::new();
2984 let header_length = Label::new();
2985 let start = Label::new();
2986 let header_start = Label::new();
2987 let end = Label::new();
2988 let header_end = Label::new();
2989 let section = Section::with_endian(Endian::Little)
2990 .initial_length(format, &length, &start)
2991 .D16(5)
2992 .D8(4)
2994 .D8(0)
2996 .word_label(format.word_size(), &header_length)
2997 .mark(&header_start)
2998 .D8(1)
3000 .D8(1)
3002 .D8(1)
3004 .D8(0)
3006 .D8(1)
3008 .D8(expected_lengths.len() as u8 + 1)
3010 .append_bytes(expected_lengths)
3012 .D8(1)
3014 .uleb(constants::DW_LNCT_path.0 as u64)
3015 .uleb(constants::DW_FORM_string.0 as u64)
3016 .D8(2)
3018 .append_bytes(b"dir1\0")
3019 .append_bytes(b"dir2\0")
3020 .D8(4)
3022 .uleb(constants::DW_LNCT_path.0 as u64)
3023 .uleb(constants::DW_FORM_string.0 as u64)
3024 .uleb(constants::DW_LNCT_directory_index.0 as u64)
3025 .uleb(constants::DW_FORM_data1.0 as u64)
3026 .uleb(constants::DW_LNCT_MD5.0 as u64)
3027 .uleb(constants::DW_FORM_data16.0 as u64)
3028 .uleb(constants::DW_LNCT_LLVM_source.0 as u64)
3029 .uleb(constants::DW_FORM_string.0 as u64)
3030 .D8(2)
3032 .append_bytes(b"file1\0")
3033 .D8(0)
3034 .append_bytes(&expected_file_names[0].md5)
3035 .append_bytes(b"foobar\0")
3036 .append_bytes(b"file2\0")
3037 .D8(1)
3038 .append_bytes(&expected_file_names[1].md5)
3039 .append_bytes(b"quux\0")
3040 .mark(&header_end)
3041 .append_bytes(expected_program)
3043 .mark(&end)
3044 .append_bytes(expected_rest);
3046 length.set_const((&end - &start) as u64);
3047 header_length.set_const((&header_end - &header_start) as u64);
3048 let section = section.get_contents().unwrap();
3049
3050 let input = &mut EndianSlice::new(§ion, LittleEndian);
3051
3052 let header = LineProgramHeader::parse(input, DebugLineOffset(0), 0, None, None)
3053 .expect("should parse header ok");
3054
3055 assert_eq!(header.raw_program_buf().slice(), expected_program);
3056 assert_eq!(input.slice(), expected_rest);
3057
3058 assert_eq!(header.offset, DebugLineOffset(0));
3059 assert_eq!(header.version(), 5);
3060 assert_eq!(header.address_size(), 4);
3061 assert_eq!(header.minimum_instruction_length(), 1);
3062 assert_eq!(header.maximum_operations_per_instruction(), 1);
3063 assert!(header.default_is_stmt());
3064 assert_eq!(header.line_base(), 0);
3065 assert_eq!(header.line_range(), 1);
3066 assert_eq!(header.opcode_base(), expected_lengths.len() as u8 + 1);
3067 assert_eq!(header.standard_opcode_lengths().slice(), expected_lengths);
3068 assert_eq!(
3069 header.directory_entry_format(),
3070 &[FileEntryFormat {
3071 content_type: constants::DW_LNCT_path,
3072 form: constants::DW_FORM_string,
3073 }]
3074 );
3075 assert_eq!(header.include_directories(), expected_include_directories);
3076 assert_eq!(header.directory(0), Some(expected_include_directories[0]));
3077 assert_eq!(
3078 header.file_name_entry_format(),
3079 &[
3080 FileEntryFormat {
3081 content_type: constants::DW_LNCT_path,
3082 form: constants::DW_FORM_string,
3083 },
3084 FileEntryFormat {
3085 content_type: constants::DW_LNCT_directory_index,
3086 form: constants::DW_FORM_data1,
3087 },
3088 FileEntryFormat {
3089 content_type: constants::DW_LNCT_MD5,
3090 form: constants::DW_FORM_data16,
3091 },
3092 FileEntryFormat {
3093 content_type: constants::DW_LNCT_LLVM_source,
3094 form: constants::DW_FORM_string,
3095 }
3096 ]
3097 );
3098 assert_eq!(header.file_names(), expected_file_names);
3099 assert_eq!(header.file(0), Some(&expected_file_names[0]));
3100 }
3101 }
3102
3103 #[test]
3104 fn test_sequences() {
3105 #[rustfmt::skip]
3106 let buf = [
3107 94, 0x00, 0x00, 0x00,
3109 0x04, 0x00,
3111 0x28, 0x00, 0x00, 0x00,
3113 0x01,
3115 0x01,
3117 0x01,
3119 0x00,
3121 0x01,
3123 0x03,
3125 0x01, 0x02,
3127 0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
3129 0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
3132 0x00,
3133 0x00,
3134 0x00,
3135 0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
3137 0x01,
3138 0x00,
3139 0x00,
3140 0x00,
3142
3143 0, 5, constants::DW_LNE_set_address.0, 1, 0, 0, 0,
3144 constants::DW_LNS_copy.0,
3145 constants::DW_LNS_advance_pc.0, 1,
3146 constants::DW_LNS_copy.0,
3147 constants::DW_LNS_advance_pc.0, 2,
3148 0, 1, constants::DW_LNE_end_sequence.0,
3149
3150 0, 5, constants::DW_LNE_set_address.0, 0xff, 0xff, 0xff, 0xff,
3152 constants::DW_LNS_copy.0,
3153 constants::DW_LNS_advance_pc.0, 1,
3154 constants::DW_LNS_copy.0,
3155 constants::DW_LNS_advance_pc.0, 2,
3156 0, 1, constants::DW_LNE_end_sequence.0,
3157
3158 0, 5, constants::DW_LNE_set_address.0, 11, 0, 0, 0,
3159 constants::DW_LNS_copy.0,
3160 constants::DW_LNS_advance_pc.0, 1,
3161 constants::DW_LNS_copy.0,
3162 constants::DW_LNS_advance_pc.0, 2,
3163 0, 1, constants::DW_LNE_end_sequence.0,
3164 ];
3165 assert_eq!(buf[0] as usize, buf.len() - 4);
3166
3167 let rest = &mut EndianSlice::new(&buf, LittleEndian);
3168
3169 let header = LineProgramHeader::parse(rest, DebugLineOffset(0), 4, None, None)
3170 .expect("should parse header ok");
3171 let program = IncompleteLineProgram { header };
3172
3173 let sequences = program.sequences().unwrap().1;
3174 assert_eq!(sequences.len(), 2);
3175 assert_eq!(sequences[0].start, 1);
3176 assert_eq!(sequences[0].end, 4);
3177 assert_eq!(sequences[1].start, 11);
3178 assert_eq!(sequences[1].end, 14);
3179 }
3180}