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);
839                self.tombstone = address < self.address || address == tombstone_address;
840                if !self.tombstone {
841                    self.address = address;
842                    self.op_index.0 = 0;
843                }
844                false
845            }
846
847            LineInstruction::DefineFile(entry) => {
848                program.add_file(entry);
849                false
850            }
851
852            LineInstruction::SetDiscriminator(discriminator) => {
853                self.discriminator = discriminator;
854                false
855            }
856
857            LineInstruction::UnknownStandard0(_)
859            | LineInstruction::UnknownStandard1(_, _)
860            | LineInstruction::UnknownStandardN(_, _)
861            | LineInstruction::UnknownExtended(_, _) => false,
862        })
863    }
864
865    #[inline]
867    pub fn reset<R: Reader>(&mut self, header: &LineProgramHeader<R>) {
868        if self.end_sequence {
869            *self = Self::new(header);
872        } else {
873            self.discriminator = 0;
878            self.basic_block = false;
879            self.prologue_end = false;
880            self.epilogue_begin = false;
881        }
882    }
883
884    fn apply_line_advance(&mut self, line_increment: i64) {
886        if line_increment < 0 {
887            let decrement = -line_increment as u64;
888            if decrement <= self.line.0 {
889                self.line.0 -= decrement;
890            } else {
891                self.line.0 = 0;
892            }
893        } else {
894            self.line += Wrapping(line_increment as u64);
895        }
896    }
897
898    fn apply_operation_advance<R: Reader>(
900        &mut self,
901        operation_advance: u64,
902        header: &LineProgramHeader<R>,
903    ) -> Result<()> {
904        if self.tombstone {
905            return Ok(());
906        }
907
908        let operation_advance = Wrapping(operation_advance);
909
910        let minimum_instruction_length = u64::from(header.line_encoding.minimum_instruction_length);
911        let minimum_instruction_length = Wrapping(minimum_instruction_length);
912
913        let maximum_operations_per_instruction =
914            u64::from(header.line_encoding.maximum_operations_per_instruction);
915        let maximum_operations_per_instruction = Wrapping(maximum_operations_per_instruction);
916
917        let address_advance = if maximum_operations_per_instruction.0 == 1 {
918            self.op_index.0 = 0;
919            minimum_instruction_length * operation_advance
920        } else {
921            let op_index_with_advance = self.op_index + operation_advance;
922            self.op_index = op_index_with_advance % maximum_operations_per_instruction;
923            minimum_instruction_length
924                * (op_index_with_advance / maximum_operations_per_instruction)
925        };
926        self.address = self
927            .address
928            .add_sized(address_advance.0, header.address_size())?;
929        Ok(())
930    }
931
932    #[inline]
933    fn adjust_opcode<R: Reader>(&self, opcode: u8, header: &LineProgramHeader<R>) -> u8 {
934        opcode - header.opcode_base
935    }
936
937    fn exec_special_opcode<R: Reader>(
939        &mut self,
940        opcode: u8,
941        header: &LineProgramHeader<R>,
942    ) -> Result<()> {
943        let adjusted_opcode = self.adjust_opcode(opcode, header);
944
945        let line_range = header.line_encoding.line_range;
946        let line_advance = adjusted_opcode % line_range;
947        let operation_advance = adjusted_opcode / line_range;
948
949        let line_base = i64::from(header.line_encoding.line_base);
951        self.apply_line_advance(line_base + i64::from(line_advance));
952
953        self.apply_operation_advance(u64::from(operation_advance), header)?;
955        Ok(())
956    }
957}
958
959#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
961pub enum ColumnType {
962    LeftEdge,
965    Column(NonZeroU64),
967}
968
969#[deprecated(note = "LineNumberSequence has been renamed to LineSequence, use that instead.")]
971pub type LineNumberSequence<R> = LineSequence<R>;
972
973#[derive(Clone, Debug)]
977pub struct LineSequence<R: Reader> {
978    pub start: u64,
981    pub end: u64,
984    instructions: LineInstructions<R>,
985}
986
987#[deprecated(
989    note = "LineNumberProgramHeader has been renamed to LineProgramHeader, use that instead."
990)]
991pub type LineNumberProgramHeader<R, Offset> = LineProgramHeader<R, Offset>;
992
993#[derive(Clone, Debug, Eq, PartialEq)]
996pub struct LineProgramHeader<R, Offset = <R as Reader>::Offset>
997where
998    R: Reader<Offset = Offset>,
999    Offset: ReaderOffset,
1000{
1001    encoding: Encoding,
1002    offset: DebugLineOffset<Offset>,
1003    unit_length: Offset,
1004
1005    header_length: Offset,
1006
1007    line_encoding: LineEncoding,
1008
1009    opcode_base: u8,
1011
1012    standard_opcode_lengths: R,
1017
1018    directory_entry_format: Vec<FileEntryFormat>,
1020
1021    include_directories: Vec<AttributeValue<R, Offset>>,
1030
1031    file_name_entry_format: Vec<FileEntryFormat>,
1033
1034    file_names: Vec<FileEntry<R, Offset>>,
1038
1039    program_buf: R,
1041
1042    comp_dir: Option<R>,
1044
1045    comp_file: Option<FileEntry<R, Offset>>,
1047}
1048
1049impl<R, Offset> LineProgramHeader<R, Offset>
1050where
1051    R: Reader<Offset = Offset>,
1052    Offset: ReaderOffset,
1053{
1054    pub fn offset(&self) -> DebugLineOffset<R::Offset> {
1056        self.offset
1057    }
1058
1059    pub fn unit_length(&self) -> R::Offset {
1062        self.unit_length
1063    }
1064
1065    pub fn encoding(&self) -> Encoding {
1067        self.encoding
1068    }
1069
1070    pub fn version(&self) -> u16 {
1072        self.encoding.version
1073    }
1074
1075    pub fn header_length(&self) -> R::Offset {
1078        self.header_length
1079    }
1080
1081    pub fn address_size(&self) -> u8 {
1083        self.encoding.address_size
1084    }
1085
1086    pub fn format(&self) -> Format {
1088        self.encoding.format
1089    }
1090
1091    pub fn line_encoding(&self) -> LineEncoding {
1093        self.line_encoding
1094    }
1095
1096    pub fn minimum_instruction_length(&self) -> u8 {
1099        self.line_encoding.minimum_instruction_length
1100    }
1101
1102    pub fn maximum_operations_per_instruction(&self) -> u8 {
1105        self.line_encoding.maximum_operations_per_instruction
1106    }
1107
1108    pub fn default_is_stmt(&self) -> bool {
1111        self.line_encoding.default_is_stmt
1112    }
1113
1114    pub fn line_base(&self) -> i8 {
1116        self.line_encoding.line_base
1117    }
1118
1119    pub fn line_range(&self) -> u8 {
1121        self.line_encoding.line_range
1122    }
1123
1124    pub fn opcode_base(&self) -> u8 {
1126        self.opcode_base
1127    }
1128
1129    pub fn standard_opcode_lengths(&self) -> &R {
1132        &self.standard_opcode_lengths
1133    }
1134
1135    pub fn directory_entry_format(&self) -> &[FileEntryFormat] {
1137        &self.directory_entry_format[..]
1138    }
1139
1140    pub fn include_directories(&self) -> &[AttributeValue<R, Offset>] {
1145        &self.include_directories[..]
1146    }
1147
1148    pub fn directory(&self, directory: u64) -> Option<AttributeValue<R, Offset>> {
1152        if self.encoding.version <= 4 {
1153            if directory == 0 {
1154                self.comp_dir.clone().map(AttributeValue::String)
1155            } else {
1156                let directory = directory as usize - 1;
1157                self.include_directories.get(directory).cloned()
1158            }
1159        } else {
1160            self.include_directories.get(directory as usize).cloned()
1161        }
1162    }
1163
1164    pub fn file_name_entry_format(&self) -> &[FileEntryFormat] {
1166        &self.file_name_entry_format[..]
1167    }
1168
1169    pub fn file_has_timestamp(&self) -> bool {
1174        self.encoding.version <= 4
1175            || self
1176                .file_name_entry_format
1177                .iter()
1178                .any(|x| x.content_type == constants::DW_LNCT_timestamp)
1179    }
1180
1181    pub fn file_has_size(&self) -> bool {
1186        self.encoding.version <= 4
1187            || self
1188                .file_name_entry_format
1189                .iter()
1190                .any(|x| x.content_type == constants::DW_LNCT_size)
1191    }
1192
1193    pub fn file_has_md5(&self) -> bool {
1195        self.file_name_entry_format
1196            .iter()
1197            .any(|x| x.content_type == constants::DW_LNCT_MD5)
1198    }
1199
1200    pub fn file_has_source(&self) -> bool {
1202        self.file_name_entry_format
1203            .iter()
1204            .any(|x| x.content_type == constants::DW_LNCT_LLVM_source)
1205    }
1206
1207    pub fn file_names(&self) -> &[FileEntry<R, Offset>] {
1209        &self.file_names[..]
1210    }
1211
1212    pub fn file(&self, file: u64) -> Option<&FileEntry<R, Offset>> {
1218        if self.encoding.version <= 4 {
1219            if file == 0 {
1220                self.comp_file.as_ref()
1221            } else {
1222                let file = file as usize - 1;
1223                self.file_names.get(file)
1224            }
1225        } else {
1226            self.file_names.get(file as usize)
1227        }
1228    }
1229
1230    pub fn raw_program_buf(&self) -> R {
1249        self.program_buf.clone()
1250    }
1251
1252    pub fn instructions(&self) -> LineInstructions<R> {
1255        LineInstructions {
1256            input: self.program_buf.clone(),
1257        }
1258    }
1259
1260    fn parse(
1261        input: &mut R,
1262        offset: DebugLineOffset<Offset>,
1263        mut address_size: u8,
1264        mut comp_dir: Option<R>,
1265        comp_name: Option<R>,
1266    ) -> Result<LineProgramHeader<R, Offset>> {
1267        let (unit_length, format) = input.read_initial_length()?;
1268        let rest = &mut input.split(unit_length)?;
1269
1270        let version = rest.read_u16()?;
1271        if version < 2 || version > 5 {
1272            return Err(Error::UnknownVersion(u64::from(version)));
1273        }
1274
1275        if version >= 5 {
1276            address_size = rest.read_address_size()?;
1277            let segment_selector_size = rest.read_u8()?;
1278            if segment_selector_size != 0 {
1279                return Err(Error::UnsupportedSegmentSize);
1280            }
1281        }
1282
1283        let encoding = Encoding {
1284            format,
1285            version,
1286            address_size,
1287        };
1288
1289        let header_length = rest.read_length(format)?;
1290
1291        let mut program_buf = rest.clone();
1292        program_buf.skip(header_length)?;
1293        rest.truncate(header_length)?;
1294
1295        let minimum_instruction_length = rest.read_u8()?;
1296        if minimum_instruction_length == 0 {
1297            return Err(Error::MinimumInstructionLengthZero);
1298        }
1299
1300        let maximum_operations_per_instruction = if version >= 4 { rest.read_u8()? } else { 1 };
1303        if maximum_operations_per_instruction == 0 {
1304            return Err(Error::MaximumOperationsPerInstructionZero);
1305        }
1306
1307        let default_is_stmt = rest.read_u8()? != 0;
1308        let line_base = rest.read_i8()?;
1309        let line_range = rest.read_u8()?;
1310        if line_range == 0 {
1311            return Err(Error::LineRangeZero);
1312        }
1313        let line_encoding = LineEncoding {
1314            minimum_instruction_length,
1315            maximum_operations_per_instruction,
1316            default_is_stmt,
1317            line_base,
1318            line_range,
1319        };
1320
1321        let opcode_base = rest.read_u8()?;
1322        if opcode_base == 0 {
1323            return Err(Error::OpcodeBaseZero);
1324        }
1325
1326        let standard_opcode_count = R::Offset::from_u8(opcode_base - 1);
1327        let standard_opcode_lengths = rest.split(standard_opcode_count)?;
1328
1329        let directory_entry_format;
1330        let mut include_directories = Vec::new();
1331        if version <= 4 {
1332            directory_entry_format = Vec::new();
1333            loop {
1334                let directory = rest.read_null_terminated_slice()?;
1335                if directory.is_empty() {
1336                    break;
1337                }
1338                include_directories.push(AttributeValue::String(directory));
1339            }
1340        } else {
1341            comp_dir = None;
1342            directory_entry_format = FileEntryFormat::parse(rest)?;
1343            let count = rest.read_uleb128()?;
1344            for _ in 0..count {
1345                include_directories.push(parse_directory_v5(
1346                    rest,
1347                    encoding,
1348                    &directory_entry_format,
1349                )?);
1350            }
1351        }
1352
1353        let comp_file;
1354        let file_name_entry_format;
1355        let mut file_names = Vec::new();
1356        if version <= 4 {
1357            comp_file = comp_name.map(|name| FileEntry {
1358                path_name: AttributeValue::String(name),
1359                directory_index: 0,
1360                timestamp: 0,
1361                size: 0,
1362                md5: [0; 16],
1363                source: None,
1364            });
1365
1366            file_name_entry_format = Vec::new();
1367            loop {
1368                let path_name = rest.read_null_terminated_slice()?;
1369                if path_name.is_empty() {
1370                    break;
1371                }
1372                file_names.push(FileEntry::parse(rest, path_name)?);
1373            }
1374        } else {
1375            comp_file = None;
1376            file_name_entry_format = FileEntryFormat::parse(rest)?;
1377            let count = rest.read_uleb128()?;
1378            for _ in 0..count {
1379                file_names.push(parse_file_v5(rest, encoding, &file_name_entry_format)?);
1380            }
1381        }
1382
1383        let header = LineProgramHeader {
1384            encoding,
1385            offset,
1386            unit_length,
1387            header_length,
1388            line_encoding,
1389            opcode_base,
1390            standard_opcode_lengths,
1391            directory_entry_format,
1392            include_directories,
1393            file_name_entry_format,
1394            file_names,
1395            program_buf,
1396            comp_dir,
1397            comp_file,
1398        };
1399        Ok(header)
1400    }
1401}
1402
1403#[deprecated(
1405    note = "IncompleteLineNumberProgram has been renamed to IncompleteLineProgram, use that instead."
1406)]
1407pub type IncompleteLineNumberProgram<R, Offset> = IncompleteLineProgram<R, Offset>;
1408
1409#[derive(Clone, Debug, Eq, PartialEq)]
1411pub struct IncompleteLineProgram<R, Offset = <R as Reader>::Offset>
1412where
1413    R: Reader<Offset = Offset>,
1414    Offset: ReaderOffset,
1415{
1416    header: LineProgramHeader<R, Offset>,
1417}
1418
1419impl<R, Offset> IncompleteLineProgram<R, Offset>
1420where
1421    R: Reader<Offset = Offset>,
1422    Offset: ReaderOffset,
1423{
1424    pub fn header(&self) -> &LineProgramHeader<R, Offset> {
1426        &self.header
1427    }
1428
1429    pub fn rows(self) -> OneShotLineRows<R, Offset> {
1432        OneShotLineRows::new(self)
1433    }
1434
1435    #[allow(clippy::type_complexity)]
1456    pub fn sequences(self) -> Result<(CompleteLineProgram<R, Offset>, Vec<LineSequence<R>>)> {
1457        let mut sequences = Vec::new();
1458        let mut rows = self.rows();
1459        let mut instructions = rows.instructions.clone();
1460        let mut sequence_start_addr = None;
1461        loop {
1462            let sequence_end_addr;
1463            if rows.next_row()?.is_none() {
1464                break;
1465            }
1466
1467            let row = &rows.row;
1468            if row.end_sequence() {
1469                sequence_end_addr = row.address();
1470            } else if sequence_start_addr.is_none() {
1471                sequence_start_addr = Some(row.address());
1472                continue;
1473            } else {
1474                continue;
1475            }
1476
1477            sequences.push(LineSequence {
1479                start: sequence_start_addr.unwrap_or(0),
1482                end: sequence_end_addr,
1483                instructions: instructions.remove_trailing(&rows.instructions)?,
1484            });
1485            sequence_start_addr = None;
1486            instructions = rows.instructions.clone();
1487        }
1488
1489        let program = CompleteLineProgram {
1490            header: rows.program.header,
1491        };
1492        Ok((program, sequences))
1493    }
1494}
1495
1496#[deprecated(
1498    note = "CompleteLineNumberProgram has been renamed to CompleteLineProgram, use that instead."
1499)]
1500pub type CompleteLineNumberProgram<R, Offset> = CompleteLineProgram<R, Offset>;
1501
1502#[derive(Clone, Debug, Eq, PartialEq)]
1504pub struct CompleteLineProgram<R, Offset = <R as Reader>::Offset>
1505where
1506    R: Reader<Offset = Offset>,
1507    Offset: ReaderOffset,
1508{
1509    header: LineProgramHeader<R, Offset>,
1510}
1511
1512impl<R, Offset> CompleteLineProgram<R, Offset>
1513where
1514    R: Reader<Offset = Offset>,
1515    Offset: ReaderOffset,
1516{
1517    pub fn header(&self) -> &LineProgramHeader<R, Offset> {
1519        &self.header
1520    }
1521
1522    pub fn resume_from<'program>(
1544        &'program self,
1545        sequence: &LineSequence<R>,
1546    ) -> ResumedLineRows<'program, R, Offset> {
1547        ResumedLineRows::resume(self, sequence)
1548    }
1549}
1550
1551#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1553pub struct FileEntry<R, Offset = <R as Reader>::Offset>
1554where
1555    R: Reader<Offset = Offset>,
1556    Offset: ReaderOffset,
1557{
1558    path_name: AttributeValue<R, Offset>,
1559    directory_index: u64,
1560    timestamp: u64,
1561    size: u64,
1562    md5: [u8; 16],
1563    source: Option<AttributeValue<R, Offset>>,
1564}
1565
1566impl<R, Offset> FileEntry<R, Offset>
1567where
1568    R: Reader<Offset = Offset>,
1569    Offset: ReaderOffset,
1570{
1571    fn parse(input: &mut R, path_name: R) -> Result<FileEntry<R, Offset>> {
1573        let directory_index = input.read_uleb128()?;
1574        let timestamp = input.read_uleb128()?;
1575        let size = input.read_uleb128()?;
1576
1577        let entry = FileEntry {
1578            path_name: AttributeValue::String(path_name),
1579            directory_index,
1580            timestamp,
1581            size,
1582            md5: [0; 16],
1583            source: None,
1584        };
1585
1586        Ok(entry)
1587    }
1588
1589    pub fn path_name(&self) -> AttributeValue<R, Offset> {
1595        self.path_name.clone()
1596    }
1597
1598    pub fn directory_index(&self) -> u64 {
1610        self.directory_index
1611    }
1612
1613    pub fn directory(&self, header: &LineProgramHeader<R>) -> Option<AttributeValue<R, Offset>> {
1617        header.directory(self.directory_index)
1618    }
1619
1620    pub fn timestamp(&self) -> u64 {
1623        self.timestamp
1624    }
1625
1626    #[doc(hidden)]
1630    pub fn last_modification(&self) -> u64 {
1631        self.timestamp
1632    }
1633
1634    pub fn size(&self) -> u64 {
1636        self.size
1637    }
1638
1639    #[doc(hidden)]
1643    pub fn length(&self) -> u64 {
1644        self.size
1645    }
1646
1647    pub fn md5(&self) -> &[u8; 16] {
1651        &self.md5
1652    }
1653
1654    pub fn source(&self) -> Option<AttributeValue<R, Offset>> {
1661        self.source.clone()
1662    }
1663}
1664
1665#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1667pub struct FileEntryFormat {
1668    pub content_type: constants::DwLnct,
1670
1671    pub form: constants::DwForm,
1673}
1674
1675impl FileEntryFormat {
1676    fn parse<R: Reader>(input: &mut R) -> Result<Vec<FileEntryFormat>> {
1677        let format_count = input.read_u8()? as usize;
1678        let mut format = Vec::with_capacity(format_count);
1679        let mut path_count = 0;
1680        for _ in 0..format_count {
1681            let content_type = input.read_uleb128()?;
1682            let content_type = if content_type > u64::from(u16::MAX) {
1683                constants::DwLnct(u16::MAX)
1684            } else {
1685                constants::DwLnct(content_type as u16)
1686            };
1687            if content_type == constants::DW_LNCT_path {
1688                path_count += 1;
1689            }
1690
1691            let form = constants::DwForm(input.read_uleb128_u16()?);
1692
1693            format.push(FileEntryFormat { content_type, form });
1694        }
1695        if path_count != 1 {
1696            return Err(Error::MissingFileEntryFormatPath);
1697        }
1698        Ok(format)
1699    }
1700}
1701
1702fn parse_directory_v5<R: Reader>(
1703    input: &mut R,
1704    encoding: Encoding,
1705    formats: &[FileEntryFormat],
1706) -> Result<AttributeValue<R>> {
1707    let mut path_name = None;
1708
1709    for format in formats {
1710        let value = parse_attribute(input, encoding, format.form)?;
1711        if format.content_type == constants::DW_LNCT_path {
1712            path_name = Some(value);
1713        }
1714    }
1715
1716    Ok(path_name.unwrap())
1717}
1718
1719fn parse_file_v5<R: Reader>(
1720    input: &mut R,
1721    encoding: Encoding,
1722    formats: &[FileEntryFormat],
1723) -> Result<FileEntry<R>> {
1724    let mut path_name = None;
1725    let mut directory_index = 0;
1726    let mut timestamp = 0;
1727    let mut size = 0;
1728    let mut md5 = [0; 16];
1729    let mut source = None;
1730
1731    for format in formats {
1732        let value = parse_attribute(input, encoding, format.form)?;
1733        match format.content_type {
1734            constants::DW_LNCT_path => path_name = Some(value),
1735            constants::DW_LNCT_directory_index => {
1736                if let Some(value) = value.udata_value() {
1737                    directory_index = value;
1738                }
1739            }
1740            constants::DW_LNCT_timestamp => {
1741                if let Some(value) = value.udata_value() {
1742                    timestamp = value;
1743                }
1744            }
1745            constants::DW_LNCT_size => {
1746                if let Some(value) = value.udata_value() {
1747                    size = value;
1748                }
1749            }
1750            constants::DW_LNCT_MD5 => {
1751                if let AttributeValue::Block(mut value) = value {
1752                    if value.len().into_u64() == 16 {
1753                        md5 = value.read_u8_array()?;
1754                    }
1755                }
1756            }
1757            constants::DW_LNCT_LLVM_source => {
1758                source = Some(value);
1759            }
1760            _ => {}
1762        }
1763    }
1764
1765    Ok(FileEntry {
1766        path_name: path_name.unwrap(),
1767        directory_index,
1768        timestamp,
1769        size,
1770        md5,
1771        source,
1772    })
1773}
1774
1775fn parse_attribute<R: Reader>(
1777    input: &mut R,
1778    encoding: Encoding,
1779    form: constants::DwForm,
1780) -> Result<AttributeValue<R>> {
1781    Ok(match form {
1782        constants::DW_FORM_block1 => {
1783            let len = input.read_u8().map(R::Offset::from_u8)?;
1784            let block = input.split(len)?;
1785            AttributeValue::Block(block)
1786        }
1787        constants::DW_FORM_block2 => {
1788            let len = input.read_u16().map(R::Offset::from_u16)?;
1789            let block = input.split(len)?;
1790            AttributeValue::Block(block)
1791        }
1792        constants::DW_FORM_block4 => {
1793            let len = input.read_u32().map(R::Offset::from_u32)?;
1794            let block = input.split(len)?;
1795            AttributeValue::Block(block)
1796        }
1797        constants::DW_FORM_block => {
1798            let len = input.read_uleb128().and_then(R::Offset::from_u64)?;
1799            let block = input.split(len)?;
1800            AttributeValue::Block(block)
1801        }
1802        constants::DW_FORM_data1 => {
1803            let data = input.read_u8()?;
1804            AttributeValue::Data1(data)
1805        }
1806        constants::DW_FORM_data2 => {
1807            let data = input.read_u16()?;
1808            AttributeValue::Data2(data)
1809        }
1810        constants::DW_FORM_data4 => {
1811            let data = input.read_u32()?;
1812            AttributeValue::Data4(data)
1813        }
1814        constants::DW_FORM_data8 => {
1815            let data = input.read_u64()?;
1816            AttributeValue::Data8(data)
1817        }
1818        constants::DW_FORM_data16 => {
1819            let block = input.split(R::Offset::from_u8(16))?;
1820            AttributeValue::Block(block)
1821        }
1822        constants::DW_FORM_udata => {
1823            let data = input.read_uleb128()?;
1824            AttributeValue::Udata(data)
1825        }
1826        constants::DW_FORM_sdata => {
1827            let data = input.read_sleb128()?;
1828            AttributeValue::Sdata(data)
1829        }
1830        constants::DW_FORM_flag => {
1831            let present = input.read_u8()?;
1832            AttributeValue::Flag(present != 0)
1833        }
1834        constants::DW_FORM_sec_offset => {
1835            let offset = input.read_offset(encoding.format)?;
1836            AttributeValue::SecOffset(offset)
1837        }
1838        constants::DW_FORM_string => {
1839            let string = input.read_null_terminated_slice()?;
1840            AttributeValue::String(string)
1841        }
1842        constants::DW_FORM_strp => {
1843            let offset = input.read_offset(encoding.format)?;
1844            AttributeValue::DebugStrRef(DebugStrOffset(offset))
1845        }
1846        constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt => {
1847            let offset = input.read_offset(encoding.format)?;
1848            AttributeValue::DebugStrRefSup(DebugStrOffset(offset))
1849        }
1850        constants::DW_FORM_line_strp => {
1851            let offset = input.read_offset(encoding.format)?;
1852            AttributeValue::DebugLineStrRef(DebugLineStrOffset(offset))
1853        }
1854        constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => {
1855            let index = input.read_uleb128().and_then(R::Offset::from_u64)?;
1856            AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1857        }
1858        constants::DW_FORM_strx1 => {
1859            let index = input.read_u8().map(R::Offset::from_u8)?;
1860            AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1861        }
1862        constants::DW_FORM_strx2 => {
1863            let index = input.read_u16().map(R::Offset::from_u16)?;
1864            AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1865        }
1866        constants::DW_FORM_strx3 => {
1867            let index = input.read_uint(3).and_then(R::Offset::from_u64)?;
1868            AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1869        }
1870        constants::DW_FORM_strx4 => {
1871            let index = input.read_u32().map(R::Offset::from_u32)?;
1872            AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1873        }
1874        _ => {
1875            return Err(Error::UnknownForm(form));
1876        }
1877    })
1878}
1879
1880#[cfg(test)]
1881mod tests {
1882    use super::*;
1883    use crate::constants;
1884    use crate::endianity::LittleEndian;
1885    use crate::read::{EndianSlice, Error};
1886    use crate::test_util::GimliSectionMethods;
1887    use test_assembler::{Endian, Label, LabelMaker, Section};
1888
1889    #[test]
1890    fn test_parse_debug_line_32_ok() {
1891        #[rustfmt::skip]
1892        let buf = [
1893            0x3e, 0x00, 0x00, 0x00,
1895            0x04, 0x00,
1897            0x28, 0x00, 0x00, 0x00,
1899            0x01,
1901            0x01,
1903            0x01,
1905            0x00,
1907            0x01,
1909            0x03,
1911            0x01, 0x02,
1913            0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
1915            0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
1918                0x00,
1919                0x00,
1920                0x00,
1921                0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
1923                0x01,
1924                0x00,
1925                0x00,
1926            0x00,
1928
1929            0x00, 0x00, 0x00, 0x00,
1931            0x00, 0x00, 0x00, 0x00,
1932            0x00, 0x00, 0x00, 0x00,
1933            0x00, 0x00, 0x00, 0x00,
1934
1935            0x00, 0x00, 0x00, 0x00,
1937            0x00, 0x00, 0x00, 0x00,
1938            0x00, 0x00, 0x00, 0x00,
1939            0x00, 0x00, 0x00, 0x00,
1940        ];
1941
1942        let rest = &mut EndianSlice::new(&buf, LittleEndian);
1943        let comp_dir = EndianSlice::new(b"/comp_dir", LittleEndian);
1944        let comp_name = EndianSlice::new(b"/comp_name", LittleEndian);
1945
1946        let header =
1947            LineProgramHeader::parse(rest, DebugLineOffset(0), 4, Some(comp_dir), Some(comp_name))
1948                .expect("should parse header ok");
1949
1950        assert_eq!(
1951            *rest,
1952            EndianSlice::new(&buf[buf.len() - 16..], LittleEndian)
1953        );
1954
1955        assert_eq!(header.offset, DebugLineOffset(0));
1956        assert_eq!(header.version(), 4);
1957        assert_eq!(header.minimum_instruction_length(), 1);
1958        assert_eq!(header.maximum_operations_per_instruction(), 1);
1959        assert!(header.default_is_stmt());
1960        assert_eq!(header.line_base(), 0);
1961        assert_eq!(header.line_range(), 1);
1962        assert_eq!(header.opcode_base(), 3);
1963        assert_eq!(header.directory(0), Some(AttributeValue::String(comp_dir)));
1964        assert_eq!(
1965            header.file(0).unwrap().path_name,
1966            AttributeValue::String(comp_name)
1967        );
1968
1969        let expected_lengths = [1, 2];
1970        assert_eq!(header.standard_opcode_lengths().slice(), &expected_lengths);
1971
1972        let expected_include_directories = [
1973            AttributeValue::String(EndianSlice::new(b"/inc", LittleEndian)),
1974            AttributeValue::String(EndianSlice::new(b"/inc2", LittleEndian)),
1975        ];
1976        assert_eq!(header.include_directories(), &expected_include_directories);
1977
1978        let expected_file_names = [
1979            FileEntry {
1980                path_name: AttributeValue::String(EndianSlice::new(b"foo.rs", LittleEndian)),
1981                directory_index: 0,
1982                timestamp: 0,
1983                size: 0,
1984                md5: [0; 16],
1985                source: None,
1986            },
1987            FileEntry {
1988                path_name: AttributeValue::String(EndianSlice::new(b"bar.h", LittleEndian)),
1989                directory_index: 1,
1990                timestamp: 0,
1991                size: 0,
1992                md5: [0; 16],
1993                source: None,
1994            },
1995        ];
1996        assert_eq!(header.file_names(), &expected_file_names);
1997    }
1998
1999    #[test]
2000    fn test_parse_debug_line_header_length_too_short() {
2001        #[rustfmt::skip]
2002        let buf = [
2003            0x3e, 0x00, 0x00, 0x00,
2005            0x04, 0x00,
2007            0x15, 0x00, 0x00, 0x00,
2009            0x01,
2011            0x01,
2013            0x01,
2015            0x00,
2017            0x01,
2019            0x03,
2021            0x01, 0x02,
2023            0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
2025            0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
2028                0x00,
2029                0x00,
2030                0x00,
2031                0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
2033                0x01,
2034                0x00,
2035                0x00,
2036            0x00,
2038
2039            0x00, 0x00, 0x00, 0x00,
2041            0x00, 0x00, 0x00, 0x00,
2042            0x00, 0x00, 0x00, 0x00,
2043            0x00, 0x00, 0x00, 0x00,
2044
2045            0x00, 0x00, 0x00, 0x00,
2047            0x00, 0x00, 0x00, 0x00,
2048            0x00, 0x00, 0x00, 0x00,
2049            0x00, 0x00, 0x00, 0x00,
2050        ];
2051
2052        let input = &mut EndianSlice::new(&buf, LittleEndian);
2053
2054        match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) {
2055            Err(Error::UnexpectedEof(_)) => {}
2056            otherwise => panic!("Unexpected result: {:?}", otherwise),
2057        }
2058    }
2059
2060    #[test]
2061    fn test_parse_debug_line_unit_length_too_short() {
2062        #[rustfmt::skip]
2063        let buf = [
2064            0x28, 0x00, 0x00, 0x00,
2066            0x04, 0x00,
2068            0x28, 0x00, 0x00, 0x00,
2070            0x01,
2072            0x01,
2074            0x01,
2076            0x00,
2078            0x01,
2080            0x03,
2082            0x01, 0x02,
2084            0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
2086            0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
2089                0x00,
2090                0x00,
2091                0x00,
2092                0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
2094                0x01,
2095                0x00,
2096                0x00,
2097            0x00,
2099
2100            0x00, 0x00, 0x00, 0x00,
2102            0x00, 0x00, 0x00, 0x00,
2103            0x00, 0x00, 0x00, 0x00,
2104            0x00, 0x00, 0x00, 0x00,
2105
2106            0x00, 0x00, 0x00, 0x00,
2108            0x00, 0x00, 0x00, 0x00,
2109            0x00, 0x00, 0x00, 0x00,
2110            0x00, 0x00, 0x00, 0x00,
2111        ];
2112
2113        let input = &mut EndianSlice::new(&buf, LittleEndian);
2114
2115        match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) {
2116            Err(Error::UnexpectedEof(_)) => {}
2117            otherwise => panic!("Unexpected result: {:?}", otherwise),
2118        }
2119    }
2120
2121    const OPCODE_BASE: u8 = 13;
2122    const STANDARD_OPCODE_LENGTHS: &[u8] = &[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1];
2123
2124    fn make_test_header(
2125        buf: EndianSlice<'_, LittleEndian>,
2126    ) -> LineProgramHeader<EndianSlice<'_, LittleEndian>> {
2127        let encoding = Encoding {
2128            format: Format::Dwarf32,
2129            version: 4,
2130            address_size: 8,
2131        };
2132        let line_encoding = LineEncoding {
2133            line_base: -3,
2134            line_range: 12,
2135            ..Default::default()
2136        };
2137        LineProgramHeader {
2138            encoding,
2139            offset: DebugLineOffset(0),
2140            unit_length: 1,
2141            header_length: 1,
2142            line_encoding,
2143            opcode_base: OPCODE_BASE,
2144            standard_opcode_lengths: EndianSlice::new(STANDARD_OPCODE_LENGTHS, LittleEndian),
2145            file_names: vec![
2146                FileEntry {
2147                    path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)),
2148                    directory_index: 0,
2149                    timestamp: 0,
2150                    size: 0,
2151                    md5: [0; 16],
2152                    source: None,
2153                },
2154                FileEntry {
2155                    path_name: AttributeValue::String(EndianSlice::new(b"bar.rs", LittleEndian)),
2156                    directory_index: 0,
2157                    timestamp: 0,
2158                    size: 0,
2159                    md5: [0; 16],
2160                    source: None,
2161                },
2162            ],
2163            include_directories: vec![],
2164            directory_entry_format: vec![],
2165            file_name_entry_format: vec![],
2166            program_buf: buf,
2167            comp_dir: None,
2168            comp_file: None,
2169        }
2170    }
2171
2172    fn make_test_program(
2173        buf: EndianSlice<'_, LittleEndian>,
2174    ) -> IncompleteLineProgram<EndianSlice<'_, LittleEndian>> {
2175        IncompleteLineProgram {
2176            header: make_test_header(buf),
2177        }
2178    }
2179
2180    #[test]
2181    fn test_parse_special_opcodes() {
2182        for i in OPCODE_BASE..u8::MAX {
2183            let input = [i, 0, 0, 0];
2184            let input = EndianSlice::new(&input, LittleEndian);
2185            let header = make_test_header(input);
2186
2187            let mut rest = input;
2188            let opcode =
2189                LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2190
2191            assert_eq!(*rest, *input.range_from(1..));
2192            assert_eq!(opcode, LineInstruction::Special(i));
2193        }
2194    }
2195
2196    #[test]
2197    fn test_parse_standard_opcodes() {
2198        fn test<Operands>(
2199            raw: constants::DwLns,
2200            operands: Operands,
2201            expected: LineInstruction<EndianSlice<'_, LittleEndian>>,
2202        ) where
2203            Operands: AsRef<[u8]>,
2204        {
2205            let mut input = Vec::new();
2206            input.push(raw.0);
2207            input.extend_from_slice(operands.as_ref());
2208
2209            let expected_rest = [0, 1, 2, 3, 4];
2210            input.extend_from_slice(&expected_rest);
2211
2212            let input = EndianSlice::new(&input, LittleEndian);
2213            let header = make_test_header(input);
2214
2215            let mut rest = input;
2216            let opcode =
2217                LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2218
2219            assert_eq!(opcode, expected);
2220            assert_eq!(*rest, expected_rest);
2221        }
2222
2223        test(constants::DW_LNS_copy, [], LineInstruction::Copy);
2224        test(
2225            constants::DW_LNS_advance_pc,
2226            [42],
2227            LineInstruction::AdvancePc(42),
2228        );
2229        test(
2230            constants::DW_LNS_advance_line,
2231            [9],
2232            LineInstruction::AdvanceLine(9),
2233        );
2234        test(constants::DW_LNS_set_file, [7], LineInstruction::SetFile(7));
2235        test(
2236            constants::DW_LNS_set_column,
2237            [1],
2238            LineInstruction::SetColumn(1),
2239        );
2240        test(
2241            constants::DW_LNS_negate_stmt,
2242            [],
2243            LineInstruction::NegateStatement,
2244        );
2245        test(
2246            constants::DW_LNS_set_basic_block,
2247            [],
2248            LineInstruction::SetBasicBlock,
2249        );
2250        test(
2251            constants::DW_LNS_const_add_pc,
2252            [],
2253            LineInstruction::ConstAddPc,
2254        );
2255        test(
2256            constants::DW_LNS_fixed_advance_pc,
2257            [42, 0],
2258            LineInstruction::FixedAddPc(42),
2259        );
2260        test(
2261            constants::DW_LNS_set_prologue_end,
2262            [],
2263            LineInstruction::SetPrologueEnd,
2264        );
2265        test(
2266            constants::DW_LNS_set_isa,
2267            [57 + 0x80, 100],
2268            LineInstruction::SetIsa(12857),
2269        );
2270    }
2271
2272    #[test]
2273    fn test_parse_unknown_standard_opcode_no_args() {
2274        let input = [OPCODE_BASE, 1, 2, 3];
2275        let input = EndianSlice::new(&input, LittleEndian);
2276        let mut standard_opcode_lengths = Vec::new();
2277        let mut header = make_test_header(input);
2278        standard_opcode_lengths.extend(header.standard_opcode_lengths.slice());
2279        standard_opcode_lengths.push(0);
2280        header.opcode_base += 1;
2281        header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian);
2282
2283        let mut rest = input;
2284        let opcode =
2285            LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2286
2287        assert_eq!(
2288            opcode,
2289            LineInstruction::UnknownStandard0(constants::DwLns(OPCODE_BASE))
2290        );
2291        assert_eq!(*rest, *input.range_from(1..));
2292    }
2293
2294    #[test]
2295    fn test_parse_unknown_standard_opcode_one_arg() {
2296        let input = [OPCODE_BASE, 1, 2, 3];
2297        let input = EndianSlice::new(&input, LittleEndian);
2298        let mut standard_opcode_lengths = Vec::new();
2299        let mut header = make_test_header(input);
2300        standard_opcode_lengths.extend(header.standard_opcode_lengths.slice());
2301        standard_opcode_lengths.push(1);
2302        header.opcode_base += 1;
2303        header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian);
2304
2305        let mut rest = input;
2306        let opcode =
2307            LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2308
2309        assert_eq!(
2310            opcode,
2311            LineInstruction::UnknownStandard1(constants::DwLns(OPCODE_BASE), 1)
2312        );
2313        assert_eq!(*rest, *input.range_from(2..));
2314    }
2315
2316    #[test]
2317    fn test_parse_unknown_standard_opcode_many_args() {
2318        let input = [OPCODE_BASE, 1, 2, 3];
2319        let input = EndianSlice::new(&input, LittleEndian);
2320        let args = input.range_from(1..);
2321        let mut standard_opcode_lengths = Vec::new();
2322        let mut header = make_test_header(input);
2323        standard_opcode_lengths.extend(header.standard_opcode_lengths.slice());
2324        standard_opcode_lengths.push(3);
2325        header.opcode_base += 1;
2326        header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian);
2327
2328        let mut rest = input;
2329        let opcode =
2330            LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2331
2332        assert_eq!(
2333            opcode,
2334            LineInstruction::UnknownStandardN(constants::DwLns(OPCODE_BASE), args)
2335        );
2336        assert_eq!(*rest, []);
2337    }
2338
2339    #[test]
2340    fn test_parse_extended_opcodes() {
2341        fn test<Operands>(
2342            raw: constants::DwLne,
2343            operands: Operands,
2344            expected: LineInstruction<EndianSlice<'_, LittleEndian>>,
2345        ) where
2346            Operands: AsRef<[u8]>,
2347        {
2348            let mut input = Vec::new();
2349            input.push(0);
2350
2351            let operands = operands.as_ref();
2352            input.push(1 + operands.len() as u8);
2353
2354            input.push(raw.0);
2355            input.extend_from_slice(operands);
2356
2357            let expected_rest = [0, 1, 2, 3, 4];
2358            input.extend_from_slice(&expected_rest);
2359
2360            let input = EndianSlice::new(&input, LittleEndian);
2361            let header = make_test_header(input);
2362
2363            let mut rest = input;
2364            let opcode =
2365                LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2366
2367            assert_eq!(opcode, expected);
2368            assert_eq!(*rest, expected_rest);
2369        }
2370
2371        test(
2372            constants::DW_LNE_end_sequence,
2373            [],
2374            LineInstruction::EndSequence,
2375        );
2376        test(
2377            constants::DW_LNE_set_address,
2378            [1, 2, 3, 4, 5, 6, 7, 8],
2379            LineInstruction::SetAddress(578_437_695_752_307_201),
2380        );
2381        test(
2382            constants::DW_LNE_set_discriminator,
2383            [42],
2384            LineInstruction::SetDiscriminator(42),
2385        );
2386
2387        let mut file = Vec::new();
2388        let path_name = [b'f', b'o', b'o', b'.', b'c', 0];
2390        file.extend_from_slice(&path_name);
2391        file.push(0);
2393        file.push(1);
2395        file.push(2);
2397
2398        test(
2399            constants::DW_LNE_define_file,
2400            file,
2401            LineInstruction::DefineFile(FileEntry {
2402                path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)),
2403                directory_index: 0,
2404                timestamp: 1,
2405                size: 2,
2406                md5: [0; 16],
2407                source: None,
2408            }),
2409        );
2410
2411        let operands = [1, 2, 3, 4, 5, 6];
2413        let opcode = constants::DwLne(99);
2414        test(
2415            opcode,
2416            operands,
2417            LineInstruction::UnknownExtended(opcode, EndianSlice::new(&operands, LittleEndian)),
2418        );
2419    }
2420
2421    #[test]
2422    fn test_file_entry_directory() {
2423        let path_name = [b'f', b'o', b'o', b'.', b'r', b's', 0];
2424
2425        let mut file = FileEntry {
2426            path_name: AttributeValue::String(EndianSlice::new(&path_name, LittleEndian)),
2427            directory_index: 1,
2428            timestamp: 0,
2429            size: 0,
2430            md5: [0; 16],
2431            source: None,
2432        };
2433
2434        let mut header = make_test_header(EndianSlice::new(&[], LittleEndian));
2435
2436        let dir = AttributeValue::String(EndianSlice::new(b"dir", LittleEndian));
2437        header.include_directories.push(dir);
2438
2439        assert_eq!(file.directory(&header), Some(dir));
2440
2441        file.directory_index = 0;
2443        assert_eq!(file.directory(&header), None);
2444    }
2445
2446    fn assert_exec_opcode<'input>(
2447        header: LineProgramHeader<EndianSlice<'input, LittleEndian>>,
2448        mut registers: LineRow,
2449        opcode: LineInstruction<EndianSlice<'input, LittleEndian>>,
2450        expected_registers: LineRow,
2451        expect_new_row: bool,
2452    ) {
2453        let mut program = IncompleteLineProgram { header };
2454        let is_new_row = registers.execute(opcode, &mut program);
2455
2456        assert_eq!(is_new_row, Ok(expect_new_row));
2457        assert_eq!(registers, expected_registers);
2458    }
2459
2460    #[test]
2461    fn test_exec_special_noop() {
2462        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2463
2464        let initial_registers = LineRow::new(&header);
2465        let opcode = LineInstruction::Special(16);
2466        let expected_registers = initial_registers;
2467
2468        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2469    }
2470
2471    #[test]
2472    fn test_exec_special_negative_line_advance() {
2473        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2474
2475        let mut initial_registers = LineRow::new(&header);
2476        initial_registers.line.0 = 10;
2477
2478        let opcode = LineInstruction::Special(13);
2479
2480        let mut expected_registers = initial_registers;
2481        expected_registers.line.0 -= 3;
2482
2483        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2484    }
2485
2486    #[test]
2487    fn test_exec_special_positive_line_advance() {
2488        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2489
2490        let initial_registers = LineRow::new(&header);
2491
2492        let opcode = LineInstruction::Special(19);
2493
2494        let mut expected_registers = initial_registers;
2495        expected_registers.line.0 += 3;
2496
2497        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2498    }
2499
2500    #[test]
2501    fn test_exec_special_positive_address_advance() {
2502        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2503
2504        let initial_registers = LineRow::new(&header);
2505
2506        let opcode = LineInstruction::Special(52);
2507
2508        let mut expected_registers = initial_registers;
2509        expected_registers.address += 3;
2510
2511        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2512    }
2513
2514    #[test]
2515    fn test_exec_special_positive_address_and_line_advance() {
2516        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2517
2518        let initial_registers = LineRow::new(&header);
2519
2520        let opcode = LineInstruction::Special(55);
2521
2522        let mut expected_registers = initial_registers;
2523        expected_registers.address += 3;
2524        expected_registers.line.0 += 3;
2525
2526        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2527    }
2528
2529    #[test]
2530    fn test_exec_special_positive_address_and_negative_line_advance() {
2531        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2532
2533        let mut initial_registers = LineRow::new(&header);
2534        initial_registers.line.0 = 10;
2535
2536        let opcode = LineInstruction::Special(49);
2537
2538        let mut expected_registers = initial_registers;
2539        expected_registers.address += 3;
2540        expected_registers.line.0 -= 3;
2541
2542        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2543    }
2544
2545    #[test]
2546    fn test_exec_special_line_underflow() {
2547        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2548
2549        let mut initial_registers = LineRow::new(&header);
2550        initial_registers.line.0 = 2;
2551
2552        let opcode = LineInstruction::Special(13);
2554
2555        let mut expected_registers = initial_registers;
2556        expected_registers.line.0 = 0;
2559
2560        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2561    }
2562
2563    #[test]
2564    fn test_exec_copy() {
2565        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2566
2567        let mut initial_registers = LineRow::new(&header);
2568        initial_registers.address = 1337;
2569        initial_registers.line.0 = 42;
2570
2571        let opcode = LineInstruction::Copy;
2572
2573        let expected_registers = initial_registers;
2574
2575        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2576    }
2577
2578    #[test]
2579    fn test_exec_advance_pc() {
2580        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2581        let initial_registers = LineRow::new(&header);
2582        let opcode = LineInstruction::AdvancePc(42);
2583
2584        let mut expected_registers = initial_registers;
2585        expected_registers.address += 42;
2586
2587        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2588    }
2589
2590    #[test]
2591    fn test_exec_advance_pc_overflow_32() {
2592        let mut header = make_test_header(EndianSlice::new(&[], LittleEndian));
2593        header.encoding.address_size = 4;
2594        let mut registers = LineRow::new(&header);
2595        registers.address = u32::MAX.into();
2596        let opcode = LineInstruction::AdvancePc(42);
2597        let mut program = IncompleteLineProgram { header };
2598        let result = registers.execute(opcode, &mut program);
2599        assert_eq!(result, Err(Error::AddressOverflow));
2600    }
2601
2602    #[test]
2603    fn test_exec_advance_pc_overflow_64() {
2604        let mut header = make_test_header(EndianSlice::new(&[], LittleEndian));
2605        header.encoding.address_size = 8;
2606        let mut registers = LineRow::new(&header);
2607        registers.address = u64::MAX;
2608        let opcode = LineInstruction::AdvancePc(42);
2609        let mut program = IncompleteLineProgram { header };
2610        let result = registers.execute(opcode, &mut program);
2611        assert_eq!(result, Err(Error::AddressOverflow));
2612    }
2613
2614    #[test]
2615    fn test_exec_advance_line() {
2616        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2617        let initial_registers = LineRow::new(&header);
2618        let opcode = LineInstruction::AdvanceLine(42);
2619
2620        let mut expected_registers = initial_registers;
2621        expected_registers.line.0 += 42;
2622
2623        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2624    }
2625
2626    #[test]
2627    fn test_exec_advance_line_overflow() {
2628        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2629        let opcode = LineInstruction::AdvanceLine(42);
2630
2631        let mut initial_registers = LineRow::new(&header);
2632        initial_registers.line.0 = u64::MAX;
2633
2634        let mut expected_registers = initial_registers;
2635        expected_registers.line.0 = 41;
2636
2637        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2638    }
2639
2640    #[test]
2641    fn test_exec_set_file_in_bounds() {
2642        for file_idx in 1..3 {
2643            let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2644            let initial_registers = LineRow::new(&header);
2645            let opcode = LineInstruction::SetFile(file_idx);
2646
2647            let mut expected_registers = initial_registers;
2648            expected_registers.file = file_idx;
2649
2650            assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2651        }
2652    }
2653
2654    #[test]
2655    fn test_exec_set_file_out_of_bounds() {
2656        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2657        let initial_registers = LineRow::new(&header);
2658        let opcode = LineInstruction::SetFile(100);
2659
2660        let mut expected_registers = initial_registers;
2667        expected_registers.file = 100;
2668
2669        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2670    }
2671
2672    #[test]
2673    fn test_file_entry_file_index_out_of_bounds() {
2674        let out_of_bounds_indices = [0, 100];
2677
2678        for file_idx in &out_of_bounds_indices[..] {
2679            let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2680            let mut row = LineRow::new(&header);
2681
2682            row.file = *file_idx;
2683
2684            assert_eq!(row.file(&header), None);
2685        }
2686    }
2687
2688    #[test]
2689    fn test_file_entry_file_index_in_bounds() {
2690        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2691        let mut row = LineRow::new(&header);
2692
2693        row.file = 2;
2694
2695        assert_eq!(row.file(&header), Some(&header.file_names()[1]));
2696    }
2697
2698    #[test]
2699    fn test_exec_set_column() {
2700        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2701        let initial_registers = LineRow::new(&header);
2702        let opcode = LineInstruction::SetColumn(42);
2703
2704        let mut expected_registers = initial_registers;
2705        expected_registers.column = 42;
2706
2707        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2708    }
2709
2710    #[test]
2711    fn test_exec_negate_statement() {
2712        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2713        let initial_registers = LineRow::new(&header);
2714        let opcode = LineInstruction::NegateStatement;
2715
2716        let mut expected_registers = initial_registers;
2717        expected_registers.is_stmt = !initial_registers.is_stmt;
2718
2719        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2720    }
2721
2722    #[test]
2723    fn test_exec_set_basic_block() {
2724        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2725
2726        let mut initial_registers = LineRow::new(&header);
2727        initial_registers.basic_block = false;
2728
2729        let opcode = LineInstruction::SetBasicBlock;
2730
2731        let mut expected_registers = initial_registers;
2732        expected_registers.basic_block = true;
2733
2734        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2735    }
2736
2737    #[test]
2738    fn test_exec_const_add_pc() {
2739        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2740        let initial_registers = LineRow::new(&header);
2741        let opcode = LineInstruction::ConstAddPc;
2742
2743        let mut expected_registers = initial_registers;
2744        expected_registers.address += 20;
2745
2746        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2747    }
2748
2749    #[test]
2750    fn test_exec_const_add_pc_overflow() {
2751        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2752        let mut registers = LineRow::new(&header);
2753        registers.address = u64::MAX;
2754        let opcode = LineInstruction::ConstAddPc;
2755        let mut program = IncompleteLineProgram { header };
2756        let result = registers.execute(opcode, &mut program);
2757        assert_eq!(result, Err(Error::AddressOverflow));
2758    }
2759
2760    #[test]
2761    fn test_exec_fixed_add_pc() {
2762        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2763
2764        let mut initial_registers = LineRow::new(&header);
2765        initial_registers.op_index.0 = 1;
2766
2767        let opcode = LineInstruction::FixedAddPc(10);
2768
2769        let mut expected_registers = initial_registers;
2770        expected_registers.address += 10;
2771        expected_registers.op_index.0 = 0;
2772
2773        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2774    }
2775
2776    #[test]
2777    fn test_exec_fixed_add_pc_overflow() {
2778        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2779        let mut registers = LineRow::new(&header);
2780        registers.address = u64::MAX;
2781        registers.op_index.0 = 1;
2782        let opcode = LineInstruction::FixedAddPc(10);
2783        let mut program = IncompleteLineProgram { header };
2784        let result = registers.execute(opcode, &mut program);
2785        assert_eq!(result, Err(Error::AddressOverflow));
2786    }
2787
2788    #[test]
2789    fn test_exec_set_prologue_end() {
2790        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2791
2792        let mut initial_registers = LineRow::new(&header);
2793        initial_registers.prologue_end = false;
2794
2795        let opcode = LineInstruction::SetPrologueEnd;
2796
2797        let mut expected_registers = initial_registers;
2798        expected_registers.prologue_end = true;
2799
2800        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2801    }
2802
2803    #[test]
2804    fn test_exec_set_isa() {
2805        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2806        let initial_registers = LineRow::new(&header);
2807        let opcode = LineInstruction::SetIsa(1993);
2808
2809        let mut expected_registers = initial_registers;
2810        expected_registers.isa = 1993;
2811
2812        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2813    }
2814
2815    #[test]
2816    fn test_exec_unknown_standard_0() {
2817        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2818        let initial_registers = LineRow::new(&header);
2819        let opcode = LineInstruction::UnknownStandard0(constants::DwLns(111));
2820        let expected_registers = initial_registers;
2821        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2822    }
2823
2824    #[test]
2825    fn test_exec_unknown_standard_1() {
2826        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2827        let initial_registers = LineRow::new(&header);
2828        let opcode = LineInstruction::UnknownStandard1(constants::DwLns(111), 2);
2829        let expected_registers = initial_registers;
2830        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2831    }
2832
2833    #[test]
2834    fn test_exec_unknown_standard_n() {
2835        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2836        let initial_registers = LineRow::new(&header);
2837        let opcode = LineInstruction::UnknownStandardN(
2838            constants::DwLns(111),
2839            EndianSlice::new(&[2, 2, 2], LittleEndian),
2840        );
2841        let expected_registers = initial_registers;
2842        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2843    }
2844
2845    #[test]
2846    fn test_exec_end_sequence() {
2847        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2848        let initial_registers = LineRow::new(&header);
2849        let opcode = LineInstruction::EndSequence;
2850
2851        let mut expected_registers = initial_registers;
2852        expected_registers.end_sequence = true;
2853
2854        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2855    }
2856
2857    #[test]
2858    fn test_exec_set_address() {
2859        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2860        let initial_registers = LineRow::new(&header);
2861        let opcode = LineInstruction::SetAddress(3030);
2862
2863        let mut expected_registers = initial_registers;
2864        expected_registers.address = 3030;
2865
2866        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2867    }
2868
2869    #[test]
2870    fn test_exec_set_address_tombstone() {
2871        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2872        let initial_registers = LineRow::new(&header);
2873        let opcode = LineInstruction::SetAddress(!0);
2874
2875        let mut expected_registers = initial_registers;
2876        expected_registers.tombstone = true;
2877
2878        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2879    }
2880
2881    #[test]
2882    fn test_exec_set_address_backwards() {
2883        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2884        let mut initial_registers = LineRow::new(&header);
2885        initial_registers.address = 1;
2886        let opcode = LineInstruction::SetAddress(0);
2887
2888        let mut expected_registers = initial_registers;
2889        expected_registers.tombstone = true;
2890
2891        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2892    }
2893
2894    #[test]
2895    fn test_exec_define_file() {
2896        let mut program = make_test_program(EndianSlice::new(&[], LittleEndian));
2897        let mut row = LineRow::new(program.header());
2898
2899        let file = FileEntry {
2900            path_name: AttributeValue::String(EndianSlice::new(b"test.cpp", LittleEndian)),
2901            directory_index: 0,
2902            timestamp: 0,
2903            size: 0,
2904            md5: [0; 16],
2905            source: None,
2906        };
2907
2908        let opcode = LineInstruction::DefineFile(file);
2909        let is_new_row = row.execute(opcode, &mut program).unwrap();
2910
2911        assert!(!is_new_row);
2912        assert_eq!(Some(&file), program.header().file_names.last());
2913    }
2914
2915    #[test]
2916    fn test_exec_set_discriminator() {
2917        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2918        let initial_registers = LineRow::new(&header);
2919        let opcode = LineInstruction::SetDiscriminator(9);
2920
2921        let mut expected_registers = initial_registers;
2922        expected_registers.discriminator = 9;
2923
2924        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2925    }
2926
2927    #[test]
2928    fn test_exec_unknown_extended() {
2929        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2930        let initial_registers = LineRow::new(&header);
2931        let opcode = LineInstruction::UnknownExtended(
2932            constants::DwLne(74),
2933            EndianSlice::new(&[], LittleEndian),
2934        );
2935        let expected_registers = initial_registers;
2936        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2937    }
2938
2939    #[allow(dead_code, unreachable_code, unused_variables)]
2942    #[allow(clippy::diverging_sub_expression)]
2943    fn test_line_rows_variance<'a, 'b>(_: &'a [u8], _: &'b [u8])
2944    where
2945        'a: 'b,
2946    {
2947        let a: &OneShotLineRows<EndianSlice<'a, LittleEndian>> = unimplemented!();
2948        let _: &OneShotLineRows<EndianSlice<'b, LittleEndian>> = a;
2949    }
2950
2951    #[test]
2952    fn test_parse_debug_line_v5_ok() {
2953        let expected_lengths = &[1, 2];
2954        let expected_program = &[0, 1, 2, 3, 4];
2955        let expected_rest = &[5, 6, 7, 8, 9];
2956        let expected_include_directories = [
2957            AttributeValue::String(EndianSlice::new(b"dir1", LittleEndian)),
2958            AttributeValue::String(EndianSlice::new(b"dir2", LittleEndian)),
2959        ];
2960        let expected_file_names = [
2961            FileEntry {
2962                path_name: AttributeValue::String(EndianSlice::new(b"file1", LittleEndian)),
2963                directory_index: 0,
2964                timestamp: 0,
2965                size: 0,
2966                md5: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
2967                source: Some(AttributeValue::String(EndianSlice::new(
2968                    b"foobar",
2969                    LittleEndian,
2970                ))),
2971            },
2972            FileEntry {
2973                path_name: AttributeValue::String(EndianSlice::new(b"file2", LittleEndian)),
2974                directory_index: 1,
2975                timestamp: 0,
2976                size: 0,
2977                md5: [
2978                    11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
2979                ],
2980                source: Some(AttributeValue::String(EndianSlice::new(
2981                    b"quux",
2982                    LittleEndian,
2983                ))),
2984            },
2985        ];
2986
2987        for format in [Format::Dwarf32, Format::Dwarf64] {
2988            let length = Label::new();
2989            let header_length = Label::new();
2990            let start = Label::new();
2991            let header_start = Label::new();
2992            let end = Label::new();
2993            let header_end = Label::new();
2994            let section = Section::with_endian(Endian::Little)
2995                .initial_length(format, &length, &start)
2996                .D16(5)
2997                .D8(4)
2999                .D8(0)
3001                .word_label(format.word_size(), &header_length)
3002                .mark(&header_start)
3003                .D8(1)
3005                .D8(1)
3007                .D8(1)
3009                .D8(0)
3011                .D8(1)
3013                .D8(expected_lengths.len() as u8 + 1)
3015                .append_bytes(expected_lengths)
3017                .D8(1)
3019                .uleb(constants::DW_LNCT_path.0 as u64)
3020                .uleb(constants::DW_FORM_string.0 as u64)
3021                .D8(2)
3023                .append_bytes(b"dir1\0")
3024                .append_bytes(b"dir2\0")
3025                .D8(4)
3027                .uleb(constants::DW_LNCT_path.0 as u64)
3028                .uleb(constants::DW_FORM_string.0 as u64)
3029                .uleb(constants::DW_LNCT_directory_index.0 as u64)
3030                .uleb(constants::DW_FORM_data1.0 as u64)
3031                .uleb(constants::DW_LNCT_MD5.0 as u64)
3032                .uleb(constants::DW_FORM_data16.0 as u64)
3033                .uleb(constants::DW_LNCT_LLVM_source.0 as u64)
3034                .uleb(constants::DW_FORM_string.0 as u64)
3035                .D8(2)
3037                .append_bytes(b"file1\0")
3038                .D8(0)
3039                .append_bytes(&expected_file_names[0].md5)
3040                .append_bytes(b"foobar\0")
3041                .append_bytes(b"file2\0")
3042                .D8(1)
3043                .append_bytes(&expected_file_names[1].md5)
3044                .append_bytes(b"quux\0")
3045                .mark(&header_end)
3046                .append_bytes(expected_program)
3048                .mark(&end)
3049                .append_bytes(expected_rest);
3051            length.set_const((&end - &start) as u64);
3052            header_length.set_const((&header_end - &header_start) as u64);
3053            let section = section.get_contents().unwrap();
3054
3055            let input = &mut EndianSlice::new(§ion, LittleEndian);
3056
3057            let header = LineProgramHeader::parse(input, DebugLineOffset(0), 0, None, None)
3058                .expect("should parse header ok");
3059
3060            assert_eq!(header.raw_program_buf().slice(), expected_program);
3061            assert_eq!(input.slice(), expected_rest);
3062
3063            assert_eq!(header.offset, DebugLineOffset(0));
3064            assert_eq!(header.version(), 5);
3065            assert_eq!(header.address_size(), 4);
3066            assert_eq!(header.minimum_instruction_length(), 1);
3067            assert_eq!(header.maximum_operations_per_instruction(), 1);
3068            assert!(header.default_is_stmt());
3069            assert_eq!(header.line_base(), 0);
3070            assert_eq!(header.line_range(), 1);
3071            assert_eq!(header.opcode_base(), expected_lengths.len() as u8 + 1);
3072            assert_eq!(header.standard_opcode_lengths().slice(), expected_lengths);
3073            assert_eq!(
3074                header.directory_entry_format(),
3075                &[FileEntryFormat {
3076                    content_type: constants::DW_LNCT_path,
3077                    form: constants::DW_FORM_string,
3078                }]
3079            );
3080            assert_eq!(header.include_directories(), expected_include_directories);
3081            assert_eq!(header.directory(0), Some(expected_include_directories[0]));
3082            assert_eq!(
3083                header.file_name_entry_format(),
3084                &[
3085                    FileEntryFormat {
3086                        content_type: constants::DW_LNCT_path,
3087                        form: constants::DW_FORM_string,
3088                    },
3089                    FileEntryFormat {
3090                        content_type: constants::DW_LNCT_directory_index,
3091                        form: constants::DW_FORM_data1,
3092                    },
3093                    FileEntryFormat {
3094                        content_type: constants::DW_LNCT_MD5,
3095                        form: constants::DW_FORM_data16,
3096                    },
3097                    FileEntryFormat {
3098                        content_type: constants::DW_LNCT_LLVM_source,
3099                        form: constants::DW_FORM_string,
3100                    }
3101                ]
3102            );
3103            assert_eq!(header.file_names(), expected_file_names);
3104            assert_eq!(header.file(0), Some(&expected_file_names[0]));
3105        }
3106    }
3107
3108    #[test]
3109    fn test_sequences() {
3110        #[rustfmt::skip]
3111        let buf = [
3112            94, 0x00, 0x00, 0x00,
3114            0x04, 0x00,
3116            0x28, 0x00, 0x00, 0x00,
3118            0x01,
3120            0x01,
3122            0x01,
3124            0x00,
3126            0x01,
3128            0x03,
3130            0x01, 0x02,
3132            0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
3134            0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
3137                0x00,
3138                0x00,
3139                0x00,
3140                0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
3142                0x01,
3143                0x00,
3144                0x00,
3145            0x00,
3147
3148            0, 5, constants::DW_LNE_set_address.0, 1, 0, 0, 0,
3149            constants::DW_LNS_copy.0,
3150            constants::DW_LNS_advance_pc.0, 1,
3151            constants::DW_LNS_copy.0,
3152            constants::DW_LNS_advance_pc.0, 2,
3153            0, 1, constants::DW_LNE_end_sequence.0,
3154
3155            0, 5, constants::DW_LNE_set_address.0, 0xff, 0xff, 0xff, 0xff,
3157            constants::DW_LNS_copy.0,
3158            constants::DW_LNS_advance_pc.0, 1,
3159            constants::DW_LNS_copy.0,
3160            constants::DW_LNS_advance_pc.0, 2,
3161            0, 1, constants::DW_LNE_end_sequence.0,
3162
3163            0, 5, constants::DW_LNE_set_address.0, 11, 0, 0, 0,
3164            constants::DW_LNS_copy.0,
3165            constants::DW_LNS_advance_pc.0, 1,
3166            constants::DW_LNS_copy.0,
3167            constants::DW_LNS_advance_pc.0, 2,
3168            0, 1, constants::DW_LNE_end_sequence.0,
3169        ];
3170        assert_eq!(buf[0] as usize, buf.len() - 4);
3171
3172        let rest = &mut EndianSlice::new(&buf, LittleEndian);
3173
3174        let header = LineProgramHeader::parse(rest, DebugLineOffset(0), 4, None, None)
3175            .expect("should parse header ok");
3176        let program = IncompleteLineProgram { header };
3177
3178        let sequences = program.sequences().unwrap().1;
3179        assert_eq!(sequences.len(), 2);
3180        assert_eq!(sequences[0].start, 1);
3181        assert_eq!(sequences[0].end, 4);
3182        assert_eq!(sequences[1].start, 11);
3183        assert_eq!(sequences[1].end, 14);
3184    }
3185}