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