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