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