Skip to main content

gimli/read/
line.rs

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/// The `DebugLine` struct contains the source location to instruction mapping
15/// found in the `.debug_line` section.
16#[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    /// Construct a new `DebugLine` instance from the data in the `.debug_line`
26    /// section.
27    ///
28    /// It is the caller's responsibility to read the `.debug_line` section and
29    /// present it as a `&[u8]` slice. That means using some ELF loader on
30    /// Linux, a Mach-O loader on macOS, etc.
31    ///
32    /// ```
33    /// use gimli::{DebugLine, LittleEndian};
34    ///
35    /// # let buf = [0x00, 0x01, 0x02, 0x03];
36    /// # let read_debug_line_section_somehow = || &buf;
37    /// let debug_line = DebugLine::new(read_debug_line_section_somehow(), LittleEndian);
38    /// ```
39    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    /// Parse the line number program whose header is at the given `offset` in the
46    /// `.debug_line` section.
47    ///
48    /// The `address_size` must match the compilation unit that the lines apply to.
49    /// The `comp_dir` should be from the `DW_AT_comp_dir` attribute of the compilation
50    /// unit. The `comp_name` should be from the `DW_AT_name` attribute of the
51    /// compilation unit.
52    ///
53    /// ```rust,no_run
54    /// use gimli::{DebugLine, DebugLineOffset, IncompleteLineProgram, EndianSlice, LittleEndian};
55    ///
56    /// # let buf = [];
57    /// # let read_debug_line_section_somehow = || &buf;
58    /// let debug_line = DebugLine::new(read_debug_line_section_somehow(), LittleEndian);
59    ///
60    /// // In a real example, we'd grab the offset via a compilation unit
61    /// // entry's `DW_AT_stmt_list` attribute, and the address size from that
62    /// // unit directly.
63    /// let offset = DebugLineOffset(0);
64    /// let address_size = 8;
65    ///
66    /// let program = debug_line.program(offset, address_size, None, None)
67    ///     .expect("should have found a header at that offset, and parsed it OK");
68    /// ```
69    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    /// Create a `DebugLine` section that references the data in `self`.
86    ///
87    /// This is useful when `R` implements `Reader` but `T` does not.
88    ///
89    /// Used by `DwarfSections::borrow`.
90    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/// A `LineProgram` provides access to a `LineProgramHeader` and
115/// a way to add files to the files table if necessary. Gimli consumers should
116/// never need to use or see this trait.
117pub trait LineProgram<R, Offset = <R as Reader>::Offset>
118where
119    R: Reader<Offset = Offset>,
120    Offset: ReaderOffset,
121{
122    /// Get a reference to the held `LineProgramHeader`.
123    fn header(&self) -> &LineProgramHeader<R, Offset>;
124    /// Add a file to the file table if necessary.
125    fn add_file(&mut self, file: FileEntry<R, Offset>);
126}
127
128impl<R, Offset> LineProgram<R, Offset> for IncompleteLineProgram<R, Offset>
129where
130    R: Reader<Offset = Offset>,
131    Offset: ReaderOffset,
132{
133    fn header(&self) -> &LineProgramHeader<R, Offset> {
134        &self.header
135    }
136    fn add_file(&mut self, file: FileEntry<R, Offset>) {
137        self.header.file_names.push(file);
138    }
139}
140
141impl<'program, R, Offset> LineProgram<R, Offset> for &'program CompleteLineProgram<R, Offset>
142where
143    R: Reader<Offset = Offset>,
144    Offset: ReaderOffset,
145{
146    fn header(&self) -> &LineProgramHeader<R, Offset> {
147        &self.header
148    }
149    fn add_file(&mut self, _: FileEntry<R, Offset>) {
150        // Nop. Our file table is already complete.
151    }
152}
153
154/// Executes a `LineProgram` to iterate over the rows in the matrix of line number information.
155///
156/// "The hypothetical machine used by a consumer of the line number information
157/// to expand the byte-coded instruction stream into a matrix of line number
158/// information." -- Section 6.2.1
159#[derive(Debug, Clone)]
160pub struct LineRows<R, Program, Offset = <R as Reader>::Offset>
161where
162    Program: LineProgram<R, Offset>,
163    R: Reader<Offset = Offset>,
164    Offset: ReaderOffset,
165{
166    program: Program,
167    row: LineRow,
168    instructions: LineInstructions<R>,
169}
170
171type OneShotLineRows<R, Offset = <R as Reader>::Offset> =
172    LineRows<R, IncompleteLineProgram<R, Offset>, Offset>;
173
174type ResumedLineRows<'program, R, Offset = <R as Reader>::Offset> =
175    LineRows<R, &'program CompleteLineProgram<R, Offset>, Offset>;
176
177impl<R, Program, Offset> LineRows<R, Program, Offset>
178where
179    Program: LineProgram<R, Offset>,
180    R: Reader<Offset = Offset>,
181    Offset: ReaderOffset,
182{
183    fn new(program: IncompleteLineProgram<R, Offset>) -> OneShotLineRows<R, Offset> {
184        let row = LineRow::new(program.header());
185        let instructions = LineInstructions {
186            input: program.header().program_buf.clone(),
187        };
188        LineRows {
189            program,
190            row,
191            instructions,
192        }
193    }
194
195    fn resume<'program>(
196        program: &'program CompleteLineProgram<R, Offset>,
197        sequence: &LineSequence<R>,
198    ) -> ResumedLineRows<'program, R, Offset> {
199        let row = LineRow::new(program.header());
200        let instructions = sequence.instructions.clone();
201        LineRows {
202            program,
203            row,
204            instructions,
205        }
206    }
207
208    /// Get a reference to the header for this state machine's line number
209    /// program.
210    #[inline]
211    pub fn header(&self) -> &LineProgramHeader<R, Offset> {
212        self.program.header()
213    }
214
215    /// Parse and execute the next instructions in the line number program until
216    /// another row in the line number matrix is computed.
217    ///
218    /// The freshly computed row is returned as `Ok(Some((header, row)))`.
219    /// If the matrix is complete, and there are no more new rows in the line
220    /// number matrix, then `Ok(None)` is returned. If there was an error parsing
221    /// an instruction, then `Err(e)` is returned.
222    ///
223    /// Unfortunately, the references mean that this cannot be a
224    /// `Iterator`.
225    pub fn next_row(&mut self) -> Result<Option<(&LineProgramHeader<R, Offset>, &LineRow)>> {
226        // Perform any reset that was required after copying the previous row.
227        self.row.reset(self.program.header());
228
229        loop {
230            // Split the borrow here, rather than calling `self.header()`.
231            match self.instructions.next_instruction(self.program.header()) {
232                Err(err) => return Err(err),
233                Ok(None) => return Ok(None),
234                Ok(Some(instruction)) => {
235                    if self.row.execute(instruction, &mut self.program)? {
236                        if self.row.tombstone {
237                            // Perform any reset that was required for the tombstone row.
238                            // Normally this is done when `next_row` is called again, but for
239                            // tombstones we loop immediately.
240                            self.row.reset(self.program.header());
241                        } else {
242                            return Ok(Some((self.header(), &self.row)));
243                        }
244                    }
245                    // Fall through, parse the next instruction, and see if that
246                    // yields a row.
247                }
248            }
249        }
250    }
251}
252
253/// A parsed line number program instruction.
254#[derive(Clone, Copy, Debug, PartialEq, Eq)]
255pub enum LineInstruction<R, Offset = <R as Reader>::Offset>
256where
257    R: Reader<Offset = Offset>,
258    Offset: ReaderOffset,
259{
260    /// > ### 6.2.5.1 Special Opcodes
261    /// >
262    /// > Each ubyte special opcode has the following effect on the state machine:
263    /// >
264    /// >   1. Add a signed integer to the line register.
265    /// >
266    /// >   2. Modify the operation pointer by incrementing the address and
267    /// >      op_index registers as described below.
268    /// >
269    /// >   3. Append a row to the matrix using the current values of the state
270    /// >      machine registers.
271    /// >
272    /// >   4. Set the basic_block register to “false.”
273    /// >
274    /// >   5. Set the prologue_end register to “false.”
275    /// >
276    /// >   6. Set the epilogue_begin register to “false.”
277    /// >
278    /// >   7. Set the discriminator register to 0.
279    /// >
280    /// > All of the special opcodes do those same seven things; they differ from
281    /// > one another only in what values they add to the line, address and
282    /// > op_index registers.
283    Special(u8),
284
285    /// "[`LineInstruction::Copy`] appends a row to the matrix using the current
286    /// values of the state machine registers. Then it sets the discriminator
287    /// register to 0, and sets the basic_block, prologue_end and epilogue_begin
288    /// registers to “false.”"
289    Copy,
290
291    /// "The DW_LNS_advance_pc opcode takes a single unsigned LEB128 operand as
292    /// the operation advance and modifies the address and op_index registers
293    /// [the same as `LineInstruction::Special`]"
294    AdvancePc(u64),
295
296    /// "The DW_LNS_advance_line opcode takes a single signed LEB128 operand and
297    /// adds that value to the line register of the state machine."
298    AdvanceLine(i64),
299
300    /// "The DW_LNS_set_file opcode takes a single unsigned LEB128 operand and
301    /// stores it in the file register of the state machine."
302    SetFile(u64),
303
304    /// "The DW_LNS_set_column opcode takes a single unsigned LEB128 operand and
305    /// stores it in the column register of the state machine."
306    SetColumn(u64),
307
308    /// "The DW_LNS_negate_stmt opcode takes no operands. It sets the is_stmt
309    /// register of the state machine to the logical negation of its current
310    /// value."
311    NegateStatement,
312
313    /// "The DW_LNS_set_basic_block opcode takes no operands. It sets the
314    /// basic_block register of the state machine to “true.”"
315    SetBasicBlock,
316
317    /// > The DW_LNS_const_add_pc opcode takes no operands. It advances the
318    /// > address and op_index registers by the increments corresponding to
319    /// > special opcode 255.
320    /// >
321    /// > When the line number program needs to advance the address by a small
322    /// > amount, it can use a single special opcode, which occupies a single
323    /// > byte. When it needs to advance the address by up to twice the range of
324    /// > the last special opcode, it can use DW_LNS_const_add_pc followed by a
325    /// > special opcode, for a total of two bytes. Only if it needs to advance
326    /// > the address by more than twice that range will it need to use both
327    /// > DW_LNS_advance_pc and a special opcode, requiring three or more bytes.
328    ConstAddPc,
329
330    /// > The DW_LNS_fixed_advance_pc opcode takes a single uhalf (unencoded)
331    /// > operand and adds it to the address register of the state machine and
332    /// > sets the op_index register to 0. This is the only standard opcode whose
333    /// > operand is not a variable length number. It also does not multiply the
334    /// > operand by the minimum_instruction_length field of the header.
335    FixedAddPc(u16),
336
337    /// "[`LineInstruction::SetPrologueEnd`] sets the prologue_end register to “true”."
338    SetPrologueEnd,
339
340    /// "[`LineInstruction::SetEpilogueBegin`] sets the epilogue_begin register to
341    /// “true”."
342    SetEpilogueBegin,
343
344    /// "The DW_LNS_set_isa opcode takes a single unsigned LEB128 operand and
345    /// stores that value in the isa register of the state machine."
346    SetIsa(u64),
347
348    /// An unknown standard opcode with zero operands.
349    UnknownStandard0(constants::DwLns),
350
351    /// An unknown standard opcode with one operand.
352    UnknownStandard1(constants::DwLns, u64),
353
354    /// An unknown standard opcode with multiple operands.
355    UnknownStandardN(constants::DwLns, R),
356
357    /// > [`LineInstruction::EndSequence`] sets the end_sequence register of the state
358    /// > machine to “true” and appends a row to the matrix using the current
359    /// > values of the state-machine registers. Then it resets the registers to
360    /// > the initial values specified above (see Section 6.2.2). Every line
361    /// > number program sequence must end with a DW_LNE_end_sequence instruction
362    /// > which creates a row whose address is that of the byte after the last
363    /// > target machine instruction of the sequence.
364    EndSequence,
365
366    /// > The DW_LNE_set_address opcode takes a single relocatable address as an
367    /// > operand. The size of the operand is the size of an address on the target
368    /// > machine. It sets the address register to the value given by the
369    /// > relocatable address and sets the op_index register to 0.
370    /// >
371    /// > All of the other line number program opcodes that affect the address
372    /// > register add a delta to it. This instruction stores a relocatable value
373    /// > into it instead.
374    SetAddress(u64),
375
376    /// Defines a new source file in the line number program and appends it to
377    /// the line number program header's list of source files.
378    DefineFile(FileEntry<R, Offset>),
379
380    /// "The DW_LNE_set_discriminator opcode takes a single parameter, an
381    /// unsigned LEB128 integer. It sets the discriminator register to the new
382    /// value."
383    SetDiscriminator(u64),
384
385    /// An unknown extended opcode and the slice of its unparsed operands.
386    UnknownExtended(constants::DwLne, R),
387}
388
389impl<R, Offset> LineInstruction<R, Offset>
390where
391    R: Reader<Offset = Offset>,
392    Offset: ReaderOffset,
393{
394    fn parse<'header>(
395        header: &'header LineProgramHeader<R>,
396        input: &mut R,
397    ) -> Result<LineInstruction<R>>
398    where
399        R: 'header,
400    {
401        let opcode = input.read_u8()?;
402        if opcode == 0 {
403            let length = input.read_uleb128().and_then(R::Offset::from_u64)?;
404            let mut instr_rest = input.split(length)?;
405            let opcode = instr_rest.read_u8()?;
406
407            match constants::DwLne(opcode) {
408                constants::DW_LNE_end_sequence => Ok(LineInstruction::EndSequence),
409
410                constants::DW_LNE_set_address => {
411                    let address = instr_rest.read_address(header.address_size())?;
412                    Ok(LineInstruction::SetAddress(address))
413                }
414
415                constants::DW_LNE_define_file => {
416                    if header.version() <= 4 {
417                        let path_name = instr_rest.read_null_terminated_slice()?;
418                        let entry = FileEntry::parse(&mut instr_rest, path_name)?;
419                        Ok(LineInstruction::DefineFile(entry))
420                    } else {
421                        Ok(LineInstruction::UnknownExtended(
422                            constants::DW_LNE_define_file,
423                            instr_rest,
424                        ))
425                    }
426                }
427
428                constants::DW_LNE_set_discriminator => {
429                    let discriminator = instr_rest.read_uleb128()?;
430                    Ok(LineInstruction::SetDiscriminator(discriminator))
431                }
432
433                otherwise => Ok(LineInstruction::UnknownExtended(otherwise, instr_rest)),
434            }
435        } else if opcode >= header.opcode_base {
436            Ok(LineInstruction::Special(opcode))
437        } else {
438            match constants::DwLns(opcode) {
439                constants::DW_LNS_copy => Ok(LineInstruction::Copy),
440
441                constants::DW_LNS_advance_pc => {
442                    let advance = input.read_uleb128()?;
443                    Ok(LineInstruction::AdvancePc(advance))
444                }
445
446                constants::DW_LNS_advance_line => {
447                    let increment = input.read_sleb128()?;
448                    Ok(LineInstruction::AdvanceLine(increment))
449                }
450
451                constants::DW_LNS_set_file => {
452                    let file = input.read_uleb128()?;
453                    Ok(LineInstruction::SetFile(file))
454                }
455
456                constants::DW_LNS_set_column => {
457                    let column = input.read_uleb128()?;
458                    Ok(LineInstruction::SetColumn(column))
459                }
460
461                constants::DW_LNS_negate_stmt => Ok(LineInstruction::NegateStatement),
462
463                constants::DW_LNS_set_basic_block => Ok(LineInstruction::SetBasicBlock),
464
465                constants::DW_LNS_const_add_pc => Ok(LineInstruction::ConstAddPc),
466
467                constants::DW_LNS_fixed_advance_pc => {
468                    let advance = input.read_u16()?;
469                    Ok(LineInstruction::FixedAddPc(advance))
470                }
471
472                constants::DW_LNS_set_prologue_end => Ok(LineInstruction::SetPrologueEnd),
473
474                constants::DW_LNS_set_epilogue_begin => Ok(LineInstruction::SetEpilogueBegin),
475
476                constants::DW_LNS_set_isa => {
477                    let isa = input.read_uleb128()?;
478                    Ok(LineInstruction::SetIsa(isa))
479                }
480
481                otherwise => {
482                    let mut opcode_lengths = header.standard_opcode_lengths().clone();
483                    opcode_lengths.skip(R::Offset::from_u8(opcode - 1))?;
484                    let num_args = opcode_lengths.read_u8()? as usize;
485                    match num_args {
486                        0 => Ok(LineInstruction::UnknownStandard0(otherwise)),
487                        1 => {
488                            let arg = input.read_uleb128()?;
489                            Ok(LineInstruction::UnknownStandard1(otherwise, arg))
490                        }
491                        _ => {
492                            let mut args = input.clone();
493                            for _ in 0..num_args {
494                                input.read_uleb128()?;
495                            }
496                            let len = input.offset_from(&args);
497                            args.truncate(len)?;
498                            Ok(LineInstruction::UnknownStandardN(otherwise, args))
499                        }
500                    }
501                }
502            }
503        }
504    }
505}
506
507/// An iterator yielding parsed instructions.
508///
509/// See
510/// [`LineProgramHeader::instructions`](./struct.LineProgramHeader.html#method.instructions)
511/// for more details.
512#[derive(Clone, Debug)]
513pub struct LineInstructions<R: Reader> {
514    input: R,
515}
516
517impl<R: Reader> LineInstructions<R> {
518    fn remove_trailing(&self, other: &LineInstructions<R>) -> Result<LineInstructions<R>> {
519        let offset = other.input.offset_from(&self.input);
520        let mut input = self.input.clone();
521        input.truncate(offset)?;
522        Ok(LineInstructions { input })
523    }
524}
525
526impl<R: Reader> LineInstructions<R> {
527    /// Advance the iterator and return the next instruction.
528    ///
529    /// Returns the newly parsed instruction as `Ok(Some(instruction))`. Returns
530    /// `Ok(None)` when iteration is complete and all instructions have already been
531    /// parsed and yielded. If an error occurs while parsing the next attribute,
532    /// then this error is returned as `Err(e)`, and all subsequent calls return
533    /// `Ok(None)`.
534    ///
535    /// Unfortunately, the `header` parameter means that this cannot be a
536    /// `Iterator`.
537    #[inline(always)]
538    pub fn next_instruction(
539        &mut self,
540        header: &LineProgramHeader<R>,
541    ) -> Result<Option<LineInstruction<R>>> {
542        if self.input.is_empty() {
543            return Ok(None);
544        }
545
546        match LineInstruction::parse(header, &mut self.input) {
547            Ok(instruction) => Ok(Some(instruction)),
548            Err(e) => {
549                self.input.empty();
550                Err(e)
551            }
552        }
553    }
554}
555
556/// A row in the line number program's resulting matrix.
557///
558/// Each row is a copy of the registers of the state machine, as defined in section 6.2.2.
559#[derive(Clone, Copy, Debug, PartialEq, Eq)]
560pub struct LineRow {
561    tombstone: bool,
562    address: u64,
563    op_index: Wrapping<u64>,
564    file: u64,
565    line: Wrapping<u64>,
566    column: u64,
567    is_stmt: bool,
568    basic_block: bool,
569    end_sequence: bool,
570    prologue_end: bool,
571    epilogue_begin: bool,
572    isa: u64,
573    discriminator: u64,
574}
575
576impl LineRow {
577    /// Create a line number row in the initial state for the given program.
578    pub fn new<R: Reader>(header: &LineProgramHeader<R>) -> Self {
579        LineRow {
580            // "At the beginning of each sequence within a line number program, the
581            // state of the registers is:" -- Section 6.2.2
582            tombstone: false,
583            address: 0,
584            op_index: Wrapping(0),
585            file: 1,
586            line: Wrapping(1),
587            column: 0,
588            // "determined by default_is_stmt in the line number program header"
589            is_stmt: header.line_encoding.default_is_stmt,
590            basic_block: false,
591            end_sequence: false,
592            prologue_end: false,
593            epilogue_begin: false,
594            // "The isa value 0 specifies that the instruction set is the
595            // architecturally determined default instruction set. This may be fixed
596            // by the ABI, or it may be specified by other means, for example, by
597            // the object file description."
598            isa: 0,
599            discriminator: 0,
600        }
601    }
602
603    /// "The program-counter value corresponding to a machine instruction
604    /// generated by the compiler."
605    #[inline]
606    pub fn address(&self) -> u64 {
607        self.address
608    }
609
610    /// > An unsigned integer representing the index of an operation within a VLIW
611    /// > instruction. The index of the first operation is 0. For non-VLIW
612    /// > architectures, this register will always be 0.
613    /// >
614    /// > The address and op_index registers, taken together, form an operation
615    /// > pointer that can reference any individual operation with the
616    /// > instruction stream.
617    #[inline]
618    pub fn op_index(&self) -> u64 {
619        self.op_index.0
620    }
621
622    /// "An unsigned integer indicating the identity of the source file
623    /// corresponding to a machine instruction."
624    #[inline]
625    pub fn file_index(&self) -> u64 {
626        self.file
627    }
628
629    /// The source file corresponding to the current machine instruction.
630    #[inline]
631    pub fn file<'header, R: Reader>(
632        &self,
633        header: &'header LineProgramHeader<R>,
634    ) -> Option<&'header FileEntry<R>> {
635        header.file(self.file)
636    }
637
638    /// "An unsigned integer indicating a source line number. Lines are numbered
639    /// beginning at 1. The compiler may emit the value 0 in cases where an
640    /// instruction cannot be attributed to any source line."
641    /// Line number values of 0 are represented as `None`.
642    #[inline]
643    pub fn line(&self) -> Option<NonZeroU64> {
644        NonZeroU64::new(self.line.0)
645    }
646
647    /// "An unsigned integer indicating a column number within a source
648    /// line. Columns are numbered beginning at 1. The value 0 is reserved to
649    /// indicate that a statement begins at the “left edge” of the line."
650    #[inline]
651    pub fn column(&self) -> ColumnType {
652        NonZeroU64::new(self.column)
653            .map(ColumnType::Column)
654            .unwrap_or(ColumnType::LeftEdge)
655    }
656
657    /// "A boolean indicating that the current instruction is a recommended
658    /// breakpoint location. A recommended breakpoint location is intended to
659    /// “represent” a line, a statement and/or a semantically distinct subpart
660    /// of a statement."
661    #[inline]
662    pub fn is_stmt(&self) -> bool {
663        self.is_stmt
664    }
665
666    /// "A boolean indicating that the current instruction is the beginning of a
667    /// basic block."
668    #[inline]
669    pub fn basic_block(&self) -> bool {
670        self.basic_block
671    }
672
673    /// "A boolean indicating that the current address is that of the first byte
674    /// after the end of a sequence of target machine instructions. end_sequence
675    /// terminates a sequence of lines; therefore other information in the same
676    /// row is not meaningful."
677    #[inline]
678    pub fn end_sequence(&self) -> bool {
679        self.end_sequence
680    }
681
682    /// "A boolean indicating that the current address is one (of possibly many)
683    /// where execution should be suspended for an entry breakpoint of a
684    /// function."
685    #[inline]
686    pub fn prologue_end(&self) -> bool {
687        self.prologue_end
688    }
689
690    /// "A boolean indicating that the current address is one (of possibly many)
691    /// where execution should be suspended for an exit breakpoint of a
692    /// function."
693    #[inline]
694    pub fn epilogue_begin(&self) -> bool {
695        self.epilogue_begin
696    }
697
698    /// Tag for the current instruction set architecture.
699    ///
700    /// > An unsigned integer whose value encodes the applicable instruction set
701    /// > architecture for the current instruction.
702    /// >
703    /// > The encoding of instruction sets should be shared by all users of a
704    /// > given architecture. It is recommended that this encoding be defined by
705    /// > the ABI authoring committee for each architecture.
706    #[inline]
707    pub fn isa(&self) -> u64 {
708        self.isa
709    }
710
711    /// "An unsigned integer identifying the block to which the current
712    /// instruction belongs. Discriminator values are assigned arbitrarily by
713    /// the DWARF producer and serve to distinguish among multiple blocks that
714    /// may all be associated with the same source file, line, and column. Where
715    /// only one block exists for a given source position, the discriminator
716    /// value should be zero."
717    #[inline]
718    pub fn discriminator(&self) -> u64 {
719        self.discriminator
720    }
721
722    /// Execute the given instruction, and return true if a new row in the
723    /// line number matrix needs to be generated.
724    ///
725    /// Unknown opcodes are treated as no-ops.
726    #[inline]
727    pub fn execute<R, Program>(
728        &mut self,
729        instruction: LineInstruction<R>,
730        program: &mut Program,
731    ) -> Result<bool>
732    where
733        Program: LineProgram<R>,
734        R: Reader,
735    {
736        Ok(match instruction {
737            LineInstruction::Special(opcode) => {
738                self.exec_special_opcode(opcode, program.header())?;
739                true
740            }
741
742            LineInstruction::Copy => true,
743
744            LineInstruction::AdvancePc(operation_advance) => {
745                self.apply_operation_advance(operation_advance, program.header())?;
746                false
747            }
748
749            LineInstruction::AdvanceLine(line_increment) => {
750                self.apply_line_advance(line_increment);
751                false
752            }
753
754            LineInstruction::SetFile(file) => {
755                self.file = file;
756                false
757            }
758
759            LineInstruction::SetColumn(column) => {
760                self.column = column;
761                false
762            }
763
764            LineInstruction::NegateStatement => {
765                self.is_stmt = !self.is_stmt;
766                false
767            }
768
769            LineInstruction::SetBasicBlock => {
770                self.basic_block = true;
771                false
772            }
773
774            LineInstruction::ConstAddPc => {
775                let adjusted = self.adjust_opcode(255, program.header());
776                let operation_advance = adjusted / program.header().line_encoding.line_range;
777                self.apply_operation_advance(u64::from(operation_advance), program.header())?;
778                false
779            }
780
781            LineInstruction::FixedAddPc(operand) => {
782                if !self.tombstone {
783                    let address_size = program.header().address_size();
784                    self.address = self.address.add_sized(u64::from(operand), address_size)?;
785                    self.op_index.0 = 0;
786                }
787                false
788            }
789
790            LineInstruction::SetPrologueEnd => {
791                self.prologue_end = true;
792                false
793            }
794
795            LineInstruction::SetEpilogueBegin => {
796                self.epilogue_begin = true;
797                false
798            }
799
800            LineInstruction::SetIsa(isa) => {
801                self.isa = isa;
802                false
803            }
804
805            LineInstruction::EndSequence => {
806                self.end_sequence = true;
807                true
808            }
809
810            LineInstruction::SetAddress(address) => {
811                // If the address is a tombstone, then skip instructions until the next address.
812                // DWARF specifies a tombstone value of -1, but many linkers use 0.
813                // However, 0 may be a valid address, so we only skip that if we have previously
814                // seen a higher address. Additionally, gold may keep the relocation addend,
815                // so we treat all lower addresses as tombstones instead of just 0.
816                // This works because DWARF specifies that addresses are monotonically increasing
817                // within a sequence; the alternative is to return an error.
818                self.tombstone = address < self.address
819                    || address >= u64::min_tombstone(program.header().encoding.address_size);
820                if !self.tombstone {
821                    self.address = address;
822                    self.op_index.0 = 0;
823                }
824                false
825            }
826
827            LineInstruction::DefineFile(entry) => {
828                program.add_file(entry);
829                false
830            }
831
832            LineInstruction::SetDiscriminator(discriminator) => {
833                self.discriminator = discriminator;
834                false
835            }
836
837            // Compatibility with future opcodes.
838            LineInstruction::UnknownStandard0(_)
839            | LineInstruction::UnknownStandard1(_, _)
840            | LineInstruction::UnknownStandardN(_, _)
841            | LineInstruction::UnknownExtended(_, _) => false,
842        })
843    }
844
845    /// Perform any reset that was required after copying the previous row.
846    #[inline]
847    pub fn reset<R: Reader>(&mut self, header: &LineProgramHeader<R>) {
848        if self.end_sequence {
849            // Previous instruction was EndSequence, so reset everything
850            // as specified in Section 6.2.5.3.
851            *self = Self::new(header);
852        } else {
853            // Previous instruction was one of:
854            // - Special - specified in Section 6.2.5.1, steps 4-7
855            // - Copy - specified in Section 6.2.5.2
856            // The reset behaviour is the same in both cases.
857            self.discriminator = 0;
858            self.basic_block = false;
859            self.prologue_end = false;
860            self.epilogue_begin = false;
861        }
862    }
863
864    /// Step 1 of section 6.2.5.1
865    fn apply_line_advance(&mut self, line_increment: i64) {
866        if line_increment < 0 {
867            let decrement = -line_increment as u64;
868            if decrement <= self.line.0 {
869                self.line.0 -= decrement;
870            } else {
871                self.line.0 = 0;
872            }
873        } else {
874            self.line += Wrapping(line_increment as u64);
875        }
876    }
877
878    /// Step 2 of section 6.2.5.1
879    fn apply_operation_advance<R: Reader>(
880        &mut self,
881        operation_advance: u64,
882        header: &LineProgramHeader<R>,
883    ) -> Result<()> {
884        if self.tombstone {
885            return Ok(());
886        }
887
888        let operation_advance = Wrapping(operation_advance);
889
890        let minimum_instruction_length = u64::from(header.line_encoding.minimum_instruction_length);
891        let minimum_instruction_length = Wrapping(minimum_instruction_length);
892
893        let maximum_operations_per_instruction =
894            u64::from(header.line_encoding.maximum_operations_per_instruction);
895        let maximum_operations_per_instruction = Wrapping(maximum_operations_per_instruction);
896
897        let address_advance = if maximum_operations_per_instruction.0 == 1 {
898            self.op_index.0 = 0;
899            minimum_instruction_length * operation_advance
900        } else {
901            let op_index_with_advance = self.op_index + operation_advance;
902            self.op_index = op_index_with_advance % maximum_operations_per_instruction;
903            minimum_instruction_length
904                * (op_index_with_advance / maximum_operations_per_instruction)
905        };
906        self.address = self
907            .address
908            .add_sized(address_advance.0, header.address_size())?;
909        Ok(())
910    }
911
912    #[inline]
913    fn adjust_opcode<R: Reader>(&self, opcode: u8, header: &LineProgramHeader<R>) -> u8 {
914        opcode - header.opcode_base
915    }
916
917    /// Section 6.2.5.1
918    fn exec_special_opcode<R: Reader>(
919        &mut self,
920        opcode: u8,
921        header: &LineProgramHeader<R>,
922    ) -> Result<()> {
923        let adjusted_opcode = self.adjust_opcode(opcode, header);
924
925        let line_range = header.line_encoding.line_range;
926        let line_advance = adjusted_opcode % line_range;
927        let operation_advance = adjusted_opcode / line_range;
928
929        // Step 1
930        let line_base = i64::from(header.line_encoding.line_base);
931        self.apply_line_advance(line_base + i64::from(line_advance));
932
933        // Step 2
934        self.apply_operation_advance(u64::from(operation_advance), header)?;
935        Ok(())
936    }
937}
938
939/// The type of column that a row is referring to.
940#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
941pub enum ColumnType {
942    /// The `LeftEdge` means that the statement begins at the start of the new
943    /// line.
944    LeftEdge,
945    /// A column number, whose range begins at 1.
946    Column(NonZeroU64),
947}
948
949/// A sequence within a line number program.  A sequence, as defined in section
950/// 6.2.5 of the standard, is a linear subset of a line number program within
951/// which addresses are monotonically increasing.
952#[derive(Clone, Debug)]
953pub struct LineSequence<R: Reader> {
954    /// The first address that is covered by this sequence within the line number
955    /// program.
956    pub start: u64,
957    /// The first address that is *not* covered by this sequence within the line
958    /// number program.
959    pub end: u64,
960    instructions: LineInstructions<R>,
961}
962
963/// A header for a line number program in the `.debug_line` section, as defined
964/// in section 6.2.4 of the standard.
965#[derive(Clone, Debug, Eq, PartialEq)]
966pub struct LineProgramHeader<R, Offset = <R as Reader>::Offset>
967where
968    R: Reader<Offset = Offset>,
969    Offset: ReaderOffset,
970{
971    encoding: Encoding,
972    offset: DebugLineOffset<Offset>,
973    unit_length: Offset,
974
975    header_length: Offset,
976
977    line_encoding: LineEncoding,
978
979    /// "The number assigned to the first special opcode."
980    opcode_base: u8,
981
982    /// "This array specifies the number of LEB128 operands for each of the
983    /// standard opcodes. The first element of the array corresponds to the
984    /// opcode whose value is 1, and the last element corresponds to the opcode
985    /// whose value is `opcode_base - 1`."
986    standard_opcode_lengths: R,
987
988    /// "A sequence of directory entry format descriptions."
989    directory_entry_format: Vec<FileEntryFormat>,
990
991    /// > Entries in this sequence describe each path that was searched for
992    /// > included source files in this compilation. (The paths include those
993    /// > directories specified explicitly by the user for the compiler to search
994    /// > and those the compiler searches without explicit direction.) Each path
995    /// > entry is either a full path name or is relative to the current directory
996    /// > of the compilation.
997    /// >
998    /// > The last entry is followed by a single null byte.
999    include_directories: Vec<AttributeValue<R, Offset>>,
1000
1001    /// "A sequence of file entry format descriptions."
1002    file_name_entry_format: Vec<FileEntryFormat>,
1003
1004    /// "Entries in this sequence describe source files that contribute to the
1005    /// line number information for this compilation unit or is used in other
1006    /// contexts."
1007    file_names: Vec<FileEntry<R, Offset>>,
1008
1009    /// The encoded line program instructions.
1010    program_buf: R,
1011
1012    /// The current directory of the compilation.
1013    comp_dir: Option<R>,
1014
1015    /// The primary source file.
1016    comp_file: Option<FileEntry<R, Offset>>,
1017}
1018
1019impl<R, Offset> LineProgramHeader<R, Offset>
1020where
1021    R: Reader<Offset = Offset>,
1022    Offset: ReaderOffset,
1023{
1024    /// Return the offset of the line number program header in the `.debug_line` section.
1025    pub fn offset(&self) -> DebugLineOffset<R::Offset> {
1026        self.offset
1027    }
1028
1029    /// Return the length of the line number program and header, not including
1030    /// the length of the encoded length itself.
1031    pub fn unit_length(&self) -> R::Offset {
1032        self.unit_length
1033    }
1034
1035    /// Return the encoding parameters for this header's line program.
1036    pub fn encoding(&self) -> Encoding {
1037        self.encoding
1038    }
1039
1040    /// Get the version of this header's line program.
1041    pub fn version(&self) -> u16 {
1042        self.encoding.version
1043    }
1044
1045    /// Get the length of the encoded line number program header, not including
1046    /// the length of the encoded length itself.
1047    pub fn header_length(&self) -> R::Offset {
1048        self.header_length
1049    }
1050
1051    /// Get the size in bytes of a target machine address.
1052    pub fn address_size(&self) -> u8 {
1053        self.encoding.address_size
1054    }
1055
1056    /// Whether this line program is encoded in 64- or 32-bit DWARF.
1057    pub fn format(&self) -> Format {
1058        self.encoding.format
1059    }
1060
1061    /// Get the line encoding parameters for this header's line program.
1062    pub fn line_encoding(&self) -> LineEncoding {
1063        self.line_encoding
1064    }
1065
1066    /// Get the minimum instruction length any instruction in this header's line
1067    /// program may have.
1068    pub fn minimum_instruction_length(&self) -> u8 {
1069        self.line_encoding.minimum_instruction_length
1070    }
1071
1072    /// Get the maximum number of operations each instruction in this header's
1073    /// line program may have.
1074    pub fn maximum_operations_per_instruction(&self) -> u8 {
1075        self.line_encoding.maximum_operations_per_instruction
1076    }
1077
1078    /// Get the default value of the `is_stmt` register for this header's line
1079    /// program.
1080    pub fn default_is_stmt(&self) -> bool {
1081        self.line_encoding.default_is_stmt
1082    }
1083
1084    /// Get the line base for this header's line program.
1085    pub fn line_base(&self) -> i8 {
1086        self.line_encoding.line_base
1087    }
1088
1089    /// Get the line range for this header's line program.
1090    pub fn line_range(&self) -> u8 {
1091        self.line_encoding.line_range
1092    }
1093
1094    /// Get opcode base for this header's line program.
1095    pub fn opcode_base(&self) -> u8 {
1096        self.opcode_base
1097    }
1098
1099    /// An array of `u8` that specifies the number of LEB128 operands for
1100    /// each of the standard opcodes.
1101    pub fn standard_opcode_lengths(&self) -> &R {
1102        &self.standard_opcode_lengths
1103    }
1104
1105    /// Get the format of a directory entry.
1106    pub fn directory_entry_format(&self) -> &[FileEntryFormat] {
1107        &self.directory_entry_format[..]
1108    }
1109
1110    /// Get the set of include directories for this header's line program.
1111    ///
1112    /// For DWARF version <= 4, the compilation's current directory is not included
1113    /// in the return value, but is implicitly considered to be in the set per spec.
1114    pub fn include_directories(&self) -> &[AttributeValue<R, Offset>] {
1115        &self.include_directories[..]
1116    }
1117
1118    /// The include directory with the given directory index.
1119    ///
1120    /// A directory index of 0 corresponds to the compilation unit directory.
1121    pub fn directory(&self, directory: u64) -> Option<AttributeValue<R, Offset>> {
1122        if self.encoding.version <= 4 {
1123            if directory == 0 {
1124                self.comp_dir.clone().map(AttributeValue::String)
1125            } else {
1126                let directory = directory as usize - 1;
1127                self.include_directories.get(directory).cloned()
1128            }
1129        } else {
1130            self.include_directories.get(directory as usize).cloned()
1131        }
1132    }
1133
1134    /// Get the format of a file name entry.
1135    pub fn file_name_entry_format(&self) -> &[FileEntryFormat] {
1136        &self.file_name_entry_format[..]
1137    }
1138
1139    /// Return true if the file entries may have valid timestamps.
1140    ///
1141    /// Only returns false if we definitely know that all timestamp fields
1142    /// are invalid.
1143    pub fn file_has_timestamp(&self) -> bool {
1144        self.encoding.version <= 4
1145            || self
1146                .file_name_entry_format
1147                .iter()
1148                .any(|x| x.content_type == constants::DW_LNCT_timestamp)
1149    }
1150
1151    /// Return true if the file entries may have valid sizes.
1152    ///
1153    /// Only returns false if we definitely know that all size fields
1154    /// are invalid.
1155    pub fn file_has_size(&self) -> bool {
1156        self.encoding.version <= 4
1157            || self
1158                .file_name_entry_format
1159                .iter()
1160                .any(|x| x.content_type == constants::DW_LNCT_size)
1161    }
1162
1163    /// Return true if the file name entry format contains an MD5 field.
1164    pub fn file_has_md5(&self) -> bool {
1165        self.file_name_entry_format
1166            .iter()
1167            .any(|x| x.content_type == constants::DW_LNCT_MD5)
1168    }
1169
1170    /// Return true if the file name entry format contains a source field.
1171    pub fn file_has_source(&self) -> bool {
1172        self.file_name_entry_format
1173            .iter()
1174            .any(|x| x.content_type == constants::DW_LNCT_LLVM_source)
1175    }
1176
1177    /// Get the list of source files that appear in this header's line program.
1178    pub fn file_names(&self) -> &[FileEntry<R, Offset>] {
1179        &self.file_names[..]
1180    }
1181
1182    /// The source file with the given file index.
1183    ///
1184    /// A file index of 0 corresponds to the compilation unit file.
1185    /// Note that a file index of 0 is invalid for DWARF version <= 4,
1186    /// but we support it anyway.
1187    pub fn file(&self, file: u64) -> Option<&FileEntry<R, Offset>> {
1188        if self.encoding.version <= 4 {
1189            if file == 0 {
1190                self.comp_file.as_ref()
1191            } else {
1192                let file = file as usize - 1;
1193                self.file_names.get(file)
1194            }
1195        } else {
1196            self.file_names.get(file as usize)
1197        }
1198    }
1199
1200    /// Get the raw, un-parsed `EndianSlice` containing this header's line number
1201    /// program.
1202    ///
1203    /// ```
1204    /// # fn foo() {
1205    /// use gimli::{LineProgramHeader, EndianSlice, NativeEndian};
1206    ///
1207    /// fn get_line_number_program_header<'a>() -> LineProgramHeader<EndianSlice<'a, NativeEndian>> {
1208    ///     // Get a line number program header from some offset in a
1209    ///     // `.debug_line` section...
1210    /// #   unimplemented!()
1211    /// }
1212    ///
1213    /// let header = get_line_number_program_header();
1214    /// let raw_program = header.raw_program_buf();
1215    /// println!("The length of the raw program in bytes is {}", raw_program.len());
1216    /// # }
1217    /// ```
1218    pub fn raw_program_buf(&self) -> R {
1219        self.program_buf.clone()
1220    }
1221
1222    /// Iterate over the instructions in this header's line number program, parsing
1223    /// them as we go.
1224    pub fn instructions(&self) -> LineInstructions<R> {
1225        LineInstructions {
1226            input: self.program_buf.clone(),
1227        }
1228    }
1229
1230    fn parse(
1231        input: &mut R,
1232        offset: DebugLineOffset<Offset>,
1233        mut address_size: u8,
1234        mut comp_dir: Option<R>,
1235        comp_name: Option<R>,
1236    ) -> Result<LineProgramHeader<R, Offset>> {
1237        let (unit_length, format) = input.read_initial_length()?;
1238        let rest = &mut input.split(unit_length)?;
1239
1240        let version = rest.read_u16()?;
1241        if version < 2 || version > 5 {
1242            return Err(Error::UnknownVersion(u64::from(version)));
1243        }
1244
1245        if version >= 5 {
1246            address_size = rest.read_address_size()?;
1247            let segment_selector_size = rest.read_u8()?;
1248            if segment_selector_size != 0 {
1249                return Err(Error::UnsupportedSegmentSize(segment_selector_size));
1250            }
1251        }
1252
1253        let encoding = Encoding {
1254            format,
1255            version,
1256            address_size,
1257        };
1258
1259        let header_length = rest.read_length(format)?;
1260
1261        let mut program_buf = rest.clone();
1262        program_buf.skip(header_length)?;
1263        rest.truncate(header_length)?;
1264
1265        let minimum_instruction_length = rest.read_u8()?;
1266        if minimum_instruction_length == 0 {
1267            return Err(Error::MinimumInstructionLengthZero);
1268        }
1269
1270        // This field did not exist before DWARF 4, but is specified to be 1 for
1271        // non-VLIW architectures, which makes it a no-op.
1272        let maximum_operations_per_instruction = if version >= 4 { rest.read_u8()? } else { 1 };
1273        if maximum_operations_per_instruction == 0 {
1274            return Err(Error::MaximumOperationsPerInstructionZero);
1275        }
1276
1277        let default_is_stmt = rest.read_u8()? != 0;
1278        let line_base = rest.read_i8()?;
1279        let line_range = rest.read_u8()?;
1280        if line_range == 0 {
1281            return Err(Error::LineRangeZero);
1282        }
1283        let line_encoding = LineEncoding {
1284            minimum_instruction_length,
1285            maximum_operations_per_instruction,
1286            default_is_stmt,
1287            line_base,
1288            line_range,
1289        };
1290
1291        let opcode_base = rest.read_u8()?;
1292        if opcode_base == 0 {
1293            return Err(Error::OpcodeBaseZero);
1294        }
1295
1296        let standard_opcode_count = R::Offset::from_u8(opcode_base - 1);
1297        let standard_opcode_lengths = rest.split(standard_opcode_count)?;
1298
1299        let directory_entry_format;
1300        let mut include_directories = Vec::new();
1301        if version <= 4 {
1302            directory_entry_format = Vec::new();
1303            loop {
1304                let directory = rest.read_null_terminated_slice()?;
1305                if directory.is_empty() {
1306                    break;
1307                }
1308                include_directories.push(AttributeValue::String(directory));
1309            }
1310        } else {
1311            comp_dir = None;
1312            directory_entry_format = FileEntryFormat::parse(rest)?;
1313            let count = rest.read_uleb128()?;
1314            for _ in 0..count {
1315                include_directories.push(parse_directory_v5(
1316                    rest,
1317                    encoding,
1318                    &directory_entry_format,
1319                )?);
1320            }
1321        }
1322
1323        let comp_file;
1324        let file_name_entry_format;
1325        let mut file_names = Vec::new();
1326        if version <= 4 {
1327            comp_file = comp_name.map(|name| FileEntry {
1328                path_name: AttributeValue::String(name),
1329                directory_index: 0,
1330                timestamp: 0,
1331                size: 0,
1332                md5: [0; 16],
1333                source: None,
1334            });
1335
1336            file_name_entry_format = Vec::new();
1337            loop {
1338                let path_name = rest.read_null_terminated_slice()?;
1339                if path_name.is_empty() {
1340                    break;
1341                }
1342                file_names.push(FileEntry::parse(rest, path_name)?);
1343            }
1344        } else {
1345            comp_file = None;
1346            file_name_entry_format = FileEntryFormat::parse(rest)?;
1347            let count = rest.read_uleb128()?;
1348            for _ in 0..count {
1349                file_names.push(parse_file_v5(rest, encoding, &file_name_entry_format)?);
1350            }
1351        }
1352
1353        let header = LineProgramHeader {
1354            encoding,
1355            offset,
1356            unit_length,
1357            header_length,
1358            line_encoding,
1359            opcode_base,
1360            standard_opcode_lengths,
1361            directory_entry_format,
1362            include_directories,
1363            file_name_entry_format,
1364            file_names,
1365            program_buf,
1366            comp_dir,
1367            comp_file,
1368        };
1369        Ok(header)
1370    }
1371}
1372
1373/// A line number program that has not been run to completion.
1374#[derive(Clone, Debug, Eq, PartialEq)]
1375pub struct IncompleteLineProgram<R, Offset = <R as Reader>::Offset>
1376where
1377    R: Reader<Offset = Offset>,
1378    Offset: ReaderOffset,
1379{
1380    header: LineProgramHeader<R, Offset>,
1381}
1382
1383impl<R, Offset> IncompleteLineProgram<R, Offset>
1384where
1385    R: Reader<Offset = Offset>,
1386    Offset: ReaderOffset,
1387{
1388    /// Retrieve the `LineProgramHeader` for this program.
1389    pub fn header(&self) -> &LineProgramHeader<R, Offset> {
1390        &self.header
1391    }
1392
1393    /// Construct a new `LineRows` for executing this program to iterate
1394    /// over rows in the line information matrix.
1395    pub fn rows(self) -> OneShotLineRows<R, Offset> {
1396        OneShotLineRows::new(self)
1397    }
1398
1399    /// Execute the line number program, completing the `IncompleteLineProgram`
1400    /// into a `CompleteLineProgram` and producing an array of sequences within
1401    /// the line number program that can later be used with
1402    /// `CompleteLineProgram::resume_from`.
1403    ///
1404    /// ```
1405    /// # fn foo() {
1406    /// use gimli::{IncompleteLineProgram, EndianSlice, NativeEndian};
1407    ///
1408    /// fn get_line_number_program<'a>() -> IncompleteLineProgram<EndianSlice<'a, NativeEndian>> {
1409    ///     // Get a line number program from some offset in a
1410    ///     // `.debug_line` section...
1411    /// #   unimplemented!()
1412    /// }
1413    ///
1414    /// let program = get_line_number_program();
1415    /// let (program, sequences) = program.sequences().unwrap();
1416    /// println!("There are {} sequences in this line number program", sequences.len());
1417    /// # }
1418    /// ```
1419    #[allow(clippy::type_complexity)]
1420    pub fn sequences(self) -> Result<(CompleteLineProgram<R, Offset>, Vec<LineSequence<R>>)> {
1421        let mut sequences = Vec::new();
1422        let mut rows = self.rows();
1423        let mut instructions = rows.instructions.clone();
1424        let mut sequence_start_addr = None;
1425        loop {
1426            let sequence_end_addr;
1427            if rows.next_row()?.is_none() {
1428                break;
1429            }
1430
1431            let row = &rows.row;
1432            if row.end_sequence() {
1433                sequence_end_addr = row.address();
1434            } else if sequence_start_addr.is_none() {
1435                sequence_start_addr = Some(row.address());
1436                continue;
1437            } else {
1438                continue;
1439            }
1440
1441            // We just finished a sequence.
1442            sequences.push(LineSequence {
1443                // In theory one could have multiple DW_LNE_end_sequence instructions
1444                // in a row.
1445                start: sequence_start_addr.unwrap_or(0),
1446                end: sequence_end_addr,
1447                instructions: instructions.remove_trailing(&rows.instructions)?,
1448            });
1449            sequence_start_addr = None;
1450            instructions = rows.instructions.clone();
1451        }
1452
1453        let program = CompleteLineProgram {
1454            header: rows.program.header,
1455        };
1456        Ok((program, sequences))
1457    }
1458}
1459
1460/// A line number program that has previously been run to completion.
1461#[derive(Clone, Debug, Eq, PartialEq)]
1462pub struct CompleteLineProgram<R, Offset = <R as Reader>::Offset>
1463where
1464    R: Reader<Offset = Offset>,
1465    Offset: ReaderOffset,
1466{
1467    header: LineProgramHeader<R, Offset>,
1468}
1469
1470impl<R, Offset> CompleteLineProgram<R, Offset>
1471where
1472    R: Reader<Offset = Offset>,
1473    Offset: ReaderOffset,
1474{
1475    /// Retrieve the `LineProgramHeader` for this program.
1476    pub fn header(&self) -> &LineProgramHeader<R, Offset> {
1477        &self.header
1478    }
1479
1480    /// Construct a new `LineRows` for executing the subset of the line
1481    /// number program identified by 'sequence' and  generating the line information
1482    /// matrix.
1483    ///
1484    /// ```
1485    /// # fn foo() {
1486    /// use gimli::{IncompleteLineProgram, EndianSlice, NativeEndian};
1487    ///
1488    /// fn get_line_number_program<'a>() -> IncompleteLineProgram<EndianSlice<'a, NativeEndian>> {
1489    ///     // Get a line number program from some offset in a
1490    ///     // `.debug_line` section...
1491    /// #   unimplemented!()
1492    /// }
1493    ///
1494    /// let program = get_line_number_program();
1495    /// let (program, sequences) = program.sequences().unwrap();
1496    /// for sequence in &sequences {
1497    ///     let mut sm = program.resume_from(sequence);
1498    /// }
1499    /// # }
1500    /// ```
1501    pub fn resume_from<'program>(
1502        &'program self,
1503        sequence: &LineSequence<R>,
1504    ) -> ResumedLineRows<'program, R, Offset> {
1505        ResumedLineRows::resume(self, sequence)
1506    }
1507}
1508
1509/// An entry in the `LineProgramHeader`'s `file_names` set.
1510#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1511pub struct FileEntry<R, Offset = <R as Reader>::Offset>
1512where
1513    R: Reader<Offset = Offset>,
1514    Offset: ReaderOffset,
1515{
1516    path_name: AttributeValue<R, Offset>,
1517    directory_index: u64,
1518    timestamp: u64,
1519    size: u64,
1520    md5: [u8; 16],
1521    source: Option<AttributeValue<R, Offset>>,
1522}
1523
1524impl<R, Offset> FileEntry<R, Offset>
1525where
1526    R: Reader<Offset = Offset>,
1527    Offset: ReaderOffset,
1528{
1529    // version 2-4
1530    fn parse(input: &mut R, path_name: R) -> Result<FileEntry<R, Offset>> {
1531        let directory_index = input.read_uleb128()?;
1532        let timestamp = input.read_uleb128()?;
1533        let size = input.read_uleb128()?;
1534
1535        let entry = FileEntry {
1536            path_name: AttributeValue::String(path_name),
1537            directory_index,
1538            timestamp,
1539            size,
1540            md5: [0; 16],
1541            source: None,
1542        };
1543
1544        Ok(entry)
1545    }
1546
1547    /// > A slice containing the full or relative path name of
1548    /// > a source file. If the entry contains a file name or a relative path
1549    /// > name, the file is located relative to either the compilation directory
1550    /// > (as specified by the DW_AT_comp_dir attribute given in the compilation
1551    /// > unit) or one of the directories in the include_directories section.
1552    pub fn path_name(&self) -> AttributeValue<R, Offset> {
1553        self.path_name.clone()
1554    }
1555
1556    /// > An unsigned LEB128 number representing the directory index of the
1557    /// > directory in which the file was found.
1558    /// >
1559    /// > ...
1560    /// >
1561    /// > The directory index represents an entry in the include_directories
1562    /// > section of the line number program header. The index is 0 if the file
1563    /// > was found in the current directory of the compilation, 1 if it was found
1564    /// > in the first directory in the include_directories section, and so
1565    /// > on. The directory index is ignored for file names that represent full
1566    /// > path names.
1567    pub fn directory_index(&self) -> u64 {
1568        self.directory_index
1569    }
1570
1571    /// Get this file's directory.
1572    ///
1573    /// A directory index of 0 corresponds to the compilation unit directory.
1574    pub fn directory(&self, header: &LineProgramHeader<R>) -> Option<AttributeValue<R, Offset>> {
1575        header.directory(self.directory_index)
1576    }
1577
1578    /// The implementation-defined time of last modification of the file,
1579    /// or 0 if not available.
1580    pub fn timestamp(&self) -> u64 {
1581        self.timestamp
1582    }
1583
1584    /// "An unsigned LEB128 number representing the time of last modification of
1585    /// the file, or 0 if not available."
1586    // Terminology changed in DWARF version 5.
1587    #[doc(hidden)]
1588    pub fn last_modification(&self) -> u64 {
1589        self.timestamp
1590    }
1591
1592    /// The size of the file in bytes, or 0 if not available.
1593    pub fn size(&self) -> u64 {
1594        self.size
1595    }
1596
1597    /// "An unsigned LEB128 number representing the length in bytes of the file,
1598    /// or 0 if not available."
1599    // Terminology changed in DWARF version 5.
1600    #[doc(hidden)]
1601    pub fn length(&self) -> u64 {
1602        self.size
1603    }
1604
1605    /// A 16-byte MD5 digest of the file contents.
1606    ///
1607    /// Only valid if `LineProgramHeader::file_has_md5` returns `true`.
1608    pub fn md5(&self) -> &[u8; 16] {
1609        &self.md5
1610    }
1611
1612    /// The source code of this file. (UTF-8 source text string with "\n" line
1613    /// endings).
1614    ///
1615    /// Note: For DWARF v5 files this may return an empty attribute that
1616    /// indicates that no source code is available, which this function
1617    /// represents as `Some(<zero-length attr>)`.
1618    pub fn source(&self) -> Option<AttributeValue<R, Offset>> {
1619        self.source.clone()
1620    }
1621}
1622
1623/// The format of a component of an include directory or file name entry.
1624#[derive(Copy, Clone, Debug, PartialEq, Eq)]
1625pub struct FileEntryFormat {
1626    /// The type of information that is represented by the component.
1627    pub content_type: constants::DwLnct,
1628
1629    /// The encoding form of the component value.
1630    pub form: constants::DwForm,
1631}
1632
1633impl FileEntryFormat {
1634    fn parse<R: Reader>(input: &mut R) -> Result<Vec<FileEntryFormat>> {
1635        let format_count = input.read_u8()? as usize;
1636        let mut format = Vec::with_capacity(format_count);
1637        let mut path_count = 0;
1638        for _ in 0..format_count {
1639            let content_type = input.read_uleb128()?;
1640            let content_type = if content_type > u64::from(u16::MAX) {
1641                constants::DwLnct(u16::MAX)
1642            } else {
1643                constants::DwLnct(content_type as u16)
1644            };
1645            if content_type == constants::DW_LNCT_path {
1646                path_count += 1;
1647            }
1648
1649            let form = constants::DwForm(input.read_uleb128_u16()?);
1650
1651            format.push(FileEntryFormat { content_type, form });
1652        }
1653        if path_count != 1 {
1654            return Err(Error::MissingFileEntryFormatPath);
1655        }
1656        Ok(format)
1657    }
1658}
1659
1660fn parse_directory_v5<R: Reader>(
1661    input: &mut R,
1662    encoding: Encoding,
1663    formats: &[FileEntryFormat],
1664) -> Result<AttributeValue<R>> {
1665    let mut path_name = None;
1666
1667    for format in formats {
1668        let value = parse_attribute(input, encoding, format.form)?;
1669        if format.content_type == constants::DW_LNCT_path {
1670            path_name = Some(value);
1671        }
1672    }
1673
1674    Ok(path_name.unwrap())
1675}
1676
1677fn parse_file_v5<R: Reader>(
1678    input: &mut R,
1679    encoding: Encoding,
1680    formats: &[FileEntryFormat],
1681) -> Result<FileEntry<R>> {
1682    let mut path_name = None;
1683    let mut directory_index = 0;
1684    let mut timestamp = 0;
1685    let mut size = 0;
1686    let mut md5 = [0; 16];
1687    let mut source = None;
1688
1689    for format in formats {
1690        let value = parse_attribute(input, encoding, format.form)?;
1691        match format.content_type {
1692            constants::DW_LNCT_path => path_name = Some(value),
1693            constants::DW_LNCT_directory_index => {
1694                if let Some(value) = value.udata_value() {
1695                    directory_index = value;
1696                }
1697            }
1698            constants::DW_LNCT_timestamp => {
1699                if let Some(value) = value.udata_value() {
1700                    timestamp = value;
1701                }
1702            }
1703            constants::DW_LNCT_size => {
1704                if let Some(value) = value.udata_value() {
1705                    size = value;
1706                }
1707            }
1708            constants::DW_LNCT_MD5 => {
1709                if let AttributeValue::Block(mut value) = value
1710                    && value.len().into_u64() == 16
1711                {
1712                    md5 = value.read_u8_array()?;
1713                }
1714            }
1715            constants::DW_LNCT_LLVM_source => {
1716                source = Some(value);
1717            }
1718            // Ignore unknown content types.
1719            _ => {}
1720        }
1721    }
1722
1723    Ok(FileEntry {
1724        path_name: path_name.unwrap(),
1725        directory_index,
1726        timestamp,
1727        size,
1728        md5,
1729        source,
1730    })
1731}
1732
1733// TODO: this should be shared with unit::parse_attribute(), but that is hard to do.
1734fn parse_attribute<R: Reader>(
1735    input: &mut R,
1736    encoding: Encoding,
1737    form: constants::DwForm,
1738) -> Result<AttributeValue<R>> {
1739    Ok(match form {
1740        constants::DW_FORM_block1 => {
1741            let len = input.read_u8().map(R::Offset::from_u8)?;
1742            let block = input.split(len)?;
1743            AttributeValue::Block(block)
1744        }
1745        constants::DW_FORM_block2 => {
1746            let len = input.read_u16().map(R::Offset::from_u16)?;
1747            let block = input.split(len)?;
1748            AttributeValue::Block(block)
1749        }
1750        constants::DW_FORM_block4 => {
1751            let len = input.read_u32().map(R::Offset::from_u32)?;
1752            let block = input.split(len)?;
1753            AttributeValue::Block(block)
1754        }
1755        constants::DW_FORM_block => {
1756            let len = input.read_uleb128().and_then(R::Offset::from_u64)?;
1757            let block = input.split(len)?;
1758            AttributeValue::Block(block)
1759        }
1760        constants::DW_FORM_data1 => {
1761            let data = input.read_u8()?;
1762            AttributeValue::Data1(data)
1763        }
1764        constants::DW_FORM_data2 => {
1765            let data = input.read_u16()?;
1766            AttributeValue::Data2(data)
1767        }
1768        constants::DW_FORM_data4 => {
1769            let data = input.read_u32()?;
1770            AttributeValue::Data4(data)
1771        }
1772        constants::DW_FORM_data8 => {
1773            let data = input.read_u64()?;
1774            AttributeValue::Data8(data)
1775        }
1776        constants::DW_FORM_data16 => {
1777            let block = input.split(R::Offset::from_u8(16))?;
1778            AttributeValue::Block(block)
1779        }
1780        constants::DW_FORM_udata => {
1781            let data = input.read_uleb128()?;
1782            AttributeValue::Udata(data)
1783        }
1784        constants::DW_FORM_sdata => {
1785            let data = input.read_sleb128()?;
1786            AttributeValue::Sdata(data)
1787        }
1788        constants::DW_FORM_flag => {
1789            let present = input.read_u8()?;
1790            AttributeValue::Flag(present != 0)
1791        }
1792        constants::DW_FORM_sec_offset => {
1793            let offset = input.read_offset(encoding.format)?;
1794            AttributeValue::SecOffset(offset)
1795        }
1796        constants::DW_FORM_string => {
1797            let string = input.read_null_terminated_slice()?;
1798            AttributeValue::String(string)
1799        }
1800        constants::DW_FORM_strp => {
1801            let offset = input.read_offset(encoding.format)?;
1802            AttributeValue::DebugStrRef(DebugStrOffset(offset))
1803        }
1804        constants::DW_FORM_strp_sup | constants::DW_FORM_GNU_strp_alt => {
1805            let offset = input.read_offset(encoding.format)?;
1806            AttributeValue::DebugStrRefSup(DebugStrOffset(offset))
1807        }
1808        constants::DW_FORM_line_strp => {
1809            let offset = input.read_offset(encoding.format)?;
1810            AttributeValue::DebugLineStrRef(DebugLineStrOffset(offset))
1811        }
1812        constants::DW_FORM_strx | constants::DW_FORM_GNU_str_index => {
1813            let index = input.read_uleb128().and_then(R::Offset::from_u64)?;
1814            AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1815        }
1816        constants::DW_FORM_strx1 => {
1817            let index = input.read_u8().map(R::Offset::from_u8)?;
1818            AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1819        }
1820        constants::DW_FORM_strx2 => {
1821            let index = input.read_u16().map(R::Offset::from_u16)?;
1822            AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1823        }
1824        constants::DW_FORM_strx3 => {
1825            let index = input.read_uint(3).and_then(R::Offset::from_u64)?;
1826            AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1827        }
1828        constants::DW_FORM_strx4 => {
1829            let index = input.read_u32().map(R::Offset::from_u32)?;
1830            AttributeValue::DebugStrOffsetsIndex(DebugStrOffsetsIndex(index))
1831        }
1832        _ => {
1833            return Err(Error::UnknownForm(form));
1834        }
1835    })
1836}
1837
1838#[cfg(test)]
1839mod tests {
1840    use super::*;
1841    use crate::constants;
1842    use crate::endianity::LittleEndian;
1843    use crate::read::{EndianSlice, Error};
1844    use crate::test_util::GimliSectionMethods;
1845    use test_assembler::{Endian, Label, LabelMaker, Section};
1846
1847    #[test]
1848    fn test_parse_debug_line_32_ok() {
1849        #[rustfmt::skip]
1850        let buf = [
1851            // 32-bit length = 62.
1852            0x3e, 0x00, 0x00, 0x00,
1853            // Version.
1854            0x04, 0x00,
1855            // Header length = 40.
1856            0x28, 0x00, 0x00, 0x00,
1857            // Minimum instruction length.
1858            0x01,
1859            // Maximum operations per byte.
1860            0x01,
1861            // Default is_stmt.
1862            0x01,
1863            // Line base.
1864            0x00,
1865            // Line range.
1866            0x01,
1867            // Opcode base.
1868            0x03,
1869            // Standard opcode lengths for opcodes 1 .. opcode base - 1.
1870            0x01, 0x02,
1871            // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0'
1872            0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
1873            // File names
1874                // foo.rs
1875                0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
1876                0x00,
1877                0x00,
1878                0x00,
1879                // bar.h
1880                0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
1881                0x01,
1882                0x00,
1883                0x00,
1884            // End file names.
1885            0x00,
1886
1887            // Dummy line program data.
1888            0x00, 0x00, 0x00, 0x00,
1889            0x00, 0x00, 0x00, 0x00,
1890            0x00, 0x00, 0x00, 0x00,
1891            0x00, 0x00, 0x00, 0x00,
1892
1893            // Dummy next line program.
1894            0x00, 0x00, 0x00, 0x00,
1895            0x00, 0x00, 0x00, 0x00,
1896            0x00, 0x00, 0x00, 0x00,
1897            0x00, 0x00, 0x00, 0x00,
1898        ];
1899
1900        let rest = &mut EndianSlice::new(&buf, LittleEndian);
1901        let comp_dir = EndianSlice::new(b"/comp_dir", LittleEndian);
1902        let comp_name = EndianSlice::new(b"/comp_name", LittleEndian);
1903
1904        let header =
1905            LineProgramHeader::parse(rest, DebugLineOffset(0), 4, Some(comp_dir), Some(comp_name))
1906                .expect("should parse header ok");
1907
1908        assert_eq!(
1909            *rest,
1910            EndianSlice::new(&buf[buf.len() - 16..], LittleEndian)
1911        );
1912
1913        assert_eq!(header.offset, DebugLineOffset(0));
1914        assert_eq!(header.version(), 4);
1915        assert_eq!(header.minimum_instruction_length(), 1);
1916        assert_eq!(header.maximum_operations_per_instruction(), 1);
1917        assert!(header.default_is_stmt());
1918        assert_eq!(header.line_base(), 0);
1919        assert_eq!(header.line_range(), 1);
1920        assert_eq!(header.opcode_base(), 3);
1921        assert_eq!(header.directory(0), Some(AttributeValue::String(comp_dir)));
1922        assert_eq!(
1923            header.file(0).unwrap().path_name,
1924            AttributeValue::String(comp_name)
1925        );
1926
1927        let expected_lengths = [1, 2];
1928        assert_eq!(header.standard_opcode_lengths().slice(), &expected_lengths);
1929
1930        let expected_include_directories = [
1931            AttributeValue::String(EndianSlice::new(b"/inc", LittleEndian)),
1932            AttributeValue::String(EndianSlice::new(b"/inc2", LittleEndian)),
1933        ];
1934        assert_eq!(header.include_directories(), &expected_include_directories);
1935
1936        let expected_file_names = [
1937            FileEntry {
1938                path_name: AttributeValue::String(EndianSlice::new(b"foo.rs", LittleEndian)),
1939                directory_index: 0,
1940                timestamp: 0,
1941                size: 0,
1942                md5: [0; 16],
1943                source: None,
1944            },
1945            FileEntry {
1946                path_name: AttributeValue::String(EndianSlice::new(b"bar.h", LittleEndian)),
1947                directory_index: 1,
1948                timestamp: 0,
1949                size: 0,
1950                md5: [0; 16],
1951                source: None,
1952            },
1953        ];
1954        assert_eq!(header.file_names(), &expected_file_names);
1955    }
1956
1957    #[test]
1958    fn test_parse_debug_line_header_length_too_short() {
1959        #[rustfmt::skip]
1960        let buf = [
1961            // 32-bit length = 62.
1962            0x3e, 0x00, 0x00, 0x00,
1963            // Version.
1964            0x04, 0x00,
1965            // Header length = 20. TOO SHORT!!!
1966            0x15, 0x00, 0x00, 0x00,
1967            // Minimum instruction length.
1968            0x01,
1969            // Maximum operations per byte.
1970            0x01,
1971            // Default is_stmt.
1972            0x01,
1973            // Line base.
1974            0x00,
1975            // Line range.
1976            0x01,
1977            // Opcode base.
1978            0x03,
1979            // Standard opcode lengths for opcodes 1 .. opcode base - 1.
1980            0x01, 0x02,
1981            // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0'
1982            0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
1983            // File names
1984                // foo.rs
1985                0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
1986                0x00,
1987                0x00,
1988                0x00,
1989                // bar.h
1990                0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
1991                0x01,
1992                0x00,
1993                0x00,
1994            // End file names.
1995            0x00,
1996
1997            // Dummy line program data.
1998            0x00, 0x00, 0x00, 0x00,
1999            0x00, 0x00, 0x00, 0x00,
2000            0x00, 0x00, 0x00, 0x00,
2001            0x00, 0x00, 0x00, 0x00,
2002
2003            // Dummy next line program.
2004            0x00, 0x00, 0x00, 0x00,
2005            0x00, 0x00, 0x00, 0x00,
2006            0x00, 0x00, 0x00, 0x00,
2007            0x00, 0x00, 0x00, 0x00,
2008        ];
2009
2010        let input = &mut EndianSlice::new(&buf, LittleEndian);
2011
2012        match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) {
2013            Err(Error::UnexpectedEof(_)) => {}
2014            otherwise => panic!("Unexpected result: {:?}", otherwise),
2015        }
2016    }
2017
2018    #[test]
2019    fn test_parse_debug_line_unit_length_too_short() {
2020        #[rustfmt::skip]
2021        let buf = [
2022            // 32-bit length = 40. TOO SHORT!!!
2023            0x28, 0x00, 0x00, 0x00,
2024            // Version.
2025            0x04, 0x00,
2026            // Header length = 40.
2027            0x28, 0x00, 0x00, 0x00,
2028            // Minimum instruction length.
2029            0x01,
2030            // Maximum operations per byte.
2031            0x01,
2032            // Default is_stmt.
2033            0x01,
2034            // Line base.
2035            0x00,
2036            // Line range.
2037            0x01,
2038            // Opcode base.
2039            0x03,
2040            // Standard opcode lengths for opcodes 1 .. opcode base - 1.
2041            0x01, 0x02,
2042            // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0'
2043            0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
2044            // File names
2045                // foo.rs
2046                0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
2047                0x00,
2048                0x00,
2049                0x00,
2050                // bar.h
2051                0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
2052                0x01,
2053                0x00,
2054                0x00,
2055            // End file names.
2056            0x00,
2057
2058            // Dummy line program data.
2059            0x00, 0x00, 0x00, 0x00,
2060            0x00, 0x00, 0x00, 0x00,
2061            0x00, 0x00, 0x00, 0x00,
2062            0x00, 0x00, 0x00, 0x00,
2063
2064            // Dummy next line program.
2065            0x00, 0x00, 0x00, 0x00,
2066            0x00, 0x00, 0x00, 0x00,
2067            0x00, 0x00, 0x00, 0x00,
2068            0x00, 0x00, 0x00, 0x00,
2069        ];
2070
2071        let input = &mut EndianSlice::new(&buf, LittleEndian);
2072
2073        match LineProgramHeader::parse(input, DebugLineOffset(0), 4, None, None) {
2074            Err(Error::UnexpectedEof(_)) => {}
2075            otherwise => panic!("Unexpected result: {:?}", otherwise),
2076        }
2077    }
2078
2079    const OPCODE_BASE: u8 = 13;
2080    const STANDARD_OPCODE_LENGTHS: &[u8] = &[0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1];
2081
2082    fn make_test_header(
2083        buf: EndianSlice<'_, LittleEndian>,
2084    ) -> LineProgramHeader<EndianSlice<'_, LittleEndian>> {
2085        let encoding = Encoding {
2086            format: Format::Dwarf32,
2087            version: 4,
2088            address_size: 8,
2089        };
2090        let line_encoding = LineEncoding {
2091            line_base: -3,
2092            line_range: 12,
2093            ..Default::default()
2094        };
2095        LineProgramHeader {
2096            encoding,
2097            offset: DebugLineOffset(0),
2098            unit_length: 1,
2099            header_length: 1,
2100            line_encoding,
2101            opcode_base: OPCODE_BASE,
2102            standard_opcode_lengths: EndianSlice::new(STANDARD_OPCODE_LENGTHS, LittleEndian),
2103            file_names: vec![
2104                FileEntry {
2105                    path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)),
2106                    directory_index: 0,
2107                    timestamp: 0,
2108                    size: 0,
2109                    md5: [0; 16],
2110                    source: None,
2111                },
2112                FileEntry {
2113                    path_name: AttributeValue::String(EndianSlice::new(b"bar.rs", LittleEndian)),
2114                    directory_index: 0,
2115                    timestamp: 0,
2116                    size: 0,
2117                    md5: [0; 16],
2118                    source: None,
2119                },
2120            ],
2121            include_directories: vec![],
2122            directory_entry_format: vec![],
2123            file_name_entry_format: vec![],
2124            program_buf: buf,
2125            comp_dir: None,
2126            comp_file: None,
2127        }
2128    }
2129
2130    fn make_test_program(
2131        buf: EndianSlice<'_, LittleEndian>,
2132    ) -> IncompleteLineProgram<EndianSlice<'_, LittleEndian>> {
2133        IncompleteLineProgram {
2134            header: make_test_header(buf),
2135        }
2136    }
2137
2138    #[test]
2139    fn test_parse_special_opcodes() {
2140        for i in OPCODE_BASE..u8::MAX {
2141            let input = [i, 0, 0, 0];
2142            let input = EndianSlice::new(&input, LittleEndian);
2143            let header = make_test_header(input);
2144
2145            let mut rest = input;
2146            let opcode =
2147                LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2148
2149            assert_eq!(*rest, *input.range_from(1..));
2150            assert_eq!(opcode, LineInstruction::Special(i));
2151        }
2152    }
2153
2154    #[test]
2155    fn test_parse_standard_opcodes() {
2156        fn test<Operands>(
2157            raw: constants::DwLns,
2158            operands: Operands,
2159            expected: LineInstruction<EndianSlice<'_, LittleEndian>>,
2160        ) where
2161            Operands: AsRef<[u8]>,
2162        {
2163            let mut input = Vec::new();
2164            input.push(raw.0);
2165            input.extend_from_slice(operands.as_ref());
2166
2167            let expected_rest = [0, 1, 2, 3, 4];
2168            input.extend_from_slice(&expected_rest);
2169
2170            let input = EndianSlice::new(&input, LittleEndian);
2171            let header = make_test_header(input);
2172
2173            let mut rest = input;
2174            let opcode =
2175                LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2176
2177            assert_eq!(opcode, expected);
2178            assert_eq!(*rest, expected_rest);
2179        }
2180
2181        test(constants::DW_LNS_copy, [], LineInstruction::Copy);
2182        test(
2183            constants::DW_LNS_advance_pc,
2184            [42],
2185            LineInstruction::AdvancePc(42),
2186        );
2187        test(
2188            constants::DW_LNS_advance_line,
2189            [9],
2190            LineInstruction::AdvanceLine(9),
2191        );
2192        test(constants::DW_LNS_set_file, [7], LineInstruction::SetFile(7));
2193        test(
2194            constants::DW_LNS_set_column,
2195            [1],
2196            LineInstruction::SetColumn(1),
2197        );
2198        test(
2199            constants::DW_LNS_negate_stmt,
2200            [],
2201            LineInstruction::NegateStatement,
2202        );
2203        test(
2204            constants::DW_LNS_set_basic_block,
2205            [],
2206            LineInstruction::SetBasicBlock,
2207        );
2208        test(
2209            constants::DW_LNS_const_add_pc,
2210            [],
2211            LineInstruction::ConstAddPc,
2212        );
2213        test(
2214            constants::DW_LNS_fixed_advance_pc,
2215            [42, 0],
2216            LineInstruction::FixedAddPc(42),
2217        );
2218        test(
2219            constants::DW_LNS_set_prologue_end,
2220            [],
2221            LineInstruction::SetPrologueEnd,
2222        );
2223        test(
2224            constants::DW_LNS_set_isa,
2225            [57 + 0x80, 100],
2226            LineInstruction::SetIsa(12857),
2227        );
2228    }
2229
2230    #[test]
2231    fn test_parse_unknown_standard_opcode_no_args() {
2232        let input = [OPCODE_BASE, 1, 2, 3];
2233        let input = EndianSlice::new(&input, LittleEndian);
2234        let mut standard_opcode_lengths = Vec::new();
2235        let mut header = make_test_header(input);
2236        standard_opcode_lengths.extend(header.standard_opcode_lengths.slice());
2237        standard_opcode_lengths.push(0);
2238        header.opcode_base += 1;
2239        header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian);
2240
2241        let mut rest = input;
2242        let opcode =
2243            LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2244
2245        assert_eq!(
2246            opcode,
2247            LineInstruction::UnknownStandard0(constants::DwLns(OPCODE_BASE))
2248        );
2249        assert_eq!(*rest, *input.range_from(1..));
2250    }
2251
2252    #[test]
2253    fn test_parse_unknown_standard_opcode_one_arg() {
2254        let input = [OPCODE_BASE, 1, 2, 3];
2255        let input = EndianSlice::new(&input, LittleEndian);
2256        let mut standard_opcode_lengths = Vec::new();
2257        let mut header = make_test_header(input);
2258        standard_opcode_lengths.extend(header.standard_opcode_lengths.slice());
2259        standard_opcode_lengths.push(1);
2260        header.opcode_base += 1;
2261        header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian);
2262
2263        let mut rest = input;
2264        let opcode =
2265            LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2266
2267        assert_eq!(
2268            opcode,
2269            LineInstruction::UnknownStandard1(constants::DwLns(OPCODE_BASE), 1)
2270        );
2271        assert_eq!(*rest, *input.range_from(2..));
2272    }
2273
2274    #[test]
2275    fn test_parse_unknown_standard_opcode_many_args() {
2276        let input = [OPCODE_BASE, 1, 2, 3];
2277        let input = EndianSlice::new(&input, LittleEndian);
2278        let args = input.range_from(1..);
2279        let mut standard_opcode_lengths = Vec::new();
2280        let mut header = make_test_header(input);
2281        standard_opcode_lengths.extend(header.standard_opcode_lengths.slice());
2282        standard_opcode_lengths.push(3);
2283        header.opcode_base += 1;
2284        header.standard_opcode_lengths = EndianSlice::new(&standard_opcode_lengths, LittleEndian);
2285
2286        let mut rest = input;
2287        let opcode =
2288            LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2289
2290        assert_eq!(
2291            opcode,
2292            LineInstruction::UnknownStandardN(constants::DwLns(OPCODE_BASE), args)
2293        );
2294        assert_eq!(*rest, []);
2295    }
2296
2297    #[test]
2298    fn test_parse_extended_opcodes() {
2299        fn test<Operands>(
2300            raw: constants::DwLne,
2301            operands: Operands,
2302            expected: LineInstruction<EndianSlice<'_, LittleEndian>>,
2303        ) where
2304            Operands: AsRef<[u8]>,
2305        {
2306            let mut input = Vec::new();
2307            input.push(0);
2308
2309            let operands = operands.as_ref();
2310            input.push(1 + operands.len() as u8);
2311
2312            input.push(raw.0);
2313            input.extend_from_slice(operands);
2314
2315            let expected_rest = [0, 1, 2, 3, 4];
2316            input.extend_from_slice(&expected_rest);
2317
2318            let input = EndianSlice::new(&input, LittleEndian);
2319            let header = make_test_header(input);
2320
2321            let mut rest = input;
2322            let opcode =
2323                LineInstruction::parse(&header, &mut rest).expect("Should parse the opcode OK");
2324
2325            assert_eq!(opcode, expected);
2326            assert_eq!(*rest, expected_rest);
2327        }
2328
2329        test(
2330            constants::DW_LNE_end_sequence,
2331            [],
2332            LineInstruction::EndSequence,
2333        );
2334        test(
2335            constants::DW_LNE_set_address,
2336            [1, 2, 3, 4, 5, 6, 7, 8],
2337            LineInstruction::SetAddress(578_437_695_752_307_201),
2338        );
2339        test(
2340            constants::DW_LNE_set_discriminator,
2341            [42],
2342            LineInstruction::SetDiscriminator(42),
2343        );
2344
2345        let mut file = Vec::new();
2346        // "foo.c"
2347        let path_name = [b'f', b'o', b'o', b'.', b'c', 0];
2348        file.extend_from_slice(&path_name);
2349        // Directory index.
2350        file.push(0);
2351        // Last modification of file.
2352        file.push(1);
2353        // Size of file.
2354        file.push(2);
2355
2356        test(
2357            constants::DW_LNE_define_file,
2358            file,
2359            LineInstruction::DefineFile(FileEntry {
2360                path_name: AttributeValue::String(EndianSlice::new(b"foo.c", LittleEndian)),
2361                directory_index: 0,
2362                timestamp: 1,
2363                size: 2,
2364                md5: [0; 16],
2365                source: None,
2366            }),
2367        );
2368
2369        // Unknown extended opcode.
2370        let operands = [1, 2, 3, 4, 5, 6];
2371        let opcode = constants::DwLne(99);
2372        test(
2373            opcode,
2374            operands,
2375            LineInstruction::UnknownExtended(opcode, EndianSlice::new(&operands, LittleEndian)),
2376        );
2377    }
2378
2379    #[test]
2380    fn test_file_entry_directory() {
2381        let path_name = [b'f', b'o', b'o', b'.', b'r', b's', 0];
2382
2383        let mut file = FileEntry {
2384            path_name: AttributeValue::String(EndianSlice::new(&path_name, LittleEndian)),
2385            directory_index: 1,
2386            timestamp: 0,
2387            size: 0,
2388            md5: [0; 16],
2389            source: None,
2390        };
2391
2392        let mut header = make_test_header(EndianSlice::new(&[], LittleEndian));
2393
2394        let dir = AttributeValue::String(EndianSlice::new(b"dir", LittleEndian));
2395        header.include_directories.push(dir);
2396
2397        assert_eq!(file.directory(&header), Some(dir));
2398
2399        // Now test the compilation's current directory.
2400        file.directory_index = 0;
2401        assert_eq!(file.directory(&header), None);
2402    }
2403
2404    fn assert_exec_opcode<'input>(
2405        header: LineProgramHeader<EndianSlice<'input, LittleEndian>>,
2406        mut registers: LineRow,
2407        opcode: LineInstruction<EndianSlice<'input, LittleEndian>>,
2408        expected_registers: LineRow,
2409        expect_new_row: bool,
2410    ) {
2411        let mut program = IncompleteLineProgram { header };
2412        let is_new_row = registers.execute(opcode, &mut program);
2413
2414        assert_eq!(is_new_row, Ok(expect_new_row));
2415        assert_eq!(registers, expected_registers);
2416    }
2417
2418    #[test]
2419    fn test_exec_special_noop() {
2420        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2421
2422        let initial_registers = LineRow::new(&header);
2423        let opcode = LineInstruction::Special(16);
2424        let expected_registers = initial_registers;
2425
2426        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2427    }
2428
2429    #[test]
2430    fn test_exec_special_negative_line_advance() {
2431        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2432
2433        let mut initial_registers = LineRow::new(&header);
2434        initial_registers.line.0 = 10;
2435
2436        let opcode = LineInstruction::Special(13);
2437
2438        let mut expected_registers = initial_registers;
2439        expected_registers.line.0 -= 3;
2440
2441        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2442    }
2443
2444    #[test]
2445    fn test_exec_special_positive_line_advance() {
2446        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2447
2448        let initial_registers = LineRow::new(&header);
2449
2450        let opcode = LineInstruction::Special(19);
2451
2452        let mut expected_registers = initial_registers;
2453        expected_registers.line.0 += 3;
2454
2455        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2456    }
2457
2458    #[test]
2459    fn test_exec_special_positive_address_advance() {
2460        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2461
2462        let initial_registers = LineRow::new(&header);
2463
2464        let opcode = LineInstruction::Special(52);
2465
2466        let mut expected_registers = initial_registers;
2467        expected_registers.address += 3;
2468
2469        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2470    }
2471
2472    #[test]
2473    fn test_exec_special_positive_address_and_line_advance() {
2474        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2475
2476        let initial_registers = LineRow::new(&header);
2477
2478        let opcode = LineInstruction::Special(55);
2479
2480        let mut expected_registers = initial_registers;
2481        expected_registers.address += 3;
2482        expected_registers.line.0 += 3;
2483
2484        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2485    }
2486
2487    #[test]
2488    fn test_exec_special_positive_address_and_negative_line_advance() {
2489        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2490
2491        let mut initial_registers = LineRow::new(&header);
2492        initial_registers.line.0 = 10;
2493
2494        let opcode = LineInstruction::Special(49);
2495
2496        let mut expected_registers = initial_registers;
2497        expected_registers.address += 3;
2498        expected_registers.line.0 -= 3;
2499
2500        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2501    }
2502
2503    #[test]
2504    fn test_exec_special_line_underflow() {
2505        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2506
2507        let mut initial_registers = LineRow::new(&header);
2508        initial_registers.line.0 = 2;
2509
2510        // -3 line advance.
2511        let opcode = LineInstruction::Special(13);
2512
2513        let mut expected_registers = initial_registers;
2514        // Clamp at 0. No idea if this is the best way to handle this situation
2515        // or not...
2516        expected_registers.line.0 = 0;
2517
2518        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2519    }
2520
2521    #[test]
2522    fn test_exec_copy() {
2523        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2524
2525        let mut initial_registers = LineRow::new(&header);
2526        initial_registers.address = 1337;
2527        initial_registers.line.0 = 42;
2528
2529        let opcode = LineInstruction::Copy;
2530
2531        let expected_registers = initial_registers;
2532
2533        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2534    }
2535
2536    #[test]
2537    fn test_exec_advance_pc() {
2538        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2539        let initial_registers = LineRow::new(&header);
2540        let opcode = LineInstruction::AdvancePc(42);
2541
2542        let mut expected_registers = initial_registers;
2543        expected_registers.address += 42;
2544
2545        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2546    }
2547
2548    #[test]
2549    fn test_exec_advance_pc_overflow_32() {
2550        let mut header = make_test_header(EndianSlice::new(&[], LittleEndian));
2551        header.encoding.address_size = 4;
2552        let mut registers = LineRow::new(&header);
2553        registers.address = u32::MAX.into();
2554        let opcode = LineInstruction::AdvancePc(42);
2555        let mut program = IncompleteLineProgram { header };
2556        let result = registers.execute(opcode, &mut program);
2557        assert_eq!(result, Err(Error::AddressOverflow));
2558    }
2559
2560    #[test]
2561    fn test_exec_advance_pc_overflow_64() {
2562        let mut header = make_test_header(EndianSlice::new(&[], LittleEndian));
2563        header.encoding.address_size = 8;
2564        let mut registers = LineRow::new(&header);
2565        registers.address = u64::MAX;
2566        let opcode = LineInstruction::AdvancePc(42);
2567        let mut program = IncompleteLineProgram { header };
2568        let result = registers.execute(opcode, &mut program);
2569        assert_eq!(result, Err(Error::AddressOverflow));
2570    }
2571
2572    #[test]
2573    fn test_exec_advance_line() {
2574        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2575        let initial_registers = LineRow::new(&header);
2576        let opcode = LineInstruction::AdvanceLine(42);
2577
2578        let mut expected_registers = initial_registers;
2579        expected_registers.line.0 += 42;
2580
2581        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2582    }
2583
2584    #[test]
2585    fn test_exec_advance_line_overflow() {
2586        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2587        let opcode = LineInstruction::AdvanceLine(42);
2588
2589        let mut initial_registers = LineRow::new(&header);
2590        initial_registers.line.0 = u64::MAX;
2591
2592        let mut expected_registers = initial_registers;
2593        expected_registers.line.0 = 41;
2594
2595        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2596    }
2597
2598    #[test]
2599    fn test_exec_set_file_in_bounds() {
2600        for file_idx in 1..3 {
2601            let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2602            let initial_registers = LineRow::new(&header);
2603            let opcode = LineInstruction::SetFile(file_idx);
2604
2605            let mut expected_registers = initial_registers;
2606            expected_registers.file = file_idx;
2607
2608            assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2609        }
2610    }
2611
2612    #[test]
2613    fn test_exec_set_file_out_of_bounds() {
2614        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2615        let initial_registers = LineRow::new(&header);
2616        let opcode = LineInstruction::SetFile(100);
2617
2618        // The spec doesn't say anything about rejecting input programs
2619        // that set the file register out of bounds of the actual number
2620        // of files that have been defined. Instead, we cross our
2621        // fingers and hope that one gets defined before
2622        // `LineRow::file` gets called and handle the error at
2623        // that time if need be.
2624        let mut expected_registers = initial_registers;
2625        expected_registers.file = 100;
2626
2627        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2628    }
2629
2630    #[test]
2631    fn test_file_entry_file_index_out_of_bounds() {
2632        // These indices are 1-based, so 0 is invalid. 100 is way more than the
2633        // number of files defined in the header.
2634        let out_of_bounds_indices = [0, 100];
2635
2636        for file_idx in &out_of_bounds_indices[..] {
2637            let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2638            let mut row = LineRow::new(&header);
2639
2640            row.file = *file_idx;
2641
2642            assert_eq!(row.file(&header), None);
2643        }
2644    }
2645
2646    #[test]
2647    fn test_file_entry_file_index_in_bounds() {
2648        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2649        let mut row = LineRow::new(&header);
2650
2651        row.file = 2;
2652
2653        assert_eq!(row.file(&header), Some(&header.file_names()[1]));
2654    }
2655
2656    #[test]
2657    fn test_exec_set_column() {
2658        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2659        let initial_registers = LineRow::new(&header);
2660        let opcode = LineInstruction::SetColumn(42);
2661
2662        let mut expected_registers = initial_registers;
2663        expected_registers.column = 42;
2664
2665        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2666    }
2667
2668    #[test]
2669    fn test_exec_negate_statement() {
2670        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2671        let initial_registers = LineRow::new(&header);
2672        let opcode = LineInstruction::NegateStatement;
2673
2674        let mut expected_registers = initial_registers;
2675        expected_registers.is_stmt = !initial_registers.is_stmt;
2676
2677        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2678    }
2679
2680    #[test]
2681    fn test_exec_set_basic_block() {
2682        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2683
2684        let mut initial_registers = LineRow::new(&header);
2685        initial_registers.basic_block = false;
2686
2687        let opcode = LineInstruction::SetBasicBlock;
2688
2689        let mut expected_registers = initial_registers;
2690        expected_registers.basic_block = true;
2691
2692        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2693    }
2694
2695    #[test]
2696    fn test_exec_const_add_pc() {
2697        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2698        let initial_registers = LineRow::new(&header);
2699        let opcode = LineInstruction::ConstAddPc;
2700
2701        let mut expected_registers = initial_registers;
2702        expected_registers.address += 20;
2703
2704        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2705    }
2706
2707    #[test]
2708    fn test_exec_const_add_pc_overflow() {
2709        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2710        let mut registers = LineRow::new(&header);
2711        registers.address = u64::MAX;
2712        let opcode = LineInstruction::ConstAddPc;
2713        let mut program = IncompleteLineProgram { header };
2714        let result = registers.execute(opcode, &mut program);
2715        assert_eq!(result, Err(Error::AddressOverflow));
2716    }
2717
2718    #[test]
2719    fn test_exec_fixed_add_pc() {
2720        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2721
2722        let mut initial_registers = LineRow::new(&header);
2723        initial_registers.op_index.0 = 1;
2724
2725        let opcode = LineInstruction::FixedAddPc(10);
2726
2727        let mut expected_registers = initial_registers;
2728        expected_registers.address += 10;
2729        expected_registers.op_index.0 = 0;
2730
2731        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2732    }
2733
2734    #[test]
2735    fn test_exec_fixed_add_pc_overflow() {
2736        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2737        let mut registers = LineRow::new(&header);
2738        registers.address = u64::MAX;
2739        registers.op_index.0 = 1;
2740        let opcode = LineInstruction::FixedAddPc(10);
2741        let mut program = IncompleteLineProgram { header };
2742        let result = registers.execute(opcode, &mut program);
2743        assert_eq!(result, Err(Error::AddressOverflow));
2744    }
2745
2746    #[test]
2747    fn test_exec_set_prologue_end() {
2748        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2749
2750        let mut initial_registers = LineRow::new(&header);
2751        initial_registers.prologue_end = false;
2752
2753        let opcode = LineInstruction::SetPrologueEnd;
2754
2755        let mut expected_registers = initial_registers;
2756        expected_registers.prologue_end = true;
2757
2758        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2759    }
2760
2761    #[test]
2762    fn test_exec_set_isa() {
2763        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2764        let initial_registers = LineRow::new(&header);
2765        let opcode = LineInstruction::SetIsa(1993);
2766
2767        let mut expected_registers = initial_registers;
2768        expected_registers.isa = 1993;
2769
2770        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2771    }
2772
2773    #[test]
2774    fn test_exec_unknown_standard_0() {
2775        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2776        let initial_registers = LineRow::new(&header);
2777        let opcode = LineInstruction::UnknownStandard0(constants::DwLns(111));
2778        let expected_registers = initial_registers;
2779        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2780    }
2781
2782    #[test]
2783    fn test_exec_unknown_standard_1() {
2784        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2785        let initial_registers = LineRow::new(&header);
2786        let opcode = LineInstruction::UnknownStandard1(constants::DwLns(111), 2);
2787        let expected_registers = initial_registers;
2788        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2789    }
2790
2791    #[test]
2792    fn test_exec_unknown_standard_n() {
2793        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2794        let initial_registers = LineRow::new(&header);
2795        let opcode = LineInstruction::UnknownStandardN(
2796            constants::DwLns(111),
2797            EndianSlice::new(&[2, 2, 2], LittleEndian),
2798        );
2799        let expected_registers = initial_registers;
2800        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2801    }
2802
2803    #[test]
2804    fn test_exec_end_sequence() {
2805        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2806        let initial_registers = LineRow::new(&header);
2807        let opcode = LineInstruction::EndSequence;
2808
2809        let mut expected_registers = initial_registers;
2810        expected_registers.end_sequence = true;
2811
2812        assert_exec_opcode(header, initial_registers, opcode, expected_registers, true);
2813    }
2814
2815    #[test]
2816    fn test_exec_set_address() {
2817        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2818        let initial_registers = LineRow::new(&header);
2819        let opcode = LineInstruction::SetAddress(3030);
2820
2821        let mut expected_registers = initial_registers;
2822        expected_registers.address = 3030;
2823
2824        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2825    }
2826
2827    #[test]
2828    fn test_exec_set_address_tombstone() {
2829        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2830        let initial_registers = LineRow::new(&header);
2831        let opcode = LineInstruction::SetAddress(!0);
2832
2833        let mut expected_registers = initial_registers;
2834        expected_registers.tombstone = true;
2835
2836        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2837    }
2838
2839    #[test]
2840    fn test_exec_set_address_backwards() {
2841        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2842        let mut initial_registers = LineRow::new(&header);
2843        initial_registers.address = 1;
2844        let opcode = LineInstruction::SetAddress(0);
2845
2846        let mut expected_registers = initial_registers;
2847        expected_registers.tombstone = true;
2848
2849        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2850    }
2851
2852    #[test]
2853    fn test_exec_define_file() {
2854        let mut program = make_test_program(EndianSlice::new(&[], LittleEndian));
2855        let mut row = LineRow::new(program.header());
2856
2857        let file = FileEntry {
2858            path_name: AttributeValue::String(EndianSlice::new(b"test.cpp", LittleEndian)),
2859            directory_index: 0,
2860            timestamp: 0,
2861            size: 0,
2862            md5: [0; 16],
2863            source: None,
2864        };
2865
2866        let opcode = LineInstruction::DefineFile(file);
2867        let is_new_row = row.execute(opcode, &mut program).unwrap();
2868
2869        assert!(!is_new_row);
2870        assert_eq!(Some(&file), program.header().file_names.last());
2871    }
2872
2873    #[test]
2874    fn test_exec_set_discriminator() {
2875        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2876        let initial_registers = LineRow::new(&header);
2877        let opcode = LineInstruction::SetDiscriminator(9);
2878
2879        let mut expected_registers = initial_registers;
2880        expected_registers.discriminator = 9;
2881
2882        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2883    }
2884
2885    #[test]
2886    fn test_exec_unknown_extended() {
2887        let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2888        let initial_registers = LineRow::new(&header);
2889        let opcode = LineInstruction::UnknownExtended(
2890            constants::DwLne(74),
2891            EndianSlice::new(&[], LittleEndian),
2892        );
2893        let expected_registers = initial_registers;
2894        assert_exec_opcode(header, initial_registers, opcode, expected_registers, false);
2895    }
2896
2897    /// Ensure that `LineRows<R,P>` is covariant wrt R.
2898    /// This only needs to compile.
2899    #[allow(dead_code, unreachable_code, unused_variables)]
2900    #[allow(clippy::diverging_sub_expression)]
2901    fn test_line_rows_variance<'a, 'b>(_: &'a [u8], _: &'b [u8])
2902    where
2903        'a: 'b,
2904    {
2905        let a: &OneShotLineRows<EndianSlice<'a, LittleEndian>> = unimplemented!();
2906        let _: &OneShotLineRows<EndianSlice<'b, LittleEndian>> = a;
2907    }
2908
2909    #[test]
2910    fn test_parse_debug_line_v5_ok() {
2911        let expected_lengths = &[1, 2];
2912        let expected_program = &[0, 1, 2, 3, 4];
2913        let expected_rest = &[5, 6, 7, 8, 9];
2914        let expected_include_directories = [
2915            AttributeValue::String(EndianSlice::new(b"dir1", LittleEndian)),
2916            AttributeValue::String(EndianSlice::new(b"dir2", LittleEndian)),
2917        ];
2918        let expected_file_names = [
2919            FileEntry {
2920                path_name: AttributeValue::String(EndianSlice::new(b"file1", LittleEndian)),
2921                directory_index: 0,
2922                timestamp: 0,
2923                size: 0,
2924                md5: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
2925                source: Some(AttributeValue::String(EndianSlice::new(
2926                    b"foobar",
2927                    LittleEndian,
2928                ))),
2929            },
2930            FileEntry {
2931                path_name: AttributeValue::String(EndianSlice::new(b"file2", LittleEndian)),
2932                directory_index: 1,
2933                timestamp: 0,
2934                size: 0,
2935                md5: [
2936                    11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
2937                ],
2938                source: Some(AttributeValue::String(EndianSlice::new(
2939                    b"quux",
2940                    LittleEndian,
2941                ))),
2942            },
2943        ];
2944
2945        for format in [Format::Dwarf32, Format::Dwarf64] {
2946            let length = Label::new();
2947            let header_length = Label::new();
2948            let start = Label::new();
2949            let header_start = Label::new();
2950            let end = Label::new();
2951            let header_end = Label::new();
2952            let section = Section::with_endian(Endian::Little)
2953                .initial_length(format, &length, &start)
2954                .D16(5)
2955                // Address size.
2956                .D8(4)
2957                // Segment selector size.
2958                .D8(0)
2959                .word_label(format.word_size(), &header_length)
2960                .mark(&header_start)
2961                // Minimum instruction length.
2962                .D8(1)
2963                // Maximum operations per byte.
2964                .D8(1)
2965                // Default is_stmt.
2966                .D8(1)
2967                // Line base.
2968                .D8(0)
2969                // Line range.
2970                .D8(1)
2971                // Opcode base.
2972                .D8(expected_lengths.len() as u8 + 1)
2973                // Standard opcode lengths for opcodes 1 .. opcode base - 1.
2974                .append_bytes(expected_lengths)
2975                // Directory entry format count.
2976                .D8(1)
2977                .uleb(constants::DW_LNCT_path.0 as u64)
2978                .uleb(constants::DW_FORM_string.0 as u64)
2979                // Directory count.
2980                .D8(2)
2981                .append_bytes(b"dir1\0")
2982                .append_bytes(b"dir2\0")
2983                // File entry format count.
2984                .D8(4)
2985                .uleb(constants::DW_LNCT_path.0 as u64)
2986                .uleb(constants::DW_FORM_string.0 as u64)
2987                .uleb(constants::DW_LNCT_directory_index.0 as u64)
2988                .uleb(constants::DW_FORM_data1.0 as u64)
2989                .uleb(constants::DW_LNCT_MD5.0 as u64)
2990                .uleb(constants::DW_FORM_data16.0 as u64)
2991                .uleb(constants::DW_LNCT_LLVM_source.0 as u64)
2992                .uleb(constants::DW_FORM_string.0 as u64)
2993                // File count.
2994                .D8(2)
2995                .append_bytes(b"file1\0")
2996                .D8(0)
2997                .append_bytes(&expected_file_names[0].md5)
2998                .append_bytes(b"foobar\0")
2999                .append_bytes(b"file2\0")
3000                .D8(1)
3001                .append_bytes(&expected_file_names[1].md5)
3002                .append_bytes(b"quux\0")
3003                .mark(&header_end)
3004                // Dummy line program data.
3005                .append_bytes(expected_program)
3006                .mark(&end)
3007                // Dummy trailing data.
3008                .append_bytes(expected_rest);
3009            length.set_const((&end - &start) as u64);
3010            header_length.set_const((&header_end - &header_start) as u64);
3011            let section = section.get_contents().unwrap();
3012
3013            let input = &mut EndianSlice::new(&section, LittleEndian);
3014
3015            let header = LineProgramHeader::parse(input, DebugLineOffset(0), 0, None, None)
3016                .expect("should parse header ok");
3017
3018            assert_eq!(header.raw_program_buf().slice(), expected_program);
3019            assert_eq!(input.slice(), expected_rest);
3020
3021            assert_eq!(header.offset, DebugLineOffset(0));
3022            assert_eq!(header.version(), 5);
3023            assert_eq!(header.address_size(), 4);
3024            assert_eq!(header.minimum_instruction_length(), 1);
3025            assert_eq!(header.maximum_operations_per_instruction(), 1);
3026            assert!(header.default_is_stmt());
3027            assert_eq!(header.line_base(), 0);
3028            assert_eq!(header.line_range(), 1);
3029            assert_eq!(header.opcode_base(), expected_lengths.len() as u8 + 1);
3030            assert_eq!(header.standard_opcode_lengths().slice(), expected_lengths);
3031            assert_eq!(
3032                header.directory_entry_format(),
3033                &[FileEntryFormat {
3034                    content_type: constants::DW_LNCT_path,
3035                    form: constants::DW_FORM_string,
3036                }]
3037            );
3038            assert_eq!(header.include_directories(), expected_include_directories);
3039            assert_eq!(header.directory(0), Some(expected_include_directories[0]));
3040            assert_eq!(
3041                header.file_name_entry_format(),
3042                &[
3043                    FileEntryFormat {
3044                        content_type: constants::DW_LNCT_path,
3045                        form: constants::DW_FORM_string,
3046                    },
3047                    FileEntryFormat {
3048                        content_type: constants::DW_LNCT_directory_index,
3049                        form: constants::DW_FORM_data1,
3050                    },
3051                    FileEntryFormat {
3052                        content_type: constants::DW_LNCT_MD5,
3053                        form: constants::DW_FORM_data16,
3054                    },
3055                    FileEntryFormat {
3056                        content_type: constants::DW_LNCT_LLVM_source,
3057                        form: constants::DW_FORM_string,
3058                    }
3059                ]
3060            );
3061            assert_eq!(header.file_names(), expected_file_names);
3062            assert_eq!(header.file(0), Some(&expected_file_names[0]));
3063        }
3064    }
3065
3066    #[test]
3067    fn test_sequences() {
3068        #[rustfmt::skip]
3069        let buf = [
3070            // 32-bit length
3071            94, 0x00, 0x00, 0x00,
3072            // Version.
3073            0x04, 0x00,
3074            // Header length = 40.
3075            0x28, 0x00, 0x00, 0x00,
3076            // Minimum instruction length.
3077            0x01,
3078            // Maximum operations per byte.
3079            0x01,
3080            // Default is_stmt.
3081            0x01,
3082            // Line base.
3083            0x00,
3084            // Line range.
3085            0x01,
3086            // Opcode base.
3087            0x03,
3088            // Standard opcode lengths for opcodes 1 .. opcode base - 1.
3089            0x01, 0x02,
3090            // Include directories = '/', 'i', 'n', 'c', '\0', '/', 'i', 'n', 'c', '2', '\0', '\0'
3091            0x2f, 0x69, 0x6e, 0x63, 0x00, 0x2f, 0x69, 0x6e, 0x63, 0x32, 0x00, 0x00,
3092            // File names
3093                // foo.rs
3094                0x66, 0x6f, 0x6f, 0x2e, 0x72, 0x73, 0x00,
3095                0x00,
3096                0x00,
3097                0x00,
3098                // bar.h
3099                0x62, 0x61, 0x72, 0x2e, 0x68, 0x00,
3100                0x01,
3101                0x00,
3102                0x00,
3103            // End file names.
3104            0x00,
3105
3106            0, 5, constants::DW_LNE_set_address.0, 1, 0, 0, 0,
3107            constants::DW_LNS_copy.0,
3108            constants::DW_LNS_advance_pc.0, 1,
3109            constants::DW_LNS_copy.0,
3110            constants::DW_LNS_advance_pc.0, 2,
3111            0, 1, constants::DW_LNE_end_sequence.0,
3112
3113            // Tombstone
3114            0, 5, constants::DW_LNE_set_address.0, 0xff, 0xff, 0xff, 0xff,
3115            constants::DW_LNS_copy.0,
3116            constants::DW_LNS_advance_pc.0, 1,
3117            constants::DW_LNS_copy.0,
3118            constants::DW_LNS_advance_pc.0, 2,
3119            0, 1, constants::DW_LNE_end_sequence.0,
3120
3121            0, 5, constants::DW_LNE_set_address.0, 11, 0, 0, 0,
3122            constants::DW_LNS_copy.0,
3123            constants::DW_LNS_advance_pc.0, 1,
3124            constants::DW_LNS_copy.0,
3125            constants::DW_LNS_advance_pc.0, 2,
3126            0, 1, constants::DW_LNE_end_sequence.0,
3127        ];
3128        assert_eq!(buf[0] as usize, buf.len() - 4);
3129
3130        let rest = &mut EndianSlice::new(&buf, LittleEndian);
3131
3132        let header = LineProgramHeader::parse(rest, DebugLineOffset(0), 4, None, None)
3133            .expect("should parse header ok");
3134        let program = IncompleteLineProgram { header };
3135
3136        let sequences = program.sequences().unwrap().1;
3137        assert_eq!(sequences.len(), 2);
3138        assert_eq!(sequences[0].start, 1);
3139        assert_eq!(sequences[0].end, 4);
3140        assert_eq!(sequences[1].start, 11);
3141        assert_eq!(sequences[1].end, 14);
3142    }
3143}